/*
* collectd - src/utils_dns.c
* Copyright (C) 2006 Florian octo Forster
* Copyright (C) 2002 The Measurement Factory, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of The Measurement Factory nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* The Measurement Factory, Inc.
* Florian octo Forster
*/
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#include "collectd.h"
#include "plugin.h"
#include "utils/common/common.h"
#if HAVE_NET_IF_ARP_H
#include
#endif
#if HAVE_NET_IF_H
#include
#endif
#if HAVE_NET_PPP_DEFS_H
#include
#endif
#if HAVE_NET_IF_PPP_H
#include
#endif
#if HAVE_NETINET_IN_SYSTM_H
#include
#endif
#if HAVE_NETINET_IN_H
#include
#endif
#if HAVE_NETINET_IP6_H
#include
#endif
#if HAVE_NETINET_IF_ETHER_H
#include
#endif
#if HAVE_NETINET_IP_H
#include
#endif
#ifdef HAVE_NETINET_IP_VAR_H
#include
#endif
#if HAVE_NETINET_UDP_H
#include
#endif
#if HAVE_ARPA_INET_H
#include
#endif
#if HAVE_NETDB_H
#include
#endif
#if HAVE_PCAP_H
#include
#endif
#define PCAP_SNAPLEN 1460
#ifndef ETHER_HDR_LEN
#define ETHER_ADDR_LEN 6
#define ETHER_TYPE_LEN 2
#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
#endif
#ifndef ETHERTYPE_8021Q
#define ETHERTYPE_8021Q 0x8100
#endif
#ifndef ETHERTYPE_IPV6
#define ETHERTYPE_IPV6 0x86DD
#endif
#ifndef PPP_ADDRESS_VAL
#define PPP_ADDRESS_VAL 0xff /* The address byte value */
#endif
#ifndef PPP_CONTROL_VAL
#define PPP_CONTROL_VAL 0x03 /* The control byte value */
#endif
#if HAVE_STRUCT_UDPHDR_UH_DPORT && HAVE_STRUCT_UDPHDR_UH_SPORT
#define UDP_DEST uh_dport
#define UDP_SRC uh_sport
#elif HAVE_STRUCT_UDPHDR_DEST && HAVE_STRUCT_UDPHDR_SOURCE
#define UDP_DEST dest
#define UDP_SRC source
#else
#error "`struct udphdr' is unusable."
#endif
#if HAVE_NETINET_IP6_H && HAVE_STRUCT_IP6_EXT
#define HAVE_IPV6 1
#endif
#include "utils/dns/dns.h"
/*
* Type definitions
*/
struct ip_list_s {
struct in6_addr addr;
void *data;
struct ip_list_s *next;
};
typedef struct ip_list_s ip_list_t;
typedef int(printer)(const char *, ...);
/*
* flags/features for non-interactive mode
*/
#ifndef T_A6
#define T_A6 38
#endif
#ifndef T_SRV
#define T_SRV 33
#endif
/*
* Global variables
*/
#if HAVE_PCAP_H
static pcap_t *pcap_obj;
#endif
static ip_list_t *IgnoreList;
#if HAVE_PCAP_H
static void (*Callback)(const rfc1035_header_t *);
static int query_count_intvl;
static int query_count_total;
#ifdef __OpenBSD__
static struct bpf_timeval last_ts;
#else
static struct timeval last_ts;
#endif /* __OpenBSD__ */
#endif /* HAVE_PCAP_H */
static int cmp_in6_addr(const struct in6_addr *a, const struct in6_addr *b) {
int i;
assert(sizeof(struct in6_addr) == 16);
for (i = 0; i < 16; i++)
if (a->s6_addr[i] != b->s6_addr[i])
break;
if (i >= 16)
return 0;
return a->s6_addr[i] > b->s6_addr[i] ? 1 : -1;
} /* int cmp_addrinfo */
static inline int ignore_list_match(const struct in6_addr *addr) {
for (ip_list_t *ptr = IgnoreList; ptr != NULL; ptr = ptr->next)
if (cmp_in6_addr(addr, &ptr->addr) == 0)
return 1;
return 0;
} /* int ignore_list_match */
static void ignore_list_add(const struct in6_addr *addr) {
ip_list_t *new;
if (ignore_list_match(addr) != 0)
return;
new = malloc(sizeof(*new));
if (new == NULL) {
perror("malloc");
return;
}
memcpy(&new->addr, addr, sizeof(struct in6_addr));
new->next = IgnoreList;
IgnoreList = new;
} /* void ignore_list_add */
void ignore_list_add_name(const char *name) {
struct addrinfo *ai_list;
struct in6_addr addr;
int status;
status = getaddrinfo(name, NULL, NULL, &ai_list);
if (status != 0)
return;
for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
ai_ptr = ai_ptr->ai_next) {
if (ai_ptr->ai_family == AF_INET) {
memset(&addr, '\0', sizeof(addr));
addr.s6_addr[10] = 0xFF;
addr.s6_addr[11] = 0xFF;
memcpy(addr.s6_addr + 12,
&((struct sockaddr_in *)ai_ptr->ai_addr)->sin_addr, 4);
ignore_list_add(&addr);
} else {
ignore_list_add(&((struct sockaddr_in6 *)ai_ptr->ai_addr)->sin6_addr);
}
} /* for */
freeaddrinfo(ai_list);
}
#if HAVE_PCAP_H
static void in6_addr_from_buffer(struct in6_addr *ia, const void *buf,
size_t buf_len, int family) {
memset(ia, 0, sizeof(struct in6_addr));
if ((AF_INET == family) && (sizeof(uint32_t) == buf_len)) {
ia->s6_addr[10] = 0xFF;
ia->s6_addr[11] = 0xFF;
memcpy(ia->s6_addr + 12, buf, buf_len);
} else if ((AF_INET6 == family) && (sizeof(struct in6_addr) == buf_len)) {
memcpy(ia, buf, buf_len);
}
} /* void in6_addr_from_buffer */
void dnstop_set_pcap_obj(pcap_t *po) { pcap_obj = po; }
void dnstop_set_callback(void (*cb)(const rfc1035_header_t *)) {
Callback = cb;
}
#define RFC1035_MAXLABELSZ 63
static int rfc1035NameUnpack(const char *buf, size_t sz, off_t *off, char *name,
size_t ns) {
off_t no = 0;
unsigned char c;
size_t len;
static int loop_detect;
if (loop_detect > 2)
return 4; /* compression loop */
if (ns == 0)
return 4; /* probably compression loop */
do {
if ((*off) >= ((off_t)sz))
break;
c = *(buf + (*off));
if (c > 191) {
/* blasted compression */
int rc;
unsigned short s;
off_t ptr;
memcpy(&s, buf + (*off), sizeof(s));
s = ntohs(s);
(*off) += sizeof(s);
/* Sanity check */
if ((*off) >= ((off_t)sz))
return 1; /* message too short */
ptr = s & 0x3FFF;
/* Make sure the pointer is inside this message */
if (ptr >= ((off_t)sz))
return 2; /* bad compression ptr */
if (ptr < DNS_MSG_HDR_SZ)
return 2; /* bad compression ptr */
loop_detect++;
rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
loop_detect--;
return rc;
} else if (c > RFC1035_MAXLABELSZ) {
/*
* "(The 10 and 01 combinations are reserved for future use.)"
*/
return 3; /* reserved label/compression flags */
} else {
(*off)++;
len = (size_t)c;
if (len == 0)
break;
if (len > (ns - 1))
len = ns - 1;
if ((*off) + len > sz)
return 4; /* message is too short */
if (no + len + 1 > ns)
return 5; /* qname would overflow name buffer */
memcpy(name + no, buf + (*off), len);
(*off) += len;
no += len;
*(name + (no++)) = '.';
}
} while (c > 0);
if (no > 0)
*(name + no - 1) = '\0';
/* make sure we didn't allow someone to overflow the name buffer */
assert(no <= ((off_t)ns));
return 0;
}
static int handle_dns(const char *buf, int len) {
rfc1035_header_t qh;
uint16_t us;
off_t offset;
char *t;
int status;
/* The DNS header is 12 bytes long */
if (len < DNS_MSG_HDR_SZ)
return 0;
memcpy(&us, buf + 0, 2);
qh.id = ntohs(us);
memcpy(&us, buf + 2, 2);
us = ntohs(us);
qh.qr = (us >> 15) & 0x01;
qh.opcode = (us >> 11) & 0x0F;
qh.aa = (us >> 10) & 0x01;
qh.tc = (us >> 9) & 0x01;
qh.rd = (us >> 8) & 0x01;
qh.ra = (us >> 7) & 0x01;
qh.z = (us >> 6) & 0x01;
qh.ad = (us >> 5) & 0x01;
qh.cd = (us >> 4) & 0x01;
qh.rcode = us & 0x0F;
memcpy(&us, buf + 4, 2);
qh.qdcount = ntohs(us);
memcpy(&us, buf + 6, 2);
qh.ancount = ntohs(us);
memcpy(&us, buf + 8, 2);
qh.nscount = ntohs(us);
memcpy(&us, buf + 10, 2);
qh.arcount = ntohs(us);
offset = DNS_MSG_HDR_SZ;
memset(qh.qname, '\0', MAX_QNAME_SZ);
status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
if (status != 0) {
INFO("utils_dns: handle_dns: rfc1035NameUnpack failed "
"with status %i.",
status);
return 0;
}
if ('\0' == qh.qname[0])
sstrncpy(qh.qname, ".", sizeof(qh.qname));
while ((t = strchr(qh.qname, '\n')))
*t = ' ';
while ((t = strchr(qh.qname, '\r')))
*t = ' ';
for (t = qh.qname; *t; t++)
*t = tolower((int)*t);
memcpy(&us, buf + offset, 2);
qh.qtype = ntohs(us);
memcpy(&us, buf + offset + 2, 2);
qh.qclass = ntohs(us);
qh.length = (uint16_t)len;
if (Callback != NULL)
Callback(&qh);
return 1;
}
static int handle_udp(const struct udphdr *udp, int len) {
char buf[PCAP_SNAPLEN];
if ((ntohs(udp->UDP_DEST) != 53) && (ntohs(udp->UDP_SRC) != 53))
return 0;
memcpy(buf, udp + 1, len - sizeof(*udp));
if (0 == handle_dns(buf, len - sizeof(*udp)))
return 0;
return 1;
}
#if HAVE_IPV6
static int handle_ipv6(struct ip6_hdr *ipv6, int len) {
char buf[PCAP_SNAPLEN];
unsigned int offset;
int nexthdr;
struct in6_addr c_src_addr;
uint16_t payload_len;
if (0 > len)
return 0;
offset = sizeof(struct ip6_hdr);
nexthdr = ipv6->ip6_nxt;
c_src_addr = ipv6->ip6_src;
payload_len = ntohs(ipv6->ip6_plen);
if (ignore_list_match(&c_src_addr))
return 0;
/* Parse extension headers. This only handles the standard headers, as
* defined in RFC 2460, correctly. Fragments are discarded. */
while ((IPPROTO_ROUTING == nexthdr) /* routing header */
|| (IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */
|| (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
|| (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
|| (IPPROTO_AH == nexthdr) /* destination options. */
|| (IPPROTO_ESP == nexthdr)) /* encapsulating security payload. */
{
struct ip6_ext ext_hdr;
uint16_t ext_hdr_len;
/* Catch broken packets */
if ((offset + sizeof(struct ip6_ext)) > (unsigned int)len)
return 0;
/* Cannot handle fragments. */
if (IPPROTO_FRAGMENT == nexthdr)
return 0;
memcpy(&ext_hdr, (char *)ipv6 + offset, sizeof(struct ip6_ext));
nexthdr = ext_hdr.ip6e_nxt;
ext_hdr_len = (8 * (ntohs(ext_hdr.ip6e_len) + 1));
/* This header is longer than the packets payload.. WTF? */
if (ext_hdr_len > payload_len)
return 0;
offset += ext_hdr_len;
payload_len -= ext_hdr_len;
} /* while */
/* Catch broken and empty packets */
if (((offset + payload_len) > (unsigned int)len) || (payload_len == 0) ||
(payload_len > PCAP_SNAPLEN))
return 0;
if (IPPROTO_UDP != nexthdr)
return 0;
memcpy(buf, (char *)ipv6 + offset, payload_len);
if (handle_udp((struct udphdr *)buf, payload_len) == 0)
return 0;
return 1; /* Success */
} /* int handle_ipv6 */
/* #endif HAVE_IPV6 */
#else /* if !HAVE_IPV6 */
static int handle_ipv6(__attribute__((unused)) void *pkg,
__attribute__((unused)) int len) {
return 0;
}
#endif /* !HAVE_IPV6 */
static int handle_ip(const struct ip *ip, int len) {
char buf[PCAP_SNAPLEN];
int offset = ip->ip_hl << 2;
struct in6_addr c_src_addr;
struct in6_addr c_dst_addr;
if (ip->ip_v == 6)
return handle_ipv6((void *)ip, len);
in6_addr_from_buffer(&c_src_addr, &ip->ip_src.s_addr,
sizeof(ip->ip_src.s_addr), AF_INET);
in6_addr_from_buffer(&c_dst_addr, &ip->ip_dst.s_addr,
sizeof(ip->ip_dst.s_addr), AF_INET);
if (ignore_list_match(&c_src_addr))
return 0;
if (IPPROTO_UDP != ip->ip_p)
return 0;
memcpy(buf, ((char *)ip) + offset, len - offset);
if (0 == handle_udp((struct udphdr *)buf, len - offset))
return 0;
return 1;
}
#if HAVE_NET_IF_PPP_H
static int handle_ppp(const u_char *pkt, int len) {
char buf[PCAP_SNAPLEN];
unsigned short us;
unsigned short proto;
if (len < 2)
return 0;
if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) {
pkt += 2; /* ACFC not used */
len -= 2;
}
if (len < 2)
return 0;
if (*pkt % 2) {
proto = *pkt; /* PFC is used */
pkt++;
len--;
} else {
memcpy(&us, pkt, sizeof(us));
proto = ntohs(us);
pkt += 2;
len -= 2;
}
if (ETHERTYPE_IP != proto && PPP_IP != proto)
return 0;
memcpy(buf, pkt, len);
return handle_ip((struct ip *)buf, len);
}
#endif /* HAVE_NET_IF_PPP_H */
static int handle_null(const u_char *pkt, int len) {
unsigned int family;
memcpy(&family, pkt, sizeof(family));
if (AF_INET != family)
return 0;
return handle_ip((struct ip *)(pkt + 4), len - 4);
}
#ifdef DLT_LOOP
static int handle_loop(const u_char *pkt, int len) {
unsigned int family;
memcpy(&family, pkt, sizeof(family));
if (AF_INET != ntohl(family))
return 0;
return handle_ip((struct ip *)(pkt + 4), len - 4);
}
#endif
#ifdef DLT_RAW
static int handle_raw(const u_char *pkt, int len) {
return handle_ip((struct ip *)pkt, len);
}
#endif
static int handle_ether(const u_char *pkt, int len) {
char buf[PCAP_SNAPLEN];
struct ether_header *e = (void *)pkt;
unsigned short etype = ntohs(e->ether_type);
if (len < ETHER_HDR_LEN)
return 0;
pkt += ETHER_HDR_LEN;
len -= ETHER_HDR_LEN;
if (ETHERTYPE_8021Q == etype) {
etype = ntohs(*(unsigned short *)(pkt + 2));
pkt += 4;
len -= 4;
}
if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
return 0;
memcpy(buf, pkt, len);
if (ETHERTYPE_IPV6 == etype)
return handle_ipv6((void *)buf, len);
else
return handle_ip((struct ip *)buf, len);
}
#ifdef DLT_LINUX_SLL
static int handle_linux_sll(const u_char *pkt, int len) {
struct sll_header {
uint16_t pkt_type;
uint16_t dev_type;
uint16_t addr_len;
uint8_t addr[8];
uint16_t proto_type;
} * hdr;
uint16_t etype;
if ((0 > len) || ((unsigned int)len < sizeof(struct sll_header)))
return 0;
hdr = (struct sll_header *)pkt;
pkt = (u_char *)(hdr + 1);
len -= sizeof(struct sll_header);
etype = ntohs(hdr->proto_type);
if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
return 0;
if (ETHERTYPE_IPV6 == etype)
return handle_ipv6((void *)pkt, len);
else
return handle_ip((struct ip *)pkt, len);
}
#endif /* DLT_LINUX_SLL */
/* public function */
void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr,
const u_char *pkt) {
int status;
if (hdr->caplen < ETHER_HDR_LEN)
return;
switch (pcap_datalink(pcap_obj)) {
case DLT_EN10MB:
status = handle_ether(pkt, hdr->caplen);
break;
#if HAVE_NET_IF_PPP_H
case DLT_PPP:
status = handle_ppp(pkt, hdr->caplen);
break;
#endif
#ifdef DLT_LOOP
case DLT_LOOP:
status = handle_loop(pkt, hdr->caplen);
break;
#endif
#ifdef DLT_RAW
case DLT_RAW:
status = handle_raw(pkt, hdr->caplen);
break;
#endif
#ifdef DLT_LINUX_SLL
case DLT_LINUX_SLL:
status = handle_linux_sll(pkt, hdr->caplen);
break;
#endif
case DLT_NULL:
status = handle_null(pkt, hdr->caplen);
break;
default:
ERROR("handle_pcap: unsupported data link type %d",
pcap_datalink(pcap_obj));
status = 0;
break;
} /* switch (pcap_datalink(pcap_obj)) */
if (0 == status)
return;
query_count_intvl++;
query_count_total++;
last_ts = hdr->ts;
}
#endif /* HAVE_PCAP_H */
const char *qtype_str(int t) {
static char buf[32];
// clang-format off
/*
Built (with minor cleanup) from glibc-2.29 by
cat resolv/arpa/nameser.h | grep "ns_t_" | \
perl -ne '/ns_t_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
*/
// clang-format on
switch (t) {
case 1:
return "A";
case 2:
return "NS";
case 3:
return "MD";
case 4:
return "MF";
case 5:
return "CNAME";
case 6:
return "SOA";
case 7:
return "MB";
case 8:
return "MG";
case 9:
return "MR";
case 10:
return "NULL";
case 11:
return "WKS";
case 12:
return "PTR";
case 13:
return "HINFO";
case 14:
return "MINFO";
case 15:
return "MX";
case 16:
return "TXT";
case 17:
return "RP";
case 18:
return "AFSDB";
case 19:
return "X25";
case 20:
return "ISDN";
case 21:
return "RT";
case 22:
return "NSAP";
case 23:
return "NSAP-PTR";
case 24:
return "SIG";
case 25:
return "KEY";
case 26:
return "PX";
case 27:
return "GPOS";
case 28:
return "AAAA";
case 29:
return "LOC";
case 30:
return "NXT";
case 31:
return "EID";
case 32:
return "NIMLOC";
case 33:
return "SRV";
case 34:
return "ATMA";
case 35:
return "NAPTR";
case 36:
return "KX";
case 37:
return "CERT";
case 38:
return "A6";
case 39:
return "DNAME";
case 40:
return "SINK";
case 41:
return "OPT";
case 42:
return "APL";
case 43:
return "DS";
case 44:
return "SSHFP";
case 45:
return "IPSECKEY";
case 46:
return "RRSIG";
case 47:
return "NSEC";
case 48:
return "DNSKEY";
case 49:
return "DHCID";
case 50:
return "NSEC3";
case 51:
return "NSEC3PARAM";
case 52:
return "TLSA";
case 53:
return "SMIMEA";
case 55:
return "HIP";
case 56:
return "NINFO";
case 57:
return "RKEY";
case 58:
return "TALINK";
case 59:
return "CDS";
case 60:
return "CDNSKEY";
case 61:
return "OPENPGPKEY";
case 62:
return "CSYNC";
case 99:
return "SPF";
case 100:
return "UINFO";
case 101:
return "UID";
case 102:
return "GID";
case 103:
return "UNSPEC";
case 104:
return "NID";
case 105:
return "L32";
case 106:
return "L64";
case 107:
return "LP";
case 108:
return "EUI48";
case 109:
return "EUI64";
case 249:
return "TKEY";
case 250:
return "TSIG";
case 251:
return "IXFR";
case 252:
return "AXFR";
case 253:
return "MAILB";
case 254:
return "MAILA";
case 255:
return "ANY";
case 256:
return "URI";
case 257:
return "CAA";
case 258:
return "AVC";
case 32768:
return "TA";
case 32769:
return "DLV";
default:
ssnprintf(buf, sizeof(buf), "#%i", t);
return buf;
} /* switch (t) */
}
const char *opcode_str(int o) {
static char buf[30];
switch (o) {
case 0:
return "Query";
case 1:
return "Iquery";
case 2:
return "Status";
case 4:
return "Notify";
case 5:
return "Update";
default:
ssnprintf(buf, sizeof(buf), "Opcode%d", o);
return buf;
}
}
const char *rcode_str(int rcode) {
static char buf[32];
/* RFC2136 rcodes */
// clang-format off
/*
Built (with minor cleanup) from glibc-2.29 by
cat resolv/arpa/nameser.h | grep "ns_r_" | \
perl -ne '/ns_r_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
https://tools.ietf.org/html/rfc2671 assigns EDNS Extended RCODE "16" to "BADVERS"
https://tools.ietf.org/html/rfc2845 declares 0..15 as DNS RCODE and 16 is BADSIG.
*/
// clang-format on
switch (rcode) {
case 1:
return "FORMERR";
case 2:
return "SERVFAIL";
case 3:
return "NXDOMAIN";
case 4:
return "NOTIMPL";
case 5:
return "REFUSED";
case 6:
return "YXDOMAIN";
case 7:
return "YXRRSET";
case 8:
return "NXRRSET";
case 9:
return "NOTAUTH";
case 10:
return "NOTZONE";
case 11:
return "MAX";
case 16:
return "BADSIG";
case 17:
return "BADKEY";
case 18:
return "BADTIME";
default:
ssnprintf(buf, sizeof(buf), "RCode%i", rcode);
return buf;
}
} /* const char *rcode_str (int rcode) */
#if 0
static int
main(int argc, char *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE];
int x;
struct stat sb;
int readfile_state = 0;
struct bpf_program fp;
port53 = htons(53);
SubReport = Sources_report;
ignore_addr.s_addr = 0;
progname = strdup(strrchr(argv[0], '/') ? strchr(argv[0], '/') + 1 : argv[0]);
srandom(time(NULL));
ResetCounters();
while ((x = getopt(argc, argv, "ab:f:i:pst")) != -1) {
switch (x) {
case 'a':
anon_flag = 1;
break;
case 's':
sld_flag = 1;
break;
case 't':
nld_flag = 1;
break;
case 'p':
promisc_flag = 0;
break;
case 'b':
bpf_program_str = strdup(optarg);
break;
case 'i':
ignore_addr.s_addr = inet_addr(optarg);
break;
case 'f':
set_filter(optarg);
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
device = strdup(argv[0]);
if (0 == stat(device, &sb))
readfile_state = 1;
if (readfile_state) {
pcap_obj = pcap_open_offline(device, errbuf);
} else {
pcap_obj = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1000, errbuf);
}
if (NULL == pcap_obj) {
fprintf(stderr, "pcap_open_*: %s\n", errbuf);
exit(1);
}
if (0 == isatty(1)) {
if (0 == readfile_state) {
fprintf(stderr, "Non-interactive mode requires savefile argument\n");
exit(1);
}
interactive = 0;
print_func = printf;
}
memset(&fp, '\0', sizeof(fp));
x = pcap_compile(pcap_obj, &fp, bpf_program_str, 1, 0);
if (x < 0) {
fprintf(stderr, "pcap_compile failed\n");
exit(1);
}
x = pcap_setfilter(pcap_obj, &fp);
if (x < 0) {
fprintf(stderr, "pcap_setfilter failed\n");
exit(1);
}
/*
* non-blocking call added for Mac OS X bugfix. Sent by Max Horn.
* ref http://www.tcpdump.org/lists/workers/2002/09/msg00033.html
*/
x = pcap_setnonblock(pcap_obj, 1, errbuf);
if (x < 0) {
fprintf(stderr, "pcap_setnonblock failed: %s\n", errbuf);
exit(1);
}
switch (pcap_datalink(pcap_obj)) {
case DLT_EN10MB:
handle_datalink = handle_ether;
break;
#if HAVE_NET_IF_PPP_H
case DLT_PPP:
handle_datalink = handle_ppp;
break;
#endif
#ifdef DLT_LOOP
case DLT_LOOP:
handle_datalink = handle_loop;
break;
#endif
#ifdef DLT_RAW
case DLT_RAW:
handle_datalink = handle_raw;
break;
#endif
case DLT_NULL:
handle_datalink = handle_null;
break;
default:
fprintf(stderr, "unsupported data link type %d\n",
pcap_datalink(pcap_obj));
return 1;
break;
}
if (interactive) {
init_curses();
while (0 == Quit) {
if (readfile_state < 2) {
/*
* On some OSes select() might return 0 even when
* there are packets to process. Thus, we always
* ignore its return value and just call pcap_dispatch()
* anyway.
*/
if (0 == readfile_state) /* interactive */
pcap_select(pcap_obj, 1, 0);
x = pcap_dispatch(pcap_obj, 50, handle_pcap, NULL);
}
if (0 == x && 1 == readfile_state) {
/* block on keyboard until user quits */
readfile_state++;
nodelay(w, 0);
}
keyboard();
cron_pre();
report();
cron_post();
}
endwin(); /* klin, Thu Nov 28 08:56:51 2002 */
} else {
while (pcap_dispatch(pcap_obj, 50, handle_pcap, NULL))
(void) 0;
cron_pre();
Sources_report(); print_func("\n");
Destinatioreport(); print_func("\n");
Qtypes_report(); print_func("\n");
Opcodes_report(); print_func("\n");
Tld_report(); print_func("\n");
Sld_report(); print_func("\n");
Nld_report(); print_func("\n");
SldBySource_report();
}
pcap_close(pcap_obj);
return 0;
} /* static int main(int argc, char *argv[]) */
#endif