/* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
*
* hosts_db.c: database of hosts, ports, protocols.
*
#include "opt.h"
#include "str.h"
-#include <netdb.h> /* struct addrinfo */
+#include <netdb.h> /* struct addrinfo */
#include <assert.h>
#include <errno.h>
#include <stdio.h>
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 );
}
* 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) );
}
* 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] );
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);
}
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);
}
" <td class=\"num\">%'qu</td>\n"
" <td class=\"num\">%'qu</td>\n"
" <td class=\"num\">%'qu</td>\n",
- b->in, b->out, b->total);
+ (qu)b->in,
+ (qu)b->out,
+ (qu)b->total);
if (opt_want_lastseen) {
- long last = b->u.host.last_seen_mono;
+ int64_t last = b->u.host.last_seen_mono;
+ int64_t now = (int64_t)now_mono();
struct str *last_str = NULL;
- if ((now_mono() >= last) && (last > 0))
- last_str = length_of_time(now_mono() - last);
+ if ((now >= last) && (last != 0))
+ last_str = length_of_time(now - last);
str_append(buf, " <td class=\"num\">");
if (last_str == NULL) {
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);
" <td class=\"num\">%'qu</td>\n"
"</tr>\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
);
}
" <td class=\"num\">%'qu</td>\n"
"</tr>\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
);
}
" <td class=\"num\">%'qu</td>\n"
"</tr>\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
);
}
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,
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.
*/
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,
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.
*/
struct str *buf, *ls_len;
char ls_when[100];
const char *canonical;
- time_t last_real;
+ time_t last_seen_real;
h = host_search(ip);
if (h == NULL)
"<p>\n"
"<b>Last seen:</b> ");
- last_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_real)) != 0)
- str_append(buf, ls_when);
-
- if (h->u.host.last_seen_mono <= now_mono()) {
- ls_len = length_of_time(now_mono() - h->u.host.last_seen_mono);
- 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,
"</p>\n"
" <b>Out:</b> %'qu<br>\n"
" <b>Total:</b> %'qu<br>\n"
"</p>\n",
- h->in, h->out, h->total);
+ (qu)h->in,
+ (qu)h->out,
+ (qu)h->total);
- str_append(buf, "<h3>TCP ports</h3>\n");
+ str_append(buf, "<h3>TCP ports on this host</h3>\n");
format_table(buf, h->u.host.ports_tcp, 0,TOTAL,0);
- str_append(buf, "<h3>UDP ports</h3>\n");
+ str_append(buf, "<h3>TCP ports on remote hosts</h3>\n");
+ format_table(buf, h->u.host.ports_tcp_remote, 0,TOTAL,0);
+
+ str_append(buf, "<h3>UDP ports on this host</h3>\n");
format_table(buf, h->u.host.ports_udp, 0,TOTAL,0);
+ str_append(buf, "<h3>UDP ports on remote hosts</h3>\n");
+ format_table(buf, h->u.host.ports_udp_remote, 0,TOTAL,0);
+
str_append(buf, "<h3>IP protocols</h3>\n");
format_table(buf, h->u.host.ip_protos, 0,TOTAL,0);
+ str_append(buf, "<br>\n");
html_close(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.
}
/* ---------------------------------------------------------------------------
- * 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; i<count; i++) {
if (!read64(fd, &out)) return 0;
/* Store data */
- b = host_get_port_tcp(host, port);
+ b = get_port_fn(host, port);
b->in = in;
b->out = out;
b->total = in + out;
* 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; i<count; i++) {
if (!read64(fd, &out)) return 0;
/* Store data */
- b = host_get_port_udp(host, port);
+ b = get_port_fn(host, port);
b->in = in;
b->out = out;
b->total = in + out;
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;
return 0;
}
- if (ver == 3) {
+ if (ver >= 3) {
if (!readaddr(fd, &a))
return 0;
} else {
/* 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;
}
for (i = 0; i<hosts_db->size; 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)))
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;
}
* 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) {
* 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) {
return 1;
}
-/* vim:set ts=3 sw=3 tw=78 expandtab: */
+/* vim:set ts=3 sw=3 tw=80 expandtab: */