Migration from 'in_addr_t' to 'struct addr46'.
authorMats Erik Andersson <debian@gisladisker.se>
Wed, 13 Oct 2010 19:28:45 +0000 (21:28 +0200)
committerEmil Mikulic <emikulic@gmail.com>
Mon, 9 May 2011 12:48:50 +0000 (22:48 +1000)
In order to achieve a uniform handling of IPv4
and IPv6, a new structure 'struct addr46' encloses
both address families in a space efficient manner.
This commit completes the migration, and achieves
functionality for IPv4 accounting and IPv4 DNS lookup.

12 files changed:
acct.c
db.c
db.h
decode.c
decode.h
dns.c
dns.h
graph_db.c
hosts_db.c
hosts_db.h
localip.c
localip.h

diff --git a/acct.c b/acct.c
index a00e86f..8f947a8 100644 (file)
--- a/acct.c
+++ b/acct.c
@@ -63,8 +63,8 @@ acct_init_localnet(const char *spec)
    free(tokens[1]);
    free(tokens);
 
-   verbosef("local network address: %s", ip_to_str(localnet));
-   verbosef("   local network mask: %s", ip_to_str(localmask));
+   verbosef("local network address: %s", ip_to_str_af(&localnet, AF_INET));
+   verbosef("   local network mask: %s", ip_to_str_af(&localmask, AF_INET));
 
    if ((localnet & localmask) != localnet)
       errx(1, "this is an invalid combination of address and mask!\n"
@@ -77,11 +77,12 @@ acct_for(const pktsummary *sm)
 {
    struct bucket *hs = NULL, *hd = NULL;
    struct bucket *ps, *pd;
+   struct addr46 ipaddr;
    int dir_in, dir_out;
 
 #if 0 /* WANT_CHATTY? */
-   printf("%15s > ", ip_to_str(sm->src_ip));
-   printf("%15s ", ip_to_str(sm->dest_ip));
+   printf("%15s > ", ip_to_str_af(&sm->src_ip, AF_INET));
+   printf("%15s ", ip_to_str_af(&sm->dest_ip, AF_INET));
    printf("len %4d proto %2d", sm->len, sm->proto);
 
    if (sm->proto == IPPROTO_TCP || sm->proto == IPPROTO_UDP)
@@ -107,17 +108,17 @@ acct_for(const pktsummary *sm)
 
    if (sm->af == AF_INET) {
       if (using_localnet) {
-         if ((sm->src_ip & localmask) == localnet)
+         if ((sm->src_ip.s_addr & localmask) == localnet)
             dir_out = 1;
-         if ((sm->dest_ip & localmask) == localnet)
+         if ((sm->dest_ip.s_addr & localmask) == localnet)
             dir_in = 1;
          if (dir_in == 1 && dir_out == 1)
             /* Traffic staying within the network isn't counted. */
             dir_in = dir_out = 0;
       } else {
-         if (sm->src_ip == localip)
+         if (memcmp(&sm->src_ip, &localip, sizeof(localip)) == 0)
             dir_out = 1;
-         if (sm->dest_ip == localip)
+         if (memcmp(&sm->dest_ip, &localip, sizeof(localip)) == 0)
             dir_in = 1;
       }
    } else if (sm->af == AF_INET6) {
@@ -142,20 +143,24 @@ acct_for(const pktsummary *sm)
    if (hosts_max == 0) return; /* skip per-host accounting */
 
    /* Hosts. */
-   hs = host_get(sm->src_ip);
+   ipaddr.af = sm->af; /* TODO */
+   ipaddr.addr.ip = sm->src_ip; /* TODO */
+   hs = host_get(&ipaddr);
    hs->out   += sm->len;
    hs->total += sm->len;
    memcpy(hs->u.host.mac_addr, sm->src_mac, sizeof(sm->src_mac));
    hs->u.host.last_seen = now;
 
-   hd = host_get(sm->dest_ip); /* this can invalidate hs! */
+   ipaddr.addr.ip = sm->dest_ip; /* TODO */
+   hd = host_get(&ipaddr); /* this can invalidate hs! */
    hd->in    += sm->len;
    hd->total += sm->len;
    memcpy(hd->u.host.mac_addr, sm->dst_mac, sizeof(sm->dst_mac));
    hd->u.host.last_seen = now;
 
    /* Protocols. */
-   hs = host_find(sm->src_ip);
+   ipaddr.addr.ip = sm->src_ip; /* TODO */
+   hs = host_find(&ipaddr);
    if (hs != NULL) {
       ps = host_get_ip_proto(hs, sm->proto);
       ps->out   += sm->len;
diff --git a/db.c b/db.c
index 6d0e129..6a15ade 100644 (file)
--- a/db.c
+++ b/db.c
@@ -152,14 +152,20 @@ read32(const int fd, uint32_t *dest)
    return 1;
 }
 
-/* Read an in_addr_t from a file.  Addresses are always stored in network
+/* Read a struct addr46 from a file.  Addresses are always stored in network
  * order, both in the file and in the host's memory (FIXME: is that right?)
+ * The component "dest->af" must specify AF_INET or AF_INET6.
  */
 int
-readaddr(const int fd, in_addr_t *dest)
+readaddr(const int fd, struct addr46 *dest)
 {
-   assert(sizeof(*dest) == 4);
-   return readn(fd, dest, sizeof(*dest));
+   assert(sizeof(*dest) == sizeof(struct addr46));
+   assert(dest->af == AF_INET || dest->af == AF_INET6);
+
+   if (dest->af == AF_INET)
+      return readn(fd, &dest->addr.ip, sizeof(struct in_addr));
+   else
+      return readn(fd, &dest->addr.ip6, sizeof(struct in6_addr));
 }
 
 /* Read a network order uint64_t from a file
@@ -237,14 +243,20 @@ write64(const int fd, const uint64_t i)
 }
 
 
-/* Write an in_addr_t to a file.  Addresses are always stored in network
- * order, both in the file and in the host's memory (FIXME: is that right?)
+/* Write the active address part in a struct addr46 structure to a file.
+ * Addresses are always stored in network order, both in the file and
+ * in the host's memory (FIXME: is that right?)
  */
 int
-writeaddr(const int fd, const in_addr_t addr)
+writeaddr(const int fd, const struct addr46 *const ip)
 {
-   assert(sizeof(addr) == 4);
-   return writen(fd, &addr, sizeof(addr));
+   assert(sizeof(*ip) == sizeof(struct addr46));
+   assert(ip->af == AF_INET || ip->af == AF_INET6);
+
+   if (ip->af == AF_INET)
+      return writen(fd, &ip->addr.ip, sizeof(ip->addr.ip));
+   else
+      return writen(fd, &ip->addr.ip6, sizeof(ip->addr.ip6));
 }
 
 /* ---------------------------------------------------------------------------
diff --git a/db.h b/db.h
index 64705cf..8f3e686 100644 (file)
--- a/db.h
+++ b/db.h
@@ -4,6 +4,8 @@
  * copyright (c) 2007 Ben Stewart, Emil Mikulic.
  */
 
+#include "hosts_db.h"   /* addr46 */
+
 void db_import(const char *filename);
 void db_export(const char *filename);
 
@@ -19,7 +21,7 @@ int read8(const int fd, uint8_t *dest);
 int expect8(const int fd, uint8_t expecting);
 int read16(const int fd, uint16_t *dest);
 int read32(const int fd, uint32_t *dest);
-int readaddr(const int fd, in_addr_t *dest);
+int readaddr(const int fd, struct addr46 *dest);
 int read64(const int fd, uint64_t *dest);
 int read_file_header(const int fd, const uint8_t expected[4]);
 
@@ -28,7 +30,7 @@ int writen(const int fd, const void *dest, const size_t len);
 int write8(const int fd, const uint8_t i);
 int write16(const int fd, const uint16_t i);
 int write32(const int fd, const uint32_t i);
-int writeaddr(const int fd, const in_addr_t addr);
+int writeaddr(const int fd, const struct addr46 *const addr);
 int write64(const int fd, const uint64_t i);
 
 /* vim:set ts=3 sw=3 tw=78 et: */
index 344439a..c8e2f24 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -127,31 +127,32 @@ int
 getsnaplen(const linkhdr_t *lh)
 {
    assert(lh != NULL);
-   return (lh->hdrlen + IPV6_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
+   /* TODO MEA Investigate why the supplementary value 20 is needed on GNU/Linux.  */
+   return (20 + lh->hdrlen + IPV6_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
 }
 
 /*
- * Convert IP address to a numbers-and-dots notation in a static buffer
- * provided by inet_ntoa().
+ * Convert IP address to a presentation notation in a static buffer
+ * using inet_ntop(3).
  */
+char ipstr[INET6_ADDRSTRLEN]; /* TODO Reentrant? */
+
 char *
-ip_to_str(const in_addr_t ip)
+ip_to_str(const struct addr46 *const ip)
 {
-   struct in_addr in;
+   ipstr[0] = '\0';
+   inet_ntop(ip->af, &ip->addr.ip6, ipstr, sizeof(ipstr));
 
-   in.s_addr = ip;
-   return (inet_ntoa(in));
+   return (ipstr);
 }
 
-char ip6str[INET6_ADDRSTRLEN];
-
 char *
-ip6_to_str(const struct in6_addr *ip6)
+ip_to_str_af(const void *const addr, sa_family_t af)
 {
-   ip6str[0] = '\0';
-   inet_ntop(AF_INET6, ip6, ip6str, sizeof(ip6str));
+   ipstr[0] = '\0';
+   inet_ntop(af, addr, ipstr, sizeof(ipstr));
 
-   return (ip6str);
+   return (ipstr);
 }
 
 /* Decoding functions. */
@@ -369,8 +370,8 @@ decode_ip(const u_char *pdata, const uint32_t len, pktsummary *sm)
    sm->len = ntohs(hdr->ip_len);
    sm->af = AF_INET;
    sm->proto = hdr->ip_p;
-   sm->src_ip = hdr->ip_src.s_addr;
-   sm->dest_ip = hdr->ip_dst.s_addr;
+   memcpy(&sm->src_ip, &hdr->ip_src, sizeof(sm->src_ip));
+   memcpy(&sm->dest_ip, &hdr->ip_dst, sizeof(sm->dest_ip));
 
    switch (sm->proto) {
       case IPPROTO_TCP: {
index 10f443c..679b2e8 100644 (file)
--- a/decode.h
+++ b/decode.h
 #include <pcap.h>
 #include <netinet/in_systm.h>  /* n_time */
 #define __USE_GNU 1
-#include <netinet/in.h> /* in_addr_t */
+#include <netinet/in.h> /* for <netinet/ip.h>  */
 #include <netinet/ip.h> /* struct ip */
 
+#include "hosts_db.h"   /* addr46 */
+
 #define PPP_HDR_LEN     4
 #define FDDI_HDR_LEN    21
 #define IP_HDR_LEN      sizeof(struct ip)
@@ -36,17 +38,17 @@ typedef struct {
 
 const linkhdr_t *getlinkhdr(int linktype);
 int getsnaplen(const linkhdr_t *lh);
-char *ip_to_str(const in_addr_t ip);
-char *ip6_to_str(const struct in6_addr *ip6);
+char *ip_to_str(const struct addr46 *const ip);
+char *ip_to_str_af(const void *const addr, sa_family_t af);
 
 typedef struct {
    /* Fields are in host byte order (except IPs) */
    union {
-      in_addr_t src_ip;
+      struct in_addr src_ip;
       struct in6_addr src_ip6;
    };
    union {
-      in_addr_t dest_ip;
+      struct in_addr dest_ip;
       struct in6_addr dest_ip6;
    };
    time_t time;
diff --git a/dns.c b/dns.c
index cb36d21..128910a 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -35,8 +35,8 @@ static int sock[2];
 static pid_t pid = -1;
 
 struct dns_reply {
-   in_addr_t ip;
-   int error; /* h_errno, or 0 if no error */
+   struct addr46 addr;
+   int error; /* for gai_strerror(), or 0 if no error */
    char name[MAXHOSTNAMELEN];
 };
 
@@ -86,15 +86,26 @@ dns_stop(void)
 
 struct tree_rec {
    RB_ENTRY(tree_rec) ptree;
-   in_addr_t ip;
+   struct addr46 ip;
 };
 
 static int
 tree_cmp(struct tree_rec *a, struct tree_rec *b)
 {
-   if (a->ip < b->ip) return (-1); else
-   if (a->ip > b->ip) return (+1); else
-   return (0);
+   if (a->ip.af != b->ip.af)
+      /* Sort IPv4 to the left of IPv6.  */
+      return (a->ip.af == AF_INET ? -1 : +1);
+
+   if (a->ip.af == AF_INET) {
+      return (memcmp(&a->ip.addr.ip, &b->ip.addr.ip, sizeof(a->ip.addr.ip)));
+   }
+
+   /* AF_INET6 should remain.  */
+   if (a->ip.af == AF_INET6)
+      return (memcmp(&a->ip.addr.ip6, &b->ip.addr.ip6, sizeof(a->ip.addr.ip6)));
+
+   /* Last resort.  */
+   return -1;
 }
 
 static RB_HEAD(tree_t, tree_rec) ip_tree = RB_INITIALIZER(&tree_rec);
@@ -106,7 +117,7 @@ static struct tree_rec * tree_t_RB_MINMAX(struct tree_t *head, int val)
 RB_GENERATE(tree_t, tree_rec, ptree, tree_cmp)
 
 void
-dns_queue(const in_addr_t ip)
+dns_queue(const struct addr46 *const ipaddr)
 {
    struct tree_rec *rec;
    ssize_t num_w;
@@ -114,38 +125,46 @@ dns_queue(const in_addr_t ip)
    if (pid == -1)
       return; /* no child was started - we're not doing any DNS */
 
+#if 1
+   if (ipaddr->af != AF_INET) {
+      verbosef("dns_queue() for unknown family %d.\n", ipaddr->af);
+      /* Not yet IPv6 capable.  */
+      return;
+   }
+#endif
+
    rec = xmalloc(sizeof(*rec));
-   rec->ip = ip;
+   memcpy(&rec->ip, ipaddr, sizeof(rec->ip));
+
    if (RB_INSERT(tree_t, &ip_tree, rec) != NULL) {
       /* Already queued - this happens seldom enough that we don't care about
        * the performance hit of needlessly malloc()ing. */
-      verbosef("already queued %s", ip_to_str(ip));
+      verbosef("already queued %s", ip_to_str(ipaddr));
       free(rec);
       return;
    }
 
-   num_w = write(sock[PARENT], &ip, sizeof(ip)); /* won't block */
+   num_w = write(sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */
    if (num_w == 0)
       warnx("dns_queue: write: ignoring end of file");
    else if (num_w == -1)
       warn("dns_queue: ignoring write error");
-   else if (num_w != sizeof(ip))
-      err(1, "dns_queue: wrote %d instead of %d",
-         (int)num_w, (int)sizeof(ip));
+   else if (num_w != sizeof(*ipaddr))
+      err(1, "dns_queue: wrote %z instead of %z", num_w, sizeof(*ipaddr));
 }
 
 static void
-dns_unqueue(const in_addr_t ip)
+dns_unqueue(const struct addr46 *const ipaddr)
 {
    struct tree_rec tmp, *rec;
 
-   tmp.ip = ip;
+   memcpy(&tmp.ip, ipaddr, sizeof(tmp.ip));
    if ((rec = RB_FIND(tree_t, &ip_tree, &tmp)) != NULL) {
       RB_REMOVE(tree_t, &ip_tree, rec);
       free(rec);
    }
    else
-      verbosef("couldn't unqueue %s - not in queue!", ip_to_str(ip));
+      verbosef("couldn't unqueue %s - not in queue!", ip_to_str(ipaddr));
 }
 
 /*
@@ -153,7 +172,7 @@ dns_unqueue(const in_addr_t ip)
  * (name buffer is allocated by dns_poll)
  */
 static int
-dns_get_result(in_addr_t *ip, char **name)
+dns_get_result(struct addr46 *ipaddr, char **name)
 {
    struct dns_reply reply;
    ssize_t numread;
@@ -168,16 +187,38 @@ dns_get_result(in_addr_t *ip, char **name)
    if (numread == 0)
       goto error; /* EOF */
    if (numread != sizeof(reply))
-      errx(1, "dns_get_result read got %d, expected %d",
-         (int)numread, (int)sizeof(reply));
+      errx(1, "dns_get_result read got %z, expected %z", numread, sizeof(reply));
 
    /* Return successful reply. */
-   *ip = reply.ip;
+   memcpy(ipaddr, &reply.addr, sizeof(*ipaddr));
+#if DARKSTAT_USES_HOSTENT
    if (reply.error != 0)
       xasprintf(name, "(%s)", hstrerror(reply.error));
    else
       *name = xstrdup(reply.name);
-   dns_unqueue(reply.ip);
+#else /* !DARKSTAT_USES_HOSTENT */
+   if (reply.error != 0) {
+      /* Identify common special cases.  */
+      char *type = "none";
+
+      if (reply.addr.af == AF_INET6) {
+         if (IN6_IS_ADDR_LINKLOCAL(&reply.addr.addr.ip6))
+            type = "link-local";
+         else if (IN6_IS_ADDR_SITELOCAL(&reply.addr.addr.ip6))
+            type = "site-local";
+         else if (IN6_IS_ADDR_MULTICAST(&reply.addr.addr.ip6))
+            type = "multicast";
+      } else { /* AF_INET */
+         if (IN_MULTICAST(reply.addr.addr.ip.s_addr))
+            type = "multicast";
+      }
+      xasprintf(name, "(%s)", type);
+   }
+   else  /* Correctly resolved name.  */
+      *name = xstrdup(reply.name);
+#endif /* !DARKSTAT_USES_HOSTENT */
+
+   dns_unqueue(&reply.addr);
    return (1);
 
 error:
@@ -189,7 +230,7 @@ error:
 void
 dns_poll(void)
 {
-   in_addr_t ip;
+   struct addr46 ip;
    char *name;
 
    if (pid == -1)
@@ -197,15 +238,16 @@ dns_poll(void)
 
    while (dns_get_result(&ip, &name)) {
       /* push into hosts_db */
-      struct bucket *b = host_find(ip);
+      struct bucket *b = host_find(&ip);
+
       if (b == NULL) {
          verbosef("resolved %s to %s but it's not in the DB!",
-            ip_to_str(ip), name);
+            ip_to_str(&ip), name);
          return;
       }
       if (b->u.host.dns != NULL) {
          verbosef("resolved %s to %s but it's already in the DB!",
-            ip_to_str(ip), name);
+            ip_to_str(&ip), name);
          return;
       }
       b->u.host.dns = name;
@@ -216,25 +258,25 @@ dns_poll(void)
 
 struct qitem {
    STAILQ_ENTRY(qitem) entries;
-   in_addr_t ip;
+   struct addr46 ip;
 };
 
 STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue);
 
 static void
-enqueue(const in_addr_t ip)
+enqueue(const struct addr46 *const ip)
 {
    struct qitem *i;
 
    i = xmalloc(sizeof(*i));
-   i->ip = ip;
+   memcpy(&i->ip, ip, sizeof(i->ip));
    STAILQ_INSERT_TAIL(&queue, i, entries);
    verbosef("DNS: enqueued %s", ip_to_str(ip));
 }
 
 /* Return non-zero and populate <ip> pointer if queue isn't empty. */
 static int
-dequeue(in_addr_t *ip)
+dequeue(struct addr46 *ip)
 {
    struct qitem *i;
 
@@ -242,8 +284,9 @@ dequeue(in_addr_t *ip)
    if (i == NULL)
       return (0);
    STAILQ_REMOVE_HEAD(&queue, entries);
-   *ip = i->ip;
+   memcpy(ip, &i->ip, sizeof(*ip));
    free(i);
+   verbosef("DNS: dequeued %s", ip_to_str(ip));
    return 1;
 }
 
@@ -261,7 +304,7 @@ xwrite(const int d, const void *buf, const size_t nbytes)
 static void
 dns_main(void)
 {
-   in_addr_t ip;
+   struct addr46 ip;
 
 #ifdef HAVE_SETPROCTITLE
    setproctitle("DNS child");
@@ -292,9 +335,8 @@ dns_main(void)
             err(1, "DNS: read failed");
          }
          if (numread != sizeof(ip))
-            err(1, "DNS: read got %d bytes, expecting %d",
-               (int)numread, (int)sizeof(ip));
-         enqueue(ip);
+            err(1, "DNS: read got %z bytes, expecting %z", numread, sizeof(ip));
+         enqueue(&ip);
          if (blocking) {
             /* After one blocking read, become non-blocking so that when we
              * run out of input we fall through to queue processing.
@@ -307,10 +349,11 @@ dns_main(void)
       /* Process queue. */
       if (dequeue(&ip)) {
          struct dns_reply reply;
+#if DARKSTAT_USES_HOSTENT
          struct hostent *he;
 
-         reply.ip = ip;
-         he = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET);
+         memcpy(&reply.addr, &ip, sizeof(reply.addr));
+         he = gethostbyaddr((char *)&ip.addr.ip, sizeof(ip.addr.ip), ip.af); /* TODO MEA */
 
          /* On some platforms (for example Linux with GLIBC 2.3.3), h_errno
           * will be non-zero here even though the lookup succeeded.
@@ -325,8 +368,52 @@ dns_main(void)
          }
          fd_set_block(sock[CHILD]);
          xwrite(sock[CHILD], &reply, sizeof(reply));
-         verbosef("DNS: %s is %s", ip_to_str(ip),
+         verbosef("DNS: %s is %s", ip_to_str(&reply.addr),
             (h_errno == 0)?reply.name:hstrerror(h_errno));
+#else /* !DARKSTAT_USES_HOSTENT */
+         struct sockaddr_in sin;
+         struct sockaddr_in6 sin6;
+         char host[NI_MAXHOST];
+         int ret, flags;
+
+         reply.addr.af = ip.af;
+         flags = NI_NAMEREQD;
+#  ifdef NI_IDN
+         flags |= NI_IDN;
+#  endif
+         switch (ip.af) {
+            case AF_INET:
+               sin.sin_family = ip.af;
+               memcpy(&reply.addr.addr.ip, &ip.addr.ip, sizeof(reply.addr.addr.ip));
+               memcpy(&sin.sin_addr, &ip.addr.ip, sizeof(sin.sin_addr));
+               ret = getnameinfo((struct sockaddr *) &sin, sizeof(sin),
+                                 host, sizeof(host), NULL, 0, flags);
+               break;
+            case AF_INET6:
+               sin6.sin6_family = ip.af;
+               memcpy(&reply.addr.addr.ip6, &ip.addr.ip6, sizeof(reply.addr.addr.ip6));
+               memcpy(&sin6.sin6_addr, &ip.addr.ip6, sizeof(sin6.sin6_addr));
+               ret = getnameinfo((struct sockaddr *) &sin6, sizeof(sin6),
+                                 host, sizeof(host), NULL, 0, flags);
+               break;
+            default:
+               ret = EAI_FAMILY;
+
+         }
+
+         if (ret != 0) {
+            reply.name[0] = '\0';
+            reply.error = ret;
+         } else {
+            assert(sizeof(reply.name) > sizeof(char *)); /* not just a ptr */
+            strlcpy(reply.name, host, sizeof(reply.name));
+            reply.error = 0;
+         }
+         fd_set_block(sock[CHILD]);
+         xwrite(sock[CHILD], &reply, sizeof(reply));
+         verbosef("DNS: %s is \"%s\".", ip_to_str(&reply.addr),
+            (ret == 0) ? reply.name : gai_strerror(ret));
+#endif /* !DARKSTAT_USES_HOSTENT */
       }
    }
 }
diff --git a/dns.h b/dns.h
index fc72e4f..f7fdb3c 100644 (file)
--- a/dns.h
+++ b/dns.h
@@ -7,11 +7,11 @@
  * GNU General Public License version 2. (see COPYING.GPL)
  */
 
-#include <netinet/in.h> /* in_addr_t */
+#include "hosts_db.h"   /* addr46 */
 
 void dns_init(const char *privdrop_user);
 void dns_stop(void);
-void dns_queue(const in_addr_t ip);
+void dns_queue(const struct addr46 *const ip);
 void dns_poll(void);
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
index 580f8ba..ea5a403 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <sys/types.h>
-#include <netinet/in.h> /* for in_addr_t (db.h needs it) */
 
 #include "cap.h"
 #include "conv.h"
index 4228d82..81d7959 100644 (file)
@@ -19,6 +19,7 @@
 #include "now.h"
 
 #include <arpa/inet.h> /* inet_aton() */
+#include <netdb.h>     /* struct addrinfo */
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
@@ -101,9 +102,9 @@ coprime(const uint32_t u)
  * src/sys/netinet/tcp_hostcache.c 1.1
  */
 inline static uint32_t
-ipv4_hash(const uint32_t ip)
+ipv4_hash(const struct in_addr *const ip)
 {
-   return ( (ip) ^ ((ip) >> 7) ^ ((ip) >> 17) );
+   return ( (ip->s_addr) ^ ((ip->s_addr) >> 7) ^ ((ip->s_addr) >> 17) );
 }
 
 #ifndef s6_addr32
@@ -130,7 +131,16 @@ ipv6_hash(const struct in6_addr *const ip6)
 static uint32_t
 hash_func_host(const struct hashtable *h _unused_, const void *key)
 {
-   return (ipv4_hash(CASTKEY(in_addr_t)));
+   struct addr46 *ip = (struct addr46 *) key;
+
+   switch (ip->af) {
+      case AF_INET:
+         return (ipv4_hash(&ip->addr.ip));
+      case AF_INET6:
+         return (ipv6_hash(&ip->addr.ip6));
+      default:
+         return 0;
+   }
 }
 
 static uint32_t
@@ -152,7 +162,7 @@ hash_func_byte(const struct hashtable *h, const void *key)
 static const void *
 key_func_host(const struct bucket *b)
 {
-   return &(b->u.host.ip);
+   return &(b->u.host.ipaddr);
 }
 
 static const void *
@@ -180,7 +190,23 @@ key_func_ip_proto(const struct bucket *b)
 static int
 find_func_host(const struct bucket *b, const void *key)
 {
-   return (b->u.host.ip == CASTKEY(in_addr_t));
+   struct addr46 *ipaddr = (struct addr46 *) key;
+
+   if (b->u.host.ipaddr.af != ipaddr->af)
+      return 0; /* not comparable */
+
+   switch (ipaddr->af) {
+      case AF_INET:
+         return (memcmp(&b->u.host.ipaddr.addr.ip,
+                        &ipaddr->addr.ip, sizeof(ipaddr->addr.ip))
+                  == 0);
+      case AF_INET6:
+         return (memcmp(&b->u.host.ipaddr.addr.ip6,
+                        &ipaddr->addr.ip6, sizeof(ipaddr->addr.ip6))
+                  == 0);
+      default:
+         return 0;
+   }
 }
 
 static int
@@ -218,7 +244,7 @@ static struct bucket *
 make_func_host(const void *key)
 {
    MAKE_BUCKET(b, h, host);
-   h->ip = CASTKEY(in_addr_t);
+   memcpy(&h->ipaddr, key, sizeof(h->ipaddr));
    h->dns = NULL;
    h->last_seen = now;
    memset(&h->mac_addr, 0, sizeof(h->mac_addr));
@@ -301,7 +327,7 @@ static void
 format_row_host(struct str *buf, const struct bucket *b,
    const char *css_class)
 {
-   const char *ip = ip_to_str( b->u.host.ip );
+   const char *ip = ip_to_str( &b->u.host.ipaddr );
 
    str_appendf(buf,
       "<tr class=\"%s\">\n"
@@ -351,7 +377,7 @@ format_row_host(struct str *buf, const struct bucket *b,
 
    /* Only resolve hosts "on demand" */
    if (b->u.host.dns == NULL)
-      dns_queue(b->u.host.ip);
+      dns_queue(&b->u.host.ipaddr);
 }
 
 static void
@@ -631,18 +657,18 @@ hashtable_free(struct hashtable *h)
  * Return existing host or insert a new one.
  */
 struct bucket *
-host_get(const in_addr_t ip)
+host_get(const struct addr46 *const ip)
 {
-   return (hashtable_find_or_insert(hosts_db, &ip));
+   return (hashtable_find_or_insert(hosts_db, ip));
 }
 
 /* ---------------------------------------------------------------------------
  * Find host, returns NULL if not in DB.
  */
 struct bucket *
-host_find(const in_addr_t ip)
+host_find(const struct addr46 *const ip)
 {
-   return (hashtable_search(hosts_db, &ip));
+   return (hashtable_search(hosts_db, ip));
 }
 
 /* ---------------------------------------------------------------------------
@@ -651,11 +677,35 @@ host_find(const in_addr_t ip)
 static struct bucket *
 host_search(const char *ipstr)
 {
-   struct in_addr addr;
+   struct addr46 ipaddr;
+   struct sockaddr_storage ss;
+   struct addrinfo hints, *ai;
 
-   if (inet_aton(ipstr, &addr) != 1)
+   memset(&hints, 0, sizeof(hints));
+   hints.ai_family = AF_UNSPEC;
+   hints.ai_flags = AI_NUMERICHOST;
+
+   if (getaddrinfo(ipstr, NULL, &hints, &ai))
       return (NULL); /* invalid addr */
-   return (hashtable_search(hosts_db, &(addr.s_addr)));
+
+   memcpy(&ss, ai->ai_addr, ai->ai_addrlen);
+   freeaddrinfo(ai);
+
+   ipaddr.af = ss.ss_family;
+   switch (ss.ss_family) {
+      case AF_INET:
+         memcpy(&ipaddr.addr.ip, &((struct sockaddr_in *) &ss)->sin_addr,
+               sizeof(ipaddr.addr.ip));
+         break;
+      case AF_INET6:
+         memcpy(&ipaddr.addr.ip6, &((struct sockaddr_in6 *) &ss)->sin6_addr,
+               sizeof(ipaddr.addr.ip6));
+         break;
+      default:
+         return (NULL);
+   }
+
+   return (hashtable_search(hosts_db, &ipaddr));
 }
 
 /* ---------------------------------------------------------------------------
@@ -999,7 +1049,7 @@ html_hosts_detail(const char *ip)
 
    /* Resolve host "on demand" */
    if (h->u.host.dns == NULL)
-      dns_queue(h->u.host.ip);
+      dns_queue(&h->u.host.ipaddr);
 
    if (show_mac_addrs)
    str_appendf(buf,
@@ -1175,7 +1225,7 @@ static int
 hosts_db_import_host(const int fd)
 {
    struct bucket *host;
-   in_addr_t addr;
+   struct addr46 ipaddr;
    uint8_t hostname_len;
    uint64_t in, out;
    unsigned int pos = xtell(fd);
@@ -1193,10 +1243,11 @@ hosts_db_import_host(const int fd)
       return 0;
    }
 
-   if (!readaddr(fd, &addr)) return 0;
-   verbosef("at file pos %u, importing host %s", pos, ip_to_str(addr));
-   host = host_get(addr);
-   assert(host->u.host.ip == addr); /* make fn? */
+   ipaddr.af = AF_INET;
+   if (!readaddr(fd, &ipaddr)) return 0;
+   verbosef("at file pos %u, importing host %s", pos, ip_to_str(&ipaddr));
+   host = host_get(&ipaddr);
+   assert(host->u.host.ipaddr.addr.ip.s_addr == ipaddr.addr.ip.s_addr); /* make fn? */
 
    if (ver > 1) {
       uint64_t t;
@@ -1274,7 +1325,7 @@ int hosts_db_export(const int fd)
       if (!writen(fd, export_tag_host_ver2, sizeof(export_tag_host_ver2)))
          return 0;
 
-      if (!writeaddr(fd, b->u.host.ip)) return 0;
+      if (!writeaddr(fd, &b->u.host.ipaddr)) return 0;
 
       if (!write64(fd, (uint64_t)(b->u.host.last_seen))) return 0;
 
index 41141be..3db28fb 100644 (file)
@@ -7,18 +7,26 @@
  * GNU General Public License version 2. (see COPYING.GPL)
  */
 
+#ifndef __HOSTS_DB_H
+#  define __HOSTS_DB_H 1
+
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
 #include "str.h"
 
+struct addr46 {
+   sa_family_t af;
+   union {
+      struct in_addr ip;
+      struct in6_addr ip6;
+   } addr;
+};
+
 struct hashtable;
 
 struct host {
-   union {
-      in_addr_t ip;
-      struct in6_addr ip6;
-   };
-   sa_family_t af;
+   struct addr46 ipaddr;
    char *dns;
    uint8_t mac_addr[6];
    time_t last_seen;
@@ -66,8 +74,8 @@ void hosts_db_free(void);
 int hosts_db_import(const int fd);
 int hosts_db_export(const int fd);
 
-struct bucket *host_find(const in_addr_t ip); /* can return NULL */
-struct bucket *host_get(const in_addr_t ip);
+struct bucket *host_find(const struct addr46 *const ip); /* can return NULL */
+struct bucket *host_get(const struct addr46 *const ip);
 struct bucket *host_get_port_tcp(struct bucket *host, const uint16_t port);
 struct bucket *host_get_port_udp(struct bucket *host, const uint16_t port);
 struct bucket *host_get_ip_proto(struct bucket *host, const uint8_t proto);
@@ -79,4 +87,5 @@ struct str *html_hosts(const char *uri, const char *query);
 void qsort_buckets(const struct bucket **a, size_t n,
    size_t left, size_t right, const enum sort_dir d);
 
+#endif /* !__HOSTS_DB_H */
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
index 11330cd..2980bc9 100644 (file)
--- a/localip.c
+++ b/localip.c
@@ -9,7 +9,7 @@
 
 #include "darkstat.h"
 #include "conv.h" /* for strlcpy */
-#include "decode.h" /* for ip_to_str, ip6_to_str */
+#include "decode.h" /* for ip_to_str */
 #include "err.h"
 #include "localip.h"
 
@@ -22,8 +22,8 @@
 
 static const char *iface = NULL;
 
-in_addr_t localip = 0;
-static in_addr_t last_localip = 0;
+struct in_addr localip = { 0 };
+static struct in_addr last_localip = { 0 };
 
 struct in6_addr localip6;
 static struct in6_addr last_localip6;
@@ -46,8 +46,8 @@ localip_update(void)
 
    if (iface == NULL) {
       /* reading from capfile */
-      localip = 0;
-      memset(&localip6, '\0', sizeof(localip6));
+      memset(&localip, 0, sizeof(localip));
+      memset(&localip6, 0, sizeof(localip6));
       return;
    }
 
@@ -65,7 +65,7 @@ localip_update(void)
       if ( (ifa->ifa_addr->sa_family == AF_INET)
             && ! (flags & HAS_IPV4) ) {
          /* Good IPv4 address. */
-         localip = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr;
+         localip.s_addr = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr;
          flags |= HAS_IPV4;
          continue;
       }
@@ -103,12 +103,14 @@ localip_update(void)
     *      __u32   s_addr;
     */
 
-   if (last_localip != localip) {
-      verbosef("local_ip update(%s) = %s", iface, ip_to_str(localip));
-      last_localip = localip;
+   if (last_localip.s_addr != localip.s_addr) {
+      verbosef("local_ip update(%s) = %s", iface,
+               ip_to_str_af(&localip, AF_INET));
+      memcpy(&last_localip, &localip, sizeof(last_localip));
    }
    if (memcmp(&last_localip6, &localip6, sizeof(localip6))) {
-      verbosef("local_ip6 update(%s) = %s", iface, ip6_to_str(&localip6));
+      verbosef("local_ip6 update(%s) = %s", iface,
+               ip_to_str_af(&localip6, AF_INET6));
       memcpy(&last_localip6, &localip6, sizeof(localip6));
    }
 }
index 07fff19..a16a6a9 100644 (file)
--- a/localip.h
+++ b/localip.h
@@ -7,9 +7,9 @@
  * GNU General Public License version 2. (see COPYING.GPL)
  */
 
-#include <netinet/in.h> /* for in_addr_t */
+#include <netinet/in.h> /* for in_addr, in6_addr */
 
-extern in_addr_t localip;
+extern struct in_addr localip;
 extern struct in6_addr localip6;
 
 void localip_init(const char *interface);