already container_t&&
[ghsmtp.git] / jnk / p0f.cpp
blob2a87edb751290a84064f9092940a63de2395ec2d
1 #include <cstddef>
2 #include <cstdint>
3 #include <iostream>
4 #include <string>
6 #include <sys/socket.h>
7 #include <sys/un.h>
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
15 #include <fcntl.h>
17 #include "IP4.hpp"
19 enum class P0fMagic : uint32_t {
20 UNKNOWN = 0,
21 QUERY = 0x50304601,
22 RESP = 0x50304602,
25 enum class P0fStatus : uint32_t {
26 BADQUERY = 0x00,
27 OK = 0x10,
28 NOMATCH = 0x20,
31 enum class P0fAddr : uint8_t {
32 UNKNOWN = 0,
33 IPV4 = 4,
34 IPV6 = 6,
37 constexpr size_t P0F_STR_MAX = 31;
39 constexpr auto P0F_MATCH_FUZZY = 1;
40 constexpr auto P0F_MATCH_GENERIC = 2;
42 struct p0f_api_query {
44 P0fMagic const magic{P0fMagic::QUERY};
45 P0fAddr addr_type{P0fAddr::UNKNOWN};
46 uint8_t addr[16]{0};
48 } __attribute__((packed));
50 struct p0f_api_response {
52 P0fMagic const magic{P0fMagic::UNKNOWN};
53 P0fStatus status{P0fStatus::BADQUERY};
55 uint32_t first_seen; // First seen (unix time)
56 uint32_t last_seen; // Last seen (unix time)
57 uint32_t total_conn; // Total connections seen
59 uint32_t uptime_min; // Last uptime (minutes)
60 uint32_t up_mod_days; // Uptime modulo (days)
62 uint32_t last_nat; // NAT / LB last detected (unix time)
63 uint32_t last_chg; // OS chg last detected (unix time)
65 int16_t distance; // System distance
67 uint8_t bad_sw; // Host is lying about U-A / Server
68 uint8_t os_match_q; // Match quality
70 char os_name[P0F_STR_MAX + 1]; // Name of detected OS
71 char os_flavor[P0F_STR_MAX + 1]; // Flavor of detected OS
72 char http_name[P0F_STR_MAX + 1]; // Name of detected HTTP app
73 char http_flavor[P0F_STR_MAX + 1]; // Flavor of detected HTTP app
74 char link_type[P0F_STR_MAX + 1]; // Link type
75 char language[P0F_STR_MAX + 1]; // Language
77 } __attribute__((packed));
79 int main(int argc, char const* argv[])
81 static_assert(sizeof(p0f_api_query) == 21, "p0f_api_query wrong size");
82 static_assert(sizeof(p0f_api_response) == 232, "p0f_api_response wrong size");
84 auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
85 PCHECK(fd >= 0) << "socket() failed";
87 sockaddr_un addr{};
88 addr.sun_family = AF_UNIX;
90 constexpr char socket_path[]{"/run/p0f.sock"};
91 static_assert(sizeof(socket_path) < sizeof(addr.sun_path));
92 strcpy(addr.sun_path, socket_path);
94 PCHECK(connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))
95 == 0)
96 << "p0f api connect() failed";
98 for (auto i = 1; i < argc; ++i) {
99 if (IP4::is_address(argv[i])) {
101 p0f_api_query query_msg;
103 if (inet_pton(AF_INET, argv[i], reinterpret_cast<void*>(&query_msg.addr))
104 == 1) {
105 query_msg.addr_type = P0fAddr::IPV4;
107 PCHECK(write(fd, reinterpret_cast<void const*>(&query_msg),
108 sizeof(query_msg))
109 == sizeof(query_msg))
110 << "p0f api write() failed";
112 p0f_api_response response_msg;
114 PCHECK(read(fd, reinterpret_cast<void*>(&response_msg),
115 sizeof(response_msg))
116 == sizeof(response_msg))
117 << "p0f api read() failed";
119 CHECK(response_msg.magic == P0fMagic::RESP);
121 switch (response_msg.status) {
122 case P0fStatus::BADQUERY:
123 LOG(ERROR) << "bad query";
124 break;
125 case P0fStatus::OK:
126 std::cout << "os_match_q == "
127 << static_cast<int>(response_msg.os_match_q) << "\n";
128 std::cout << "os_name == " << response_msg.os_name << "\n";
129 std::cout << "os_flavor == " << response_msg.os_flavor << "\n";
130 break;
131 case P0fStatus::NOMATCH:
132 LOG(ERROR) << "no match";
133 break;
139 PCHECK(close(fd) == 0) << "p0f api close failed";