#include "darkstat.h"
#include "acct.h"
+#include "decode.h"
#include "conv.h"
#include "daylog.h"
#include "err.h"
#define __FAVOR_BSD
#include <netinet/tcp.h>
#include <sys/socket.h>
+#include <assert.h>
+#include <ctype.h> /* for isdigit */
+#include <netdb.h> /* for gai_strerror */
#include <stdlib.h> /* for free */
#include <string.h> /* for memcpy */
-#include <ctype.h> /* isdigit() */
uint64_t total_packets = 0, total_bytes = 0;
-static int using_localnet = 0;
-static int using_localnet6 = 0;
-static in_addr_t localnet, localmask;
-static struct in6_addr localnet6, localmask6;
+static int using_localnet4 = 0, using_localnet6 = 0;
+static struct addr localnet4, localmask4, localnet6, localmask6;
/* Parse the net/mask specification into two IPs or die trying. */
void
acct_init_localnet(const char *spec)
{
- char **tokens, *p;
- int num_tokens, isnum, j;
- int build_ipv6; /* Zero for IPv4, one for IPv6. */
+ char **tokens;
+ int num_tokens, isnum, j, ret;
int pfxlen, octets, remainder;
- struct in_addr addr;
- struct in6_addr addr6;
+ struct addr localnet, localmask;
tokens = split('/', spec, &num_tokens);
if (num_tokens != 2)
errx(1, "expecting network/netmask, got \"%s\"", spec);
- /* Presence of a colon distinguishes address families. */
- if (strchr(tokens[0], ':')) {
- build_ipv6 = 1;
- if (inet_pton(AF_INET6, tokens[0], &addr6) != 1)
- errx(1, "invalid IPv6 network address \"%s\"", tokens[0]);
- memcpy(&localnet6, &addr6, sizeof(localnet6));
- } else {
- build_ipv6 = 0;
- if (inet_pton(AF_INET, tokens[0], &addr) != 1)
- errx(1, "invalid network address \"%s\"", tokens[0]);
- localnet = addr.s_addr;
- }
+ if ((ret = str_to_addr(tokens[0], &localnet)) != 0)
+ errx(1, "couldn't parse \"%s\": %s", tokens[0], gai_strerror(ret));
/* Detect a purely numeric argument. */
isnum = 0;
- p = tokens[1];
- while (*p != '\0') {
- if (isdigit(*p)) {
- isnum = 1;
- ++p;
- continue;
- } else {
- isnum = 0;
- break;
+ {
+ const char *p = tokens[1];
+ while (*p != '\0') {
+ if (isdigit(*p)) {
+ isnum = 1;
+ ++p;
+ continue;
+ } else {
+ isnum = 0;
+ break;
+ }
}
}
if (!isnum) {
- if (build_ipv6) {
- if (inet_pton(AF_INET6, tokens[1], &addr6) != 1)
- errx(1, "invalid IPv6 network mask \"%s\"", tokens[1]);
- memcpy(&localmask6, &addr6, sizeof(localmask6));
- } else {
- if (inet_pton(AF_INET, tokens[1], &addr) != 1)
- errx(1, "invalid network mask \"%s\"", tokens[1]);
- localmask = addr.s_addr;
- }
+ if ((ret = str_to_addr(tokens[1], &localmask)) != 0)
+ errx(1, "couldn't parse \"%s\": %s", tokens[1], gai_strerror(ret));
+ if (localmask.family != localnet.family)
+ errx(1, "family mismatch between net and mask");
} else {
uint8_t frac, *p;
+ localmask.family = localnet.family;
+
/* Compute the prefix length. */
- pfxlen = strtonum(tokens[1], 1, build_ipv6 ? 128 : 32, NULL);
+ pfxlen = strtonum(tokens[1], 1,
+ (localnet.family == IPv6) ? 128 : 32, NULL);
if (pfxlen == 0)
errx(1, "invalid network prefix length \"%s\"", tokens[1]);
/* Construct the network mask. */
octets = pfxlen / 8;
remainder = pfxlen % 8;
- p = build_ipv6 ? (uint8_t *) localmask6.s6_addr : (uint8_t *) &localmask;
+ p = (localnet.family == IPv6) ? (localmask.ip.v6.s6_addr)
+ : ((uint8_t *) &(localmask.ip.v4));
- if (build_ipv6)
- memset(&localmask6, 0, sizeof(localmask6));
+ if (localnet.family == IPv6)
+ memset(p, 0, 16);
else
- memset(&localmask, 0, sizeof(localmask));
+ memset(p, 0, 4);
for (j = 0; j < octets; ++j)
p[j] = 0xff;
p[j] = frac; /* Have contribution for next position. */
}
+ free(tokens[0]);
+ free(tokens[1]);
+ free(tokens);
+
/* Register the correct netmask and calculate the correct net. */
- if (build_ipv6) {
+ addr_mask(&localnet, &localmask);
+ if (localnet.family == IPv6) {
using_localnet6 = 1;
- for (j = 0; j < 16; ++j)
- localnet6.s6_addr[j] &= localmask6.s6_addr[j];
+ localnet6 = localnet;
+ localmask6 = localmask;
} else {
- using_localnet = 1;
- localnet &= localmask;
+ using_localnet4 = 1;
+ localnet4 = localnet;
+ localmask4 = localmask;
}
- free(tokens[0]);
- free(tokens[1]);
- free(tokens);
+ verbosef("local network address: %s", addr_to_str(&localnet));
+ verbosef(" local network mask: %s", addr_to_str(&localmask));
+}
- if (build_ipv6) {
- verbosef("local network address: %s", ip_to_str_af(&localnet6, AF_INET6));
- verbosef(" local network mask: %s", ip_to_str_af(&localmask6, AF_INET6));
+static int
+addr_is_local(const struct addr * const a)
+{
+ if (a->family == IPv4) {
+ if (using_localnet4) {
+ if (addr_inside(a, &localnet4, &localmask4))
+ return 1;
+ } else {
+ if (addr_equal(a, &localip4))
+ return 1;
+ }
} else {
- verbosef("local network address: %s", ip_to_str_af(&localnet, AF_INET));
- verbosef(" local network mask: %s", ip_to_str_af(&localmask, AF_INET));
+ assert(a->family == IPv6);
+ if (using_localnet6) {
+ if (addr_inside(a, &localnet6, &localmask6))
+ return 1;
+ } else {
+ if (addr_equal(a, &localip6))
+ return 1;
+ }
}
-
+ return 0;
}
/* Account for the given packet summary. */
void
-acct_for(const pktsummary *sm)
+acct_for(const struct pktsummary * const sm)
{
struct bucket *hs = NULL, *hd = NULL;
struct bucket *ps, *pd;
- struct addr46 ipaddr;
- struct in6_addr scribble;
- int dir_in, dir_out, j;
+ int dir_in, dir_out;
#if 0 /* WANT_CHATTY? */
- printf("%15s > ", ip_to_str_af(&sm->src_ip, AF_INET));
- printf("%15s ", ip_to_str_af(&sm->dest_ip, AF_INET));
+ printf("%15s > ", addr_to_str(&sm->src));
+ printf("%15s ", addr_to_str(&sm->dst));
printf("len %4d proto %2d", sm->len, sm->proto);
if (sm->proto == IPPROTO_TCP || sm->proto == IPPROTO_UDP)
- printf(" port %5d : %5d", sm->src_port, sm->dest_port);
+ printf(" port %5d : %5d", sm->src_port, sm->dst_port);
if (sm->proto == IPPROTO_TCP)
printf(" %s%s%s%s%s%s",
(sm->tcp_flags & TH_FIN)?"F":"",
total_bytes += sm->len;
/* Graphs. */
- dir_in = dir_out = 0;
-
- if (sm->af == AF_INET) {
- if (using_localnet) {
- if ((sm->src_ip.s_addr & localmask) == localnet)
- dir_out = 1;
- 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 (memcmp(&sm->src_ip, &localip, sizeof(localip)) == 0)
- dir_out = 1;
- if (memcmp(&sm->dest_ip, &localip, sizeof(localip)) == 0)
- dir_in = 1;
- }
- } else if (sm->af == AF_INET6) {
- if (using_localnet6) {
- for (j = 0; j < 16; ++j)
- scribble.s6_addr[j] = sm->src_ip6.s6_addr[j] & localmask6.s6_addr[j];
- if (memcmp(&scribble, &localnet6, sizeof(scribble)) == 0)
- dir_out = 1;
- else {
- for (j = 0; j < 16; ++j)
- scribble.s6_addr[j] = sm->dest_ip6.s6_addr[j] & localmask6.s6_addr[j];
- if (memcmp(&scribble, &localnet6, sizeof(scribble)) == 0)
- dir_in = 1;
- }
- } else {
- if (memcmp(&sm->src_ip6, &localip6, sizeof(localip6)) == 0)
- dir_out = 1;
- if (memcmp(&sm->dest_ip6, &localip6, sizeof(localip6)) == 0)
- dir_in = 1;
- }
- }
+ dir_out = addr_is_local(&(sm->src));
+ dir_in = addr_is_local(&(sm->dst));
+
+ /* Traffic staying within the network isn't counted. */
+ if (dir_in == 1 && dir_out == 1)
+ dir_in = dir_out = 0;
if (dir_out) {
daylog_acct((uint64_t)sm->len, GRAPH_OUT);
if (hosts_max == 0) return; /* skip per-host accounting */
/* Hosts. */
- ipaddr.af = sm->af;
- switch (ipaddr.af) {
- case AF_INET6:
- memcpy(&ipaddr.addr.ip6, &sm->src_ip6, sizeof(ipaddr.addr.ip6));
- break;
- case AF_INET:
- default:
- memcpy(&ipaddr.addr.ip, &sm->src_ip, sizeof(ipaddr.addr.ip));
- break;
- }
- hs = host_get(&ipaddr);
+ hs = host_get(&(sm->src));
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;
- switch (ipaddr.af) {
- case AF_INET6:
- memcpy(&ipaddr.addr.ip6, &sm->dest_ip6, sizeof(ipaddr.addr.ip6));
- break;
- case AF_INET:
- default:
- memcpy(&ipaddr.addr.ip, &sm->dest_ip, sizeof(ipaddr.addr.ip));
- break;
- }
- hd = host_get(&ipaddr); /* this can invalidate hs! */
+ hd = host_get(&(sm->dst)); /* 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. */
- switch (ipaddr.af) {
- case AF_INET6:
- memcpy(&ipaddr.addr.ip6, &sm->src_ip6, sizeof(ipaddr.addr.ip6));
- break;
- case AF_INET:
- default:
- memcpy(&ipaddr.addr.ip, &sm->src_ip, sizeof(ipaddr.addr.ip));
- break;
- }
- hs = host_find(&ipaddr);
+ hs = host_find(&(sm->src));
if (hs != NULL) {
ps = host_get_ip_proto(hs, sm->proto);
ps->out += sm->len;
ps->total += sm->len;
}
- if (sm->dest_port <= highest_port)
+ if (sm->dst_port <= highest_port)
{
- pd = host_get_port_tcp(hd, sm->dest_port);
+ pd = host_get_port_tcp(hd, sm->dst_port);
pd->in += sm->len;
pd->total += sm->len;
if (sm->tcp_flags == TH_SYN)
ps->total += sm->len;
}
- if (sm->dest_port <= highest_port)
+ if (sm->dst_port <= highest_port)
{
- pd = host_get_port_udp(hd, sm->dest_port);
+ pd = host_get_port_udp(hd, sm->dst_port);
pd->in += sm->len;
pd->total += sm->len;
}
* acct.h: traffic accounting
*/
-#include "decode.h"
+#include <stdint.h>
+
+struct pktsummary;
extern uint64_t total_packets, total_bytes;
void acct_init_localnet(const char *spec);
-void acct_for(const pktsummary *sm);
+void acct_for(const struct pktsummary * const sm);
extern unsigned int highest_port;
return 1;
}
-/* Read a struct addr46 from a file. Addresses are always stored in network
+/* Read a struct addr 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, struct addr46 *dest)
+readaddr(const int fd, struct addr *dest)
{
- assert(sizeof(*dest) == sizeof(struct addr46));
- assert(dest->af == AF_INET || dest->af == AF_INET6);
+ assert(dest->family == IPv4 || dest->family == AF_INET6);
- if (dest->af == AF_INET)
- return readn(fd, &dest->addr.ip, sizeof(struct in_addr));
+ if (dest->family == IPv4)
+ return readn(fd, &(dest->ip.v4), sizeof(dest->ip.v4));
else
- return readn(fd, &dest->addr.ip6, sizeof(struct in6_addr));
+ return readn(fd, dest->ip.v6.s6_addr, sizeof(dest->ip.v6.s6_addr));
}
/* Read a network order uint64_t from a file
}
-/* Write the active address part in a struct addr46 structure to a file.
+/* Write the active address part in a struct addr 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 struct addr46 *const ip)
+writeaddr(const int fd, const struct addr *const a)
{
- 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));
+ if (a->family == IPv4)
+ return writen(fd, &(a->ip.v4), sizeof(a->ip.v4));
+ else {
+ assert(a->family == IPv6);
+ return writen(fd, a->ip.v6.s6_addr, sizeof(a->ip.v6.s6_addr));
+ }
}
/* ---------------------------------------------------------------------------
* copyright (c) 2007 Ben Stewart, Emil Mikulic.
*/
-#include "hosts_db.h" /* addr46 */
+#include <sys/types.h> /* for size_t */
+#include <stdint.h> /* for uint64_t */
+
+struct addr;
void db_import(const char *filename);
void db_export(const char *filename);
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, struct addr46 *dest);
int read64(const int fd, uint64_t *dest);
+int readaddr(const int fd, struct addr *dest);
int read_file_header(const int fd, const uint8_t expected[4]);
/* write helpers */
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 struct addr46 *const addr);
int write64(const int fd, const uint64_t i);
+int writeaddr(const int fd, const struct addr *const a);
/* vim:set ts=3 sw=3 tw=78 et: */
#include "darkstat.h"
#include "acct.h"
#include "cap.h"
+#include "decode.h"
+#include "err.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <assert.h>
-#include "err.h"
#include <pcap.h>
#include <string.h>
#include <unistd.h>
static void decode_pppoe(u_char *, const struct pcap_pkthdr *,
const u_char *);
static void decode_pppoe_real(const u_char *pdata, const uint32_t len,
- pktsummary *sm);
+ struct pktsummary *sm);
static void decode_linux_sll(u_char *, const struct pcap_pkthdr *,
const u_char *);
static void decode_raw(u_char *, const struct pcap_pkthdr *,
const u_char *);
static void decode_ip(const u_char *pdata, const uint32_t len,
- pktsummary *sm);
+ struct pktsummary *sm);
static void decode_ipv6(const u_char *pdata, const uint32_t len,
- pktsummary *sm);
+ struct pktsummary *sm);
/* Link-type header information */
static const struct linkhdr linkhdrs[] = {
{ DLT_LINUX_SLL, SLL_HDR_LEN, decode_linux_sll },
#endif
{ DLT_RAW, RAW_HDR_LEN, decode_raw },
- { -1, -1, NULL }
+ { -1, 0, NULL }
};
/*
return (20 + lh->hdrlen + IPV6_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
}
-/*
- * 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 struct addr46 *const ip)
-{
- ipstr[0] = '\0';
- inet_ntop(ip->af, &ip->addr.ip6, ipstr, sizeof(ipstr));
-
- return (ipstr);
-}
-
-char *
-ip_to_str_af(const void *const addr, sa_family_t af)
-{
- ipstr[0] = '\0';
- inet_ntop(af, addr, ipstr, sizeof(ipstr));
-
- return (ipstr);
-}
-
/* Decoding functions. */
static void
decode_ether(u_char *user _unused_,
{
u_short type;
const struct ether_header *hdr = (const struct ether_header *)pdata;
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
sm.time = pheader->ts.tv_sec;
const u_char *pdata)
{
uint32_t family;
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
if (pheader->caplen < NULL_HDR_LEN) {
const struct pcap_pkthdr *pheader,
const u_char *pdata)
{
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
if (pheader->caplen < PPPOE_HDR_LEN) {
const struct pcap_pkthdr *pheader,
const u_char *pdata)
{
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
sm.time = pheader->ts.tv_sec;
decode_pppoe_real(pdata, pheader->caplen, &sm);
static void
decode_pppoe_real(const u_char *pdata, const uint32_t len,
- pktsummary *sm)
+ struct pktsummary *sm)
{
if (len < PPPOE_HDR_LEN) {
verbosef("pppoe: packet too short (%u bytes)", len);
uint16_t ether_type;
} *hdr = (const struct sll_header *)pdata;
u_short type;
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
if (pheader->caplen < SLL_HDR_LEN) {
const struct pcap_pkthdr *pheader,
const u_char *pdata)
{
- pktsummary sm;
+ struct pktsummary sm;
memset(&sm, 0, sizeof(sm));
decode_ip(pdata, pheader->caplen, &sm);
}
static void
-decode_ip(const u_char *pdata, const uint32_t len, pktsummary *sm)
+decode_ip(const u_char *pdata, const uint32_t len, struct pktsummary *sm)
{
const struct ip *hdr = (const struct ip *)pdata;
}
sm->len = ntohs(hdr->ip_len);
- sm->af = AF_INET;
sm->proto = hdr->ip_p;
- memcpy(&sm->src_ip, &hdr->ip_src, sizeof(sm->src_ip));
- memcpy(&sm->dest_ip, &hdr->ip_dst, sizeof(sm->dest_ip));
+
+ sm->src.family = IPv4;
+ sm->src.ip.v4 = hdr->ip_src.s_addr;
+
+ sm->dst.family = IPv4;
+ sm->dst.ip.v4 = hdr->ip_dst.s_addr;
switch (sm->proto) {
case IPPROTO_TCP: {
return;
}
sm->src_port = ntohs(thdr->th_sport);
- sm->dest_port = ntohs(thdr->th_dport);
+ sm->dst_port = ntohs(thdr->th_dport);
sm->tcp_flags = thdr->th_flags &
(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
break;
return;
}
sm->src_port = ntohs(uhdr->uh_sport);
- sm->dest_port = ntohs(uhdr->uh_dport);
+ sm->dst_port = ntohs(uhdr->uh_dport);
break;
}
}
static void
-decode_ipv6(const u_char *pdata, const uint32_t len, pktsummary *sm)
+decode_ipv6(const u_char *pdata, const uint32_t len, struct pktsummary *sm)
{
const struct ip6_hdr *hdr = (const struct ip6_hdr *)pdata;
}
sm->len = ntohs(hdr->ip6_plen) + IPV6_HDR_LEN;
- sm->af = AF_INET6;
sm->proto = hdr->ip6_nxt;
- memcpy(&sm->src_ip6, &hdr->ip6_src, sizeof(sm->src_ip6));
- memcpy(&sm->dest_ip6, &hdr->ip6_dst, sizeof(sm->dest_ip6));
+
+ sm->src.family = IPv6;
+ memcpy(&sm->src.ip.v6, &hdr->ip6_src, sizeof(sm->src.ip.v6));
+
+ sm->dst.family = IPv6;
+ memcpy(&sm->dst.ip.v6, &hdr->ip6_dst, sizeof(sm->dst.ip.v6));
switch (sm->proto) {
case IPPROTO_TCP: {
return;
}
sm->src_port = ntohs(thdr->th_sport);
- sm->dest_port = ntohs(thdr->th_dport);
+ sm->dst_port = ntohs(thdr->th_dport);
sm->tcp_flags = thdr->th_flags &
(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
break;
return;
}
sm->src_port = ntohs(uhdr->uh_sport);
- sm->dest_port = ntohs(uhdr->uh_dport);
+ sm->dst_port = ntohs(uhdr->uh_dport);
break;
}
#include <netinet/in.h> /* for <netinet/ip.h> */
#include <netinet/ip.h> /* struct ip */
-#include "hosts_db.h" /* addr46 */
+#include "addr.h"
#define PPP_HDR_LEN 4
#define FDDI_HDR_LEN 21
const struct linkhdr *getlinkhdr(const int linktype);
int getsnaplen(const struct linkhdr *lh);
-char *ip_to_str(const struct addr46 *const ip);
-char *ip_to_str_af(const void *const addr, sa_family_t af);
-typedef struct {
+struct pktsummary {
/* Fields are in host byte order (except IPs) */
- union {
- struct in_addr src_ip;
- struct in6_addr src_ip6;
- };
- union {
- struct in_addr dest_ip;
- struct in6_addr dest_ip6;
- };
+ struct addr src, dst;
time_t time;
uint16_t len;
- sa_family_t af; /* AF_{UNSPEC, INET, INET6} */
- uint8_t proto; /* IPPROTO_{TCP, UDP, ICMP} */
- uint8_t tcp_flags; /* only for TCP */
- uint16_t src_port, dest_port; /* only for TCP, UDP */
+ uint8_t proto; /* IPPROTO_{TCP, UDP, ICMP} */
+ uint8_t tcp_flags; /* only for TCP */
+ uint16_t src_port, dst_port; /* only for TCP, UDP */
uint8_t src_mac[ETHER_ADDR_LEN],
dst_mac[ETHER_ADDR_LEN]; /* only for Ethernet */
-} pktsummary;
+};
#endif /* __DARKSTAT_DECODE_H */
/* vim:set ts=3 sw=3 tw=78 expandtab: */
#include "err.h"
#include "hosts_db.h"
#include "queue.h"
+#include "str.h"
#include "tree.h"
#include <sys/param.h>
static pid_t pid = -1;
struct dns_reply {
- struct addr46 addr;
+ struct addr addr;
int error; /* for gai_strerror(), or 0 if no error */
char name[MAXHOSTNAMELEN];
};
struct tree_rec {
RB_ENTRY(tree_rec) ptree;
- struct addr46 ip;
+ struct addr ip;
};
static int
tree_cmp(struct tree_rec *a, struct tree_rec *b)
{
- if (a->ip.af != b->ip.af)
+ if (a->ip.family != b->ip.family)
/* Sort IPv4 to the left of IPv6. */
- return (a->ip.af == AF_INET ? -1 : +1);
+ return ((a->ip.family == IPv4) ? -1 : +1);
- if (a->ip.af == AF_INET) {
- return (memcmp(&a->ip.addr.ip, &b->ip.addr.ip, sizeof(a->ip.addr.ip)));
+ if (a->ip.family == IPv4)
+ return (memcmp(&a->ip.ip.v4, &b->ip.ip.v4, sizeof(a->ip.ip.v4)));
+ else {
+ assert(a->ip.family == IPv6);
+ return (memcmp(&a->ip.ip.v6, &b->ip.ip.v6, sizeof(a->ip.ip.v6)));
}
-
- /* 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);
RB_GENERATE(tree_t, tree_rec, ptree, tree_cmp)
void
-dns_queue(const struct addr46 *const ipaddr)
+dns_queue(const struct addr *const ipaddr)
{
struct tree_rec *rec;
ssize_t num_w;
if (pid == -1)
return; /* no child was started - we're not doing any DNS */
- if (ipaddr->af != AF_INET && ipaddr->af != AF_INET6) {
- verbosef("dns_queue() for unknown family %d.\n", ipaddr->af);
+ if ((ipaddr->family != IPv4) && (ipaddr->family != IPv6)) {
+ verbosef("dns_queue() for unknown family %d", ipaddr->family);
return;
}
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(ipaddr));
+ verbosef("already queued %s", addr_to_str(ipaddr));
free(rec);
return;
}
}
static void
-dns_unqueue(const struct addr46 *const ipaddr)
+dns_unqueue(const struct addr *const ipaddr)
{
struct tree_rec tmp, *rec;
free(rec);
}
else
- verbosef("couldn't unqueue %s - not in queue!", ip_to_str(ipaddr));
+ verbosef("couldn't unqueue %s - not in queue!", addr_to_str(ipaddr));
}
/*
* (name buffer is allocated by dns_poll)
*/
static int
-dns_get_result(struct addr46 *ipaddr, char **name)
+dns_get_result(struct addr *ipaddr, char **name)
{
struct dns_reply reply;
ssize_t numread;
#else /* !DARKSTAT_USES_HOSTENT */
if (reply.error != 0) {
/* Identify common special cases. */
- char *type = "none";
+ const char *type = "none";
- if (reply.addr.af == AF_INET6) {
- if (IN6_IS_ADDR_LINKLOCAL(&reply.addr.addr.ip6))
+ if (reply.addr.family == IPv6) {
+ if (IN6_IS_ADDR_LINKLOCAL(&reply.addr.ip.v6))
type = "link-local";
- else if (IN6_IS_ADDR_SITELOCAL(&reply.addr.addr.ip6))
+ else if (IN6_IS_ADDR_SITELOCAL(&reply.addr.ip.v6))
type = "site-local";
- else if (IN6_IS_ADDR_MULTICAST(&reply.addr.addr.ip6))
+ else if (IN6_IS_ADDR_MULTICAST(&reply.addr.ip.v6))
type = "multicast";
} else { /* AF_INET */
- if (IN_MULTICAST(reply.addr.addr.ip.s_addr))
+ if (IN_MULTICAST(reply.addr.ip.v4))
type = "multicast";
}
xasprintf(name, "(%s)", type);
void
dns_poll(void)
{
- struct addr46 ip;
+ struct addr ip;
char *name;
if (pid == -1)
if (b == NULL) {
verbosef("resolved %s to %s but it's not in the DB!",
- ip_to_str(&ip), name);
+ addr_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);
+ addr_to_str(&ip), name);
return;
}
b->u.host.dns = name;
struct qitem {
STAILQ_ENTRY(qitem) entries;
- struct addr46 ip;
+ struct addr ip;
};
STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue);
static void
-enqueue(const struct addr46 *const ip)
+enqueue(const struct addr *const ip)
{
struct qitem *i;
i = xmalloc(sizeof(*i));
memcpy(&i->ip, ip, sizeof(i->ip));
STAILQ_INSERT_TAIL(&queue, i, entries);
- verbosef("DNS: enqueued %s", ip_to_str(ip));
+ verbosef("DNS: enqueued %s", addr_to_str(ip));
}
/* Return non-zero and populate <ip> pointer if queue isn't empty. */
static int
-dequeue(struct addr46 *ip)
+dequeue(struct addr *ip)
{
struct qitem *i;
STAILQ_REMOVE_HEAD(&queue, entries);
memcpy(ip, &i->ip, sizeof(*ip));
free(i);
- verbosef("DNS: dequeued %s", ip_to_str(ip));
+ verbosef("DNS: dequeued %s", addr_to_str(ip));
return 1;
}
static void
dns_main(void)
{
- struct addr46 ip;
+ struct addr ip;
#ifdef HAVE_SETPROCTITLE
setproctitle("DNS child");
}
fd_set_block(sock[CHILD]);
xwrite(sock[CHILD], &reply, sizeof(reply));
- verbosef("DNS: %s is %s", ip_to_str(&reply.addr),
+ verbosef("DNS: %s is %s", addr_to_str(&reply.addr),
(h_errno == 0)?reply.name:hstrerror(h_errno));
#else /* !DARKSTAT_USES_HOSTENT */
struct sockaddr_in sin;
char host[NI_MAXHOST];
int ret, flags;
- reply.addr.af = ip.af;
+ reply.addr = ip;
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));
+ switch (ip.family) {
+ case IPv4:
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ip.ip.v4;
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));
+ case IPv6:
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, &ip.ip.v6, 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) {
}
fd_set_block(sock[CHILD]);
xwrite(sock[CHILD], &reply, sizeof(reply));
- verbosef("DNS: %s is \"%s\".", ip_to_str(&reply.addr),
+ verbosef("DNS: %s is \"%s\".", addr_to_str(&reply.addr),
(ret == 0) ? reply.name : gai_strerror(ret));
#endif /* !DARKSTAT_USES_HOSTENT */
}
* GNU General Public License version 2. (see COPYING.GPL)
*/
-#include "hosts_db.h" /* addr46 */
+struct addr;
void dns_init(const char *privdrop_user);
void dns_stop(void);
-void dns_queue(const struct addr46 *const ip);
+void dns_queue(const struct addr *const ipaddr);
void dns_poll(void);
/* vim:set ts=3 sw=3 tw=78 expandtab: */
#include "html.h"
#include "ncache.h"
#include "now.h"
+#include "str.h"
#include <arpa/inet.h> /* inet_aton() */
#include <netdb.h> /* struct addrinfo */
* src/sys/netinet/tcp_hostcache.c 1.1
*/
inline static uint32_t
-ipv4_hash(const struct in_addr *const ip)
+ipv4_hash(const struct addr *const a)
{
- return ( (ip->s_addr) ^ ((ip->s_addr) >> 7) ^ ((ip->s_addr) >> 17) );
+ uint32_t ip = a->ip.v4;
+ return ( (ip) ^ ((ip) >> 7) ^ ((ip) >> 17) );
}
#ifndef s6_addr32
* svn rev 122922.
*/
inline static uint32_t
-ipv6_hash(const struct in6_addr *const ip6)
+ipv6_hash(const struct addr *const a)
{
- return ( ip6->s6_addr32[0] ^ ip6->s6_addr32[1] ^ ip6->s6_addr32[2] ^ ip6->s6_addr32[3] );
+ 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] );
}
/* ---------------------------------------------------------------------------
* hash_func collection
*/
-#define CASTKEY(type) (*((const type *)key))
-
static uint32_t
hash_func_host(const struct hashtable *h _unused_, const void *key)
{
- 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;
+ const struct addr *a = key;
+ if (a->family == IPv4)
+ return (ipv4_hash(a));
+ else {
+ assert(a->family == IPv6);
+ return (ipv6_hash(a));
}
}
+#define CASTKEY(type) (*((const type *)key))
+
static uint32_t
hash_func_short(const struct hashtable *h, const void *key)
{
static const void *
key_func_host(const struct bucket *b)
{
- return &(b->u.host.ipaddr);
+ return &(b->u.host.addr);
}
static const void *
static int
find_func_host(const struct bucket *b, const void *key)
{
- 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;
- }
+ return (addr_equal(key, &(b->u.host.addr)));
}
static int
make_func_host(const void *key)
{
MAKE_BUCKET(b, h, host);
- memcpy(&h->ipaddr, key, sizeof(h->ipaddr));
+ h->addr = CASTKEY(struct addr);
h->dns = NULL;
h->last_seen = now;
memset(&h->mac_addr, 0, sizeof(h->mac_addr));
format_row_host(struct str *buf, const struct bucket *b,
const char *css_class)
{
- const char *ip = ip_to_str( &b->u.host.ipaddr );
+ const char *ip = addr_to_str(&(b->u.host.addr));
str_appendf(buf,
"<tr class=\"%s\">\n"
/* Only resolve hosts "on demand" */
if (b->u.host.dns == NULL)
- dns_queue(&b->u.host.ipaddr);
+ dns_queue(&(b->u.host.addr));
}
static void
* Return existing host or insert a new one.
*/
struct bucket *
-host_get(const struct addr46 *const ip)
+host_get(const struct addr *const a)
{
- return (hashtable_find_or_insert(hosts_db, ip));
+ return (hashtable_find_or_insert(hosts_db, a));
}
/* ---------------------------------------------------------------------------
* Find host, returns NULL if not in DB.
*/
struct bucket *
-host_find(const struct addr46 *const ip)
+host_find(const struct addr *const a)
{
- return (hashtable_search(hosts_db, ip));
+ return (hashtable_search(hosts_db, a));
}
/* ---------------------------------------------------------------------------
static struct bucket *
host_search(const char *ipstr)
{
- struct addr46 ipaddr;
- struct sockaddr_storage ss;
+ struct addr a;
struct addrinfo hints, *ai;
memset(&hints, 0, sizeof(hints));
if (getaddrinfo(ipstr, NULL, &hints, &ai))
return (NULL); /* invalid 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);
+ if (ai->ai_family == AF_INET) {
+ a.family = IPv4;
+ a.ip.v4 = ((const struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
+ }
+ else if (ai->ai_family == AF_INET6) {
+ a.family = IPv6;
+ memcpy(&(a.ip.v6),
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
+ sizeof(a.ip.v6));
+ } else {
+ freeaddrinfo(ai);
+ return (NULL); /* unknown family */
}
+ freeaddrinfo(ai);
- return (hashtable_search(hosts_db, &ipaddr));
+ verbosef("search(%s) turned into %s", ipstr, addr_to_str(&a));
+ return (hashtable_search(hosts_db, &a));
}
/* ---------------------------------------------------------------------------
struct bucket *h;
struct str *buf, *ls_len;
char ls_when[100];
+ const char *canonical;
time_t ls;
h = host_search(ip);
if (h == NULL)
return (NULL); /* no such host */
+ canonical = addr_to_str(&(h->u.host.addr));
+
/* Overview. */
buf = str_make();
str_append(buf, html_header_1);
str_appendf(buf, " <title>%s</title>\n", ip);
str_append(buf, html_header_2);
+ str_appendf(buf, "<h2>%s</h2>\n", ip);
+ if (strcmp(ip, canonical) != 0)
+ str_appendf(buf, "(canonically <b>%s</b>)\n", canonical);
str_appendf(buf,
- "<h2>%s</h2>\n"
"<p>\n"
"<b>Hostname:</b> %s<br/>\n",
- ip,
(h->u.host.dns == NULL)?"(resolving...)":h->u.host.dns);
/* Resolve host "on demand" */
if (h->u.host.dns == NULL)
- dns_queue(&h->u.host.ipaddr);
+ dns_queue(&(h->u.host.addr));
if (show_mac_addrs)
- str_appendf(buf,
- "<b>MAC Address:</b> "
- "<tt>%x:%x:%x:%x:%x:%x</tt><br/>\n",
- h->u.host.mac_addr[0],
- h->u.host.mac_addr[1],
- h->u.host.mac_addr[2],
- h->u.host.mac_addr[3],
- h->u.host.mac_addr[4],
- h->u.host.mac_addr[5]);
+ str_appendf(buf,
+ "<b>MAC Address:</b> "
+ "<tt>%x:%x:%x:%x:%x:%x</tt><br/>\n",
+ h->u.host.mac_addr[0],
+ h->u.host.mac_addr[1],
+ h->u.host.mac_addr[2],
+ h->u.host.mac_addr[3],
+ h->u.host.mac_addr[4],
+ h->u.host.mac_addr[5]);
str_append(buf,
"</p>\n"
hosts_db_import_host(const int fd)
{
struct bucket *host;
- struct addr46 ipaddr;
+ struct addr a;
uint8_t hostname_len;
uint64_t in, out;
unsigned int pos = xtell(fd);
return 0;
}
- 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 (!readaddr(fd, &a)) return 0;
+ verbosef("at file pos %u, importing host %s", pos, addr_to_str(&a));
+ host = host_get(&a);
+ assert(addr_equal(&(host->u.host.addr), &a));
if (ver > 1) {
uint64_t t;
if (!writen(fd, export_tag_host_ver2, sizeof(export_tag_host_ver2)))
return 0;
- if (!writeaddr(fd, &b->u.host.ipaddr)) return 0;
+ if (!writeaddr(fd, &(b->u.host.addr))) return 0;
if (!write64(fd, (uint64_t)(b->u.host.last_seen))) return 0;
#ifndef __DARKSTAT_HOSTS_DB_H
#define __DARKSTAT_HOSTS_DB_H
-#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;
-};
+#include "addr.h"
struct hashtable;
struct host {
- struct addr46 ipaddr;
+ struct addr addr;
char *dns;
uint8_t mac_addr[6];
time_t last_seen;
int hosts_db_import(const int fd);
int hosts_db_export(const int fd);
-struct bucket *host_find(const struct addr46 *const ip); /* can return NULL */
-struct bucket *host_get(const struct addr46 *const ip);
+struct bucket *host_find(const struct addr *const a); /* can return NULL */
+struct bucket *host_get(const struct addr *const a);
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);
*/
#include "darkstat.h"
+#include "addr.h"
#include "conv.h" /* for strlcpy */
-#include "decode.h" /* for ip_to_str */
#include "err.h"
#include "localip.h"
#include <unistd.h>
static const char *iface = NULL;
-
-struct in_addr localip = { 0 };
-static struct in_addr last_localip = { 0 };
-
-struct in6_addr localip6;
-static struct in6_addr last_localip6;
+struct addr localip4, localip6;
+static struct addr last_localip4, last_localip6;
void
localip_init(const char *interface)
localip_update(void)
{
struct ifaddrs *ifas, *ifa;
- int flags = 0;
+ int got_v4 = 0, got_v6 = 0;
-#define HAS_IPV4 0x01
-#define HAS_IPV6 0x02
+ localip4.family = IPv4;
+ localip6.family = IPv6;
if (iface == NULL) {
/* reading from capfile */
- memset(&localip, 0, sizeof(localip));
- memset(&localip6, 0, sizeof(localip6));
+ localip4.ip.v4 = 0;
+ memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6));
return;
}
err(1, "can't get own IP address on interface \"%s\"", iface);
for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
- if (flags == (HAS_IPV4 | HAS_IPV6))
+ if (got_v4 && got_v6)
break; /* Task is already complete. */
if (strncmp(ifa->ifa_name, iface, IFNAMSIZ))
continue; /* Wrong interface. */
/* The first IPv4 name is always functional. */
- if ( (ifa->ifa_addr->sa_family == AF_INET)
- && ! (flags & HAS_IPV4) ) {
+ if ((ifa->ifa_addr->sa_family == AF_INET) && !got_v4)
+ {
/* Good IPv4 address. */
- localip.s_addr = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr;
- flags |= HAS_IPV4;
+ localip4.ip.v4 =
+ ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
+ got_v4 = 1;
continue;
}
if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))
|| IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) )
continue;
- else
- /* Only standard IPv6 can reach this point. */
- memcpy(&localip6, &sa6->sin6_addr, sizeof(localip6));
- flags |= HAS_IPV6;
+
+ /* Only standard IPv6 can reach this point. */
+ memcpy(&(localip6.ip.v6), &sa6->sin6_addr, sizeof(localip6.ip.v6));
+ got_v6 = 1;
}
}
freeifaddrs(ifas);
- /* Repport an error if IPv4 address could not be found. */
- if ( !(flags & HAS_IPV4) )
+ /* Report an error if IPv4 address could not be found. */
+ if (!got_v4)
err(1, "can't get own IPv4 address on interface \"%s\"", iface);
- /* struct sockaddr {
- * sa_family_t sa_family; * address family, AF_xxx
- * char sa_data[14]; * 14 bytes of protocol address
- *
- * struct sockaddr_in {
- * sa_family_t sin_family; * Address family
- * unsigned short int sin_port; * Port number
- * struct in_addr sin_addr; * Internet address
- *
- * struct in_addr {
- * __u32 s_addr;
- */
-
- 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 (!addr_equal(&last_localip4, &localip4)) {
+ verbosef("localip4 update(%s) = %s", iface, addr_to_str(&localip4));
+ last_localip4 = localip4;
}
- if (memcmp(&last_localip6, &localip6, sizeof(localip6))) {
- verbosef("local_ip6 update(%s) = %s", iface,
- ip_to_str_af(&localip6, AF_INET6));
- memcpy(&last_localip6, &localip6, sizeof(localip6));
+ if (!addr_equal(&last_localip6, &localip6)) {
+ verbosef("localip6 update(%s) = %s", iface, addr_to_str(&localip6));
+ last_localip6 = localip6;
}
}
* GNU General Public License version 2. (see COPYING.GPL)
*/
-#include <netinet/in.h> /* for in_addr, in6_addr */
-
-extern struct in_addr localip;
-extern struct in6_addr localip6;
+extern struct addr localip4, localip6;
void localip_init(const char *interface);
void localip_update(void);