X-Git-Url: https://unix4lyfe.org/gitweb/darkstat-debian/blobdiff_plain/a1e8056c92203d02860d719abb1d562453896da8..HEAD:/hosts_db.c diff --git a/hosts_db.c b/hosts_db.c index 754dacc..c1193a1 100644 --- a/hosts_db.c +++ b/hosts_db.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * hosts_db.c: database of hosts, ports, protocols. * @@ -20,12 +20,13 @@ #include "opt.h" #include "str.h" -#include /* struct addrinfo */ +#include /* struct addrinfo */ #include #include #include #include #include /* memset(), strcmp() */ +#include #include int hosts_db_show_macs = 0; @@ -90,9 +91,7 @@ static const double phi_1 = 0.61803398874989490252573887119069695472717285156250; /* Co-prime of u, using phi^-1 */ -inline static uint32_t -coprime(const uint32_t u) -{ +static uint32_t coprime(const uint32_t u) { return ( (uint32_t)( (double)(u) * phi_1 ) | 1U ); } @@ -100,9 +99,7 @@ coprime(const uint32_t u) * This is the "recommended" IPv4 hash function, as seen in FreeBSD's * src/sys/netinet/tcp_hostcache.c 1.1 */ -inline static uint32_t -ipv4_hash(const struct addr *const a) -{ +static uint32_t ipv4_hash(const struct addr *const a) { uint32_t ip = a->ip.v4; return ( (ip) ^ ((ip) >> 7) ^ ((ip) >> 17) ); } @@ -124,9 +121,7 @@ ipv4_hash(const struct addr *const a) * This is the IPv6 hash function used by FreeBSD in the same file as above, * svn rev 122922. */ -inline static uint32_t -ipv6_hash(const struct addr *const a) -{ +static uint32_t ipv6_hash(const struct addr *const a) { const struct in6_addr *const ip6 = &(a->ip.v6); return ( ip6->s6_addr32[0] ^ ip6->s6_addr32[1] ^ ip6->s6_addr32[2] ^ ip6->s6_addr32[3] ); @@ -236,10 +231,12 @@ make_func_host(const void *key) MAKE_BUCKET(b, h, host); h->addr = CASTKEY(struct addr); h->dns = NULL; - h->lastseen = 0; + h->last_seen_mono = 0; memset(&h->mac_addr, 0, sizeof(h->mac_addr)); h->ports_tcp = NULL; + h->ports_tcp_remote = NULL; h->ports_udp = NULL; + h->ports_udp_remote = NULL; h->ip_protos = NULL; return (b); } @@ -250,7 +247,9 @@ free_func_host(struct bucket *b) struct host *h = &(b->u.host); if (h->dns != NULL) free(h->dns); hashtable_free(h->ports_tcp); + hashtable_free(h->ports_tcp_remote); hashtable_free(h->ports_udp); + hashtable_free(h->ports_udp_remote); hashtable_free(h->ip_protos); } @@ -341,32 +340,34 @@ format_row_host(struct str *buf, const struct bucket *b, " %'qu\n" " %'qu\n" " %'qu\n", - b->in, b->out, b->total); + (qu)b->in, + (qu)b->out, + (qu)b->total); if (opt_want_lastseen) { - time_t last_t = b->u.host.lastseen; + int64_t last = b->u.host.last_seen_mono; + int64_t now = (int64_t)now_mono(); struct str *last_str = NULL; - if ((now >= last_t) && (last_t > 0)) - last_str = length_of_time(now - last_t); + if ((now >= last) && (last != 0)) + last_str = length_of_time(now - last); - str_append(buf, - " "); + str_append(buf, " "); if (last_str == NULL) { - if (last_t == 0) + if (last == 0) str_append(buf, "(never)"); else - str_append(buf, "(clock error)"); + str_appendf(buf, "(clock error: last = %qd, now = %qu)", + (qd)last, + (qu)now); } else { str_appendstr(buf, last_str); str_free(last_str); } - str_append(buf, - ""); + str_append(buf, ""); } - str_appendf(buf, - "\n"); + str_appendf(buf, "\n"); /* Only resolve hosts "on demand" */ if (b->u.host.dns == NULL) @@ -405,7 +406,12 @@ format_row_port_tcp(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->port, getservtcp(p->port), b->in, b->out, b->total, p->syn + p->port, + getservtcp(p->port), + (qu)b->in, + (qu)b->out, + (qu)b->total, + (qu)p->syn ); } @@ -439,7 +445,11 @@ format_row_port_udp(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->port, getservudp(p->port), b->in, b->out, b->total + p->port, + getservudp(p->port), + (qu)b->in, + (qu)b->out, + (qu)b->total ); } @@ -473,8 +483,11 @@ format_row_ip_proto(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->proto, getproto(p->proto), - b->in, b->out, b->total + p->proto, + getproto(p->proto), + (qu)b->in, + (qu)b->out, + (qu)b->total ); } @@ -812,7 +825,6 @@ struct bucket * host_get_port_tcp(struct bucket *host, const uint16_t port) { struct host *h = &host->u.host; - assert(h != NULL); if (h->ports_tcp == NULL) h->ports_tcp = hashtable_make(PORT_BITS, opt_ports_max, opt_ports_keep, hash_func_short, free_func_simple, key_func_port_tcp, @@ -821,6 +833,18 @@ host_get_port_tcp(struct bucket *host, const uint16_t port) return (hashtable_find_or_insert(h->ports_tcp, &port, ALLOW_REDUCE)); } +struct bucket * +host_get_port_tcp_remote(struct bucket *host, const uint16_t port) +{ + struct host *h = &host->u.host; + if (h->ports_tcp_remote == NULL) + h->ports_tcp_remote = hashtable_make( + PORT_BITS, opt_ports_max, opt_ports_keep, hash_func_short, + free_func_simple, key_func_port_tcp, find_func_port_tcp, + make_func_port_tcp, format_cols_port_tcp, format_row_port_tcp); + return (hashtable_find_or_insert(h->ports_tcp_remote, &port, ALLOW_REDUCE)); +} + /* --------------------------------------------------------------------------- * Find or create a port_udp inside a host. */ @@ -828,7 +852,6 @@ struct bucket * host_get_port_udp(struct bucket *host, const uint16_t port) { struct host *h = &host->u.host; - assert(h != NULL); if (h->ports_udp == NULL) h->ports_udp = hashtable_make(PORT_BITS, opt_ports_max, opt_ports_keep, hash_func_short, free_func_simple, key_func_port_udp, @@ -837,6 +860,18 @@ host_get_port_udp(struct bucket *host, const uint16_t port) return (hashtable_find_or_insert(h->ports_udp, &port, ALLOW_REDUCE)); } +struct bucket * +host_get_port_udp_remote(struct bucket *host, const uint16_t port) +{ + struct host *h = &host->u.host; + if (h->ports_udp_remote == NULL) + h->ports_udp_remote = hashtable_make( + PORT_BITS, opt_ports_max, opt_ports_keep, hash_func_short, + free_func_simple, key_func_port_udp, find_func_port_udp, + make_func_port_udp, format_cols_port_udp, format_row_port_udp); + return (hashtable_find_or_insert(h->ports_udp_remote, &port, ALLOW_REDUCE)); +} + /* --------------------------------------------------------------------------- * Find or create an ip_proto inside a host. */ @@ -1024,14 +1059,12 @@ done: /* --------------------------------------------------------------------------- * Web interface: detailed view of a single host. */ -static struct str * -html_hosts_detail(const char *ip) -{ +static struct str *html_hosts_detail(const char *ip) { struct bucket *h; struct str *buf, *ls_len; char ls_when[100]; const char *canonical; - time_t ls; + time_t last_seen_real; h = host_search(ip); if (h == NULL) @@ -1069,20 +1102,28 @@ html_hosts_detail(const char *ip) "

\n" "Last seen: "); - ls = h->u.host.lastseen; - if (strftime(ls_when, sizeof(ls_when), - "%Y-%m-%d %H:%M:%S %Z%z", localtime(&ls)) != 0) - str_append(buf, ls_when); - - if (h->u.host.lastseen <= now) { - ls_len = length_of_time(now - h->u.host.lastseen); - str_append(buf, " ("); - str_appendstr(buf, ls_len); - str_free(ls_len); - str_append(buf, " ago)"); + if (h->u.host.last_seen_mono == 0) { + str_append(buf, "(never)"); } else { - str_append(buf, " (in the future, possible clock problem)"); - } + last_seen_real = mono_to_real(h->u.host.last_seen_mono); + if (strftime(ls_when, sizeof(ls_when), + "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_seen_real)) != 0) + str_append(buf, ls_when); + + if (h->u.host.last_seen_mono <= now_mono()) { + ls_len = + length_of_time((int64_t)now_mono() - h->u.host.last_seen_mono); + str_append(buf, " ("); + str_appendstr(buf, ls_len); + str_free(ls_len); + str_append(buf, " ago)"); + } else { + str_appendf(buf, " (in the future, possible clock problem, " + "last = %qd, now = %qu)", + (qd)h->u.host.last_seen_mono, + (qu)now_mono()); + } + } str_appendf(buf, "

\n" @@ -1091,39 +1132,53 @@ html_hosts_detail(const char *ip) " Out: %'qu
\n" " Total: %'qu
\n" "

\n", - h->in, h->out, h->total); + (qu)h->in, + (qu)h->out, + (qu)h->total); - str_append(buf, "

TCP ports

\n"); + str_append(buf, "

TCP ports on this host

\n"); format_table(buf, h->u.host.ports_tcp, 0,TOTAL,0); - str_append(buf, "

UDP ports

\n"); + str_append(buf, "

TCP ports on remote hosts

\n"); + format_table(buf, h->u.host.ports_tcp_remote, 0,TOTAL,0); + + str_append(buf, "

UDP ports on this host

\n"); format_table(buf, h->u.host.ports_udp, 0,TOTAL,0); + str_append(buf, "

UDP ports on remote hosts

\n"); + format_table(buf, h->u.host.ports_udp_remote, 0,TOTAL,0); + str_append(buf, "

IP protocols

\n"); format_table(buf, h->u.host.ip_protos, 0,TOTAL,0); + str_append(buf, "
\n"); html_close(buf); - return (buf); + return buf; } /* --------------------------------------------------------------------------- * Database import and export code: * Initially written and contributed by Ben Stewart. - * copyright (c) 2007-2011 Ben Stewart, Emil Mikulic. + * copyright (c) 2007-2014 Ben Stewart, Emil Mikulic. */ static int hosts_db_export_ip(const struct hashtable *h, const int fd); -static int hosts_db_export_tcp(const struct hashtable *h, const int fd); -static int hosts_db_export_udp(const struct hashtable *h, const int fd); +static int hosts_db_export_tcp(const char magic, const struct hashtable *h, + const int fd); +static int hosts_db_export_udp(const char magic, const struct hashtable *h, + const int fd); static const char - export_proto_ip = 'P', - export_proto_tcp = 'T', - export_proto_udp = 'U'; + export_proto_ip = 'P', + export_proto_tcp = 'T', + export_proto_tcp_remote = 't', + export_proto_udp = 'U', + export_proto_udp_remote = 'u'; static const unsigned char export_tag_host_ver1[] = {'H', 'S', 'T', 0x01}, export_tag_host_ver2[] = {'H', 'S', 'T', 0x02}, - export_tag_host_ver3[] = {'H', 'S', 'T', 0x03}; + export_tag_host_ver3[] = {'H', 'S', 'T', 0x03}, + export_tag_host_ver4[] = {'H', 'S', 'T', 0x04}; /* --------------------------------------------------------------------------- * Load a host's ip_proto table from a file. @@ -1157,15 +1212,16 @@ hosts_db_import_ip(const int fd, struct bucket *host) } /* --------------------------------------------------------------------------- - * Load a host's port_tcp table from a file. + * Load a host's port_tcp{,_remote} table from a file. * Returns 0 on failure, 1 on success. */ -static int -hosts_db_import_tcp(const int fd, struct bucket *host) -{ +static int hosts_db_import_tcp(const int fd, const char magic, + struct bucket *host, + struct bucket *(get_port_fn)(struct bucket *host, + uint16_t port)) { uint16_t count, i; - if (!expect8(fd, export_proto_tcp)) return 0; + if (!expect8(fd, magic)) return 0; if (!read16(fd, &count)) return 0; for (i=0; iin = in; b->out = out; b->total = in + out; @@ -1193,12 +1249,13 @@ hosts_db_import_tcp(const int fd, struct bucket *host) * Load a host's port_tcp table from a file. * Returns 0 on failure, 1 on success. */ -static int -hosts_db_import_udp(const int fd, struct bucket *host) -{ +static int hosts_db_import_udp(const int fd, const char magic, + struct bucket *host, + struct bucket *(get_port_fn)(struct bucket *host, + uint16_t port)) { uint16_t count, i; - if (!expect8(fd, export_proto_udp)) return 0; + if (!expect8(fd, magic)) return 0; if (!read16(fd, &count)) return 0; for (i=0; iin = in; b->out = out; b->total = in + out; @@ -1236,7 +1293,9 @@ hosts_db_import_host(const int fd) int ver = 0; if (!readn(fd, hdr, sizeof(hdr))) return 0; - if (memcmp(hdr, export_tag_host_ver3, sizeof(hdr)) == 0) + if (memcmp(hdr, export_tag_host_ver4, sizeof(hdr)) == 0) + ver = 4; + else if (memcmp(hdr, export_tag_host_ver3, sizeof(hdr)) == 0) ver = 3; else if (memcmp(hdr, export_tag_host_ver2, sizeof(hdr)) == 0) ver = 2; @@ -1248,7 +1307,7 @@ hosts_db_import_host(const int fd) return 0; } - if (ver == 3) { + if (ver >= 3) { if (!readaddr(fd, &a)) return 0; } else { @@ -1263,7 +1322,7 @@ hosts_db_import_host(const int fd) if (ver > 1) { uint64_t t; if (!read64(fd, &t)) return 0; - host->u.host.lastseen = (time_t)t; + host->u.host.last_seen_mono = real_to_mono(t); } assert(sizeof(host->u.host.mac_addr) == 6); @@ -1295,8 +1354,19 @@ hosts_db_import_host(const int fd) /* Host's port and proto subtables: */ if (!hosts_db_import_ip(fd, host)) return 0; - if (!hosts_db_import_tcp(fd, host)) return 0; - if (!hosts_db_import_udp(fd, host)) return 0; + if (!hosts_db_import_tcp(fd, export_proto_tcp, host, host_get_port_tcp)) + return 0; + if (!hosts_db_import_udp(fd, export_proto_udp, host, host_get_port_udp)) + return 0; + + if (ver == 4) { + if (!hosts_db_import_tcp(fd, export_proto_tcp_remote, host, + host_get_port_tcp_remote)) + return 0; + if (!hosts_db_import_udp(fd, export_proto_udp_remote, host, + host_get_port_udp_remote)) + return 0; + } return 1; } @@ -1333,12 +1403,14 @@ int hosts_db_export(const int fd) for (i = 0; isize; i++) for (b = hosts_db->table[i]; b != NULL; b = b->next) { /* For each host: */ - if (!writen(fd, export_tag_host_ver3, sizeof(export_tag_host_ver3))) + if (!writen(fd, export_tag_host_ver4, sizeof(export_tag_host_ver4))) return 0; - if (!writeaddr(fd, &(b->u.host.addr))) return 0; + if (!writeaddr(fd, &(b->u.host.addr))) + return 0; - if (!write64(fd, (uint64_t)(b->u.host.lastseen))) return 0; + if (!write64(fd, (uint64_t)mono_to_real(b->u.host.last_seen_mono))) + return 0; assert(sizeof(b->u.host.mac_addr) == 6); if (!writen(fd, b->u.host.mac_addr, sizeof(b->u.host.mac_addr))) @@ -1365,8 +1437,16 @@ int hosts_db_export(const int fd) if (!write64(fd, b->out)) return 0; if (!hosts_db_export_ip(b->u.host.ip_protos, fd)) return 0; - if (!hosts_db_export_tcp(b->u.host.ports_tcp, fd)) return 0; - if (!hosts_db_export_udp(b->u.host.ports_udp, fd)) return 0; + if (!hosts_db_export_tcp(export_proto_tcp, b->u.host.ports_tcp, fd)) + return 0; + if (!hosts_db_export_udp(export_proto_udp, b->u.host.ports_udp, fd)) + return 0; + if (!hosts_db_export_tcp(export_proto_tcp_remote, + b->u.host.ports_tcp_remote, fd)) + return 0; + if (!hosts_db_export_udp(export_proto_udp_remote, + b->u.host.ports_udp_remote, fd)) + return 0; } return 1; } @@ -1409,13 +1489,13 @@ hosts_db_export_ip(const struct hashtable *h, const int fd) * Dump the port_tcp table of a host. */ static int -hosts_db_export_tcp(const struct hashtable *h, const int fd) +hosts_db_export_tcp(const char magic, const struct hashtable *h, const int fd) { struct bucket *b; uint32_t i, written = 0; /* TCP DATA */ - if (!write8(fd, export_proto_tcp)) return 0; + if (!write8(fd, magic)) return 0; /* If no data, write a count of 0 and we're done. */ if (h == NULL) { @@ -1442,13 +1522,13 @@ hosts_db_export_tcp(const struct hashtable *h, const int fd) * Dump the port_udp table of a host. */ static int -hosts_db_export_udp(const struct hashtable *h, const int fd) +hosts_db_export_udp(const char magic, const struct hashtable *h, const int fd) { struct bucket *b; uint32_t i, written = 0; /* UDP DATA */ - if (!write8(fd, export_proto_udp)) return 0; + if (!write8(fd, magic)) return 0; /* If no data, write a count of 0 and we're done. */ if (h == NULL) { @@ -1470,4 +1550,4 @@ hosts_db_export_udp(const struct hashtable *h, const int fd) return 1; } -/* vim:set ts=3 sw=3 tw=78 expandtab: */ +/* vim:set ts=3 sw=3 tw=80 expandtab: */