/* * 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