2 * collectd - src/utils_dns.c
3 * Copyright (C) 2006 Florian octo Forster
4 * Copyright (C) 2002 The Measurement Factory, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither the name of The Measurement Factory nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 * The Measurement Factory, Inc. <http://www.measurement-factory.com/>
33 * Florian octo Forster <octo at collectd.org>
36 #define _DEFAULT_SOURCE
42 #include "utils/common/common.h"
45 #include <net/if_arp.h>
50 #if HAVE_NET_PPP_DEFS_H
51 #include <net/ppp_defs.h>
54 #include <net/if_ppp.h>
57 #if HAVE_NETINET_IN_SYSTM_H
58 #include <netinet/in_systm.h>
61 #include <netinet/in.h>
63 #if HAVE_NETINET_IP6_H
64 #include <netinet/ip6.h>
66 #if HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
70 #include <netinet/ip.h>
72 #ifdef HAVE_NETINET_IP_VAR_H
73 #include <netinet/ip_var.h>
75 #if HAVE_NETINET_UDP_H
76 #include <netinet/udp.h>
80 #include <arpa/inet.h>
91 #define PCAP_SNAPLEN 1460
93 #define ETHER_ADDR_LEN 6
94 #define ETHER_TYPE_LEN 2
95 #define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
97 #ifndef ETHERTYPE_8021Q
98 #define ETHERTYPE_8021Q 0x8100
100 #ifndef ETHERTYPE_IPV6
101 #define ETHERTYPE_IPV6 0x86DD
104 #ifndef PPP_ADDRESS_VAL
105 #define PPP_ADDRESS_VAL 0xff /* The address byte value */
107 #ifndef PPP_CONTROL_VAL
108 #define PPP_CONTROL_VAL 0x03 /* The control byte value */
111 #if HAVE_STRUCT_UDPHDR_UH_DPORT && HAVE_STRUCT_UDPHDR_UH_SPORT
112 #define UDP_DEST uh_dport
113 #define UDP_SRC uh_sport
114 #elif HAVE_STRUCT_UDPHDR_DEST && HAVE_STRUCT_UDPHDR_SOURCE
115 #define UDP_DEST dest
116 #define UDP_SRC source
118 #error "`struct udphdr' is unusable."
121 #if HAVE_NETINET_IP6_H && HAVE_STRUCT_IP6_EXT
125 #include "utils/dns/dns.h"
131 struct in6_addr addr;
133 struct ip_list_s *next;
135 typedef struct ip_list_s ip_list_t;
137 typedef int(printer)(const char *, ...);
140 * flags/features for non-interactive mode
155 static pcap_t *pcap_obj;
158 static ip_list_t *IgnoreList;
161 static void (*Callback)(const rfc1035_header_t *);
163 static int query_count_intvl;
164 static int query_count_total;
166 static struct bpf_timeval last_ts;
168 static struct timeval last_ts;
169 #endif /* __OpenBSD__ */
170 #endif /* HAVE_PCAP_H */
172 static int cmp_in6_addr(const struct in6_addr *a, const struct in6_addr *b) {
175 assert(sizeof(struct in6_addr) == 16);
177 for (i = 0; i < 16; i++)
178 if (a->s6_addr[i] != b->s6_addr[i])
184 return a->s6_addr[i] > b->s6_addr[i] ? 1 : -1;
185 } /* int cmp_addrinfo */
187 static inline int ignore_list_match(const struct in6_addr *addr) {
188 for (ip_list_t *ptr = IgnoreList; ptr != NULL; ptr = ptr->next)
189 if (cmp_in6_addr(addr, &ptr->addr) == 0)
192 } /* int ignore_list_match */
194 static void ignore_list_add(const struct in6_addr *addr) {
197 if (ignore_list_match(addr) != 0)
200 new = malloc(sizeof(*new));
206 memcpy(&new->addr, addr, sizeof(struct in6_addr));
207 new->next = IgnoreList;
210 } /* void ignore_list_add */
212 void ignore_list_add_name(const char *name) {
213 struct addrinfo *ai_list;
214 struct in6_addr addr;
217 status = getaddrinfo(name, NULL, NULL, &ai_list);
221 for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
222 ai_ptr = ai_ptr->ai_next) {
223 if (ai_ptr->ai_family == AF_INET) {
224 memset(&addr, '\0', sizeof(addr));
225 addr.s6_addr[10] = 0xFF;
226 addr.s6_addr[11] = 0xFF;
227 memcpy(addr.s6_addr + 12,
228 &((struct sockaddr_in *)ai_ptr->ai_addr)->sin_addr, 4);
230 ignore_list_add(&addr);
232 ignore_list_add(&((struct sockaddr_in6 *)ai_ptr->ai_addr)->sin6_addr);
236 freeaddrinfo(ai_list);
240 static void in6_addr_from_buffer(struct in6_addr *ia, const void *buf,
241 size_t buf_len, int family) {
242 memset(ia, 0, sizeof(struct in6_addr));
243 if ((AF_INET == family) && (sizeof(uint32_t) == buf_len)) {
244 ia->s6_addr[10] = 0xFF;
245 ia->s6_addr[11] = 0xFF;
246 memcpy(ia->s6_addr + 12, buf, buf_len);
247 } else if ((AF_INET6 == family) && (sizeof(struct in6_addr) == buf_len)) {
248 memcpy(ia, buf, buf_len);
250 } /* void in6_addr_from_buffer */
252 void dnstop_set_pcap_obj(pcap_t *po) { pcap_obj = po; }
254 void dnstop_set_callback(void (*cb)(const rfc1035_header_t *)) {
258 #define RFC1035_MAXLABELSZ 63
259 static int rfc1035NameUnpack(const char *buf, size_t sz, off_t *off, char *name,
264 static int loop_detect;
266 return 4; /* compression loop */
268 return 4; /* probably compression loop */
270 if ((*off) >= ((off_t)sz))
274 /* blasted compression */
278 memcpy(&s, buf + (*off), sizeof(s));
282 if ((*off) >= ((off_t)sz))
283 return 1; /* message too short */
285 /* Make sure the pointer is inside this message */
286 if (ptr >= ((off_t)sz))
287 return 2; /* bad compression ptr */
288 if (ptr < DNS_MSG_HDR_SZ)
289 return 2; /* bad compression ptr */
291 rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
294 } else if (c > RFC1035_MAXLABELSZ) {
296 * "(The 10 and 01 combinations are reserved for future use.)"
298 return 3; /* reserved label/compression flags */
306 if ((*off) + len > sz)
307 return 4; /* message is too short */
308 if (no + len + 1 > ns)
309 return 5; /* qname would overflow name buffer */
310 memcpy(name + no, buf + (*off), len);
313 *(name + (no++)) = '.';
317 *(name + no - 1) = '\0';
318 /* make sure we didn't allow someone to overflow the name buffer */
319 assert(no <= ((off_t)ns));
323 static int handle_dns(const char *buf, int len) {
330 /* The DNS header is 12 bytes long */
331 if (len < DNS_MSG_HDR_SZ)
334 memcpy(&us, buf + 0, 2);
337 memcpy(&us, buf + 2, 2);
339 qh.qr = (us >> 15) & 0x01;
340 qh.opcode = (us >> 11) & 0x0F;
341 qh.aa = (us >> 10) & 0x01;
342 qh.tc = (us >> 9) & 0x01;
343 qh.rd = (us >> 8) & 0x01;
344 qh.ra = (us >> 7) & 0x01;
345 qh.z = (us >> 6) & 0x01;
346 qh.ad = (us >> 5) & 0x01;
347 qh.cd = (us >> 4) & 0x01;
348 qh.rcode = us & 0x0F;
350 memcpy(&us, buf + 4, 2);
351 qh.qdcount = ntohs(us);
353 memcpy(&us, buf + 6, 2);
354 qh.ancount = ntohs(us);
356 memcpy(&us, buf + 8, 2);
357 qh.nscount = ntohs(us);
359 memcpy(&us, buf + 10, 2);
360 qh.arcount = ntohs(us);
362 offset = DNS_MSG_HDR_SZ;
363 memset(qh.qname, '\0', MAX_QNAME_SZ);
364 status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
366 INFO("utils_dns: handle_dns: rfc1035NameUnpack failed "
371 if ('\0' == qh.qname[0])
372 sstrncpy(qh.qname, ".", sizeof(qh.qname));
373 while ((t = strchr(qh.qname, '\n')))
375 while ((t = strchr(qh.qname, '\r')))
377 for (t = qh.qname; *t; t++)
378 *t = tolower((int)*t);
380 memcpy(&us, buf + offset, 2);
381 qh.qtype = ntohs(us);
382 memcpy(&us, buf + offset + 2, 2);
383 qh.qclass = ntohs(us);
385 qh.length = (uint16_t)len;
387 if (Callback != NULL)
393 static int handle_udp(const struct udphdr *udp, int len) {
394 char buf[PCAP_SNAPLEN];
395 if ((ntohs(udp->UDP_DEST) != 53) && (ntohs(udp->UDP_SRC) != 53))
397 memcpy(buf, udp + 1, len - sizeof(*udp));
398 if (0 == handle_dns(buf, len - sizeof(*udp)))
404 static int handle_ipv6(struct ip6_hdr *ipv6, int len) {
405 char buf[PCAP_SNAPLEN];
409 struct in6_addr c_src_addr;
410 uint16_t payload_len;
415 offset = sizeof(struct ip6_hdr);
416 nexthdr = ipv6->ip6_nxt;
417 c_src_addr = ipv6->ip6_src;
418 payload_len = ntohs(ipv6->ip6_plen);
420 if (ignore_list_match(&c_src_addr))
423 /* Parse extension headers. This only handles the standard headers, as
424 * defined in RFC 2460, correctly. Fragments are discarded. */
425 while ((IPPROTO_ROUTING == nexthdr) /* routing header */
426 || (IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */
427 || (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
428 || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
429 || (IPPROTO_AH == nexthdr) /* destination options. */
430 || (IPPROTO_ESP == nexthdr)) /* encapsulating security payload. */
432 struct ip6_ext ext_hdr;
433 uint16_t ext_hdr_len;
435 /* Catch broken packets */
436 if ((offset + sizeof(struct ip6_ext)) > (unsigned int)len)
439 /* Cannot handle fragments. */
440 if (IPPROTO_FRAGMENT == nexthdr)
443 memcpy(&ext_hdr, (char *)ipv6 + offset, sizeof(struct ip6_ext));
444 nexthdr = ext_hdr.ip6e_nxt;
445 ext_hdr_len = (8 * (ntohs(ext_hdr.ip6e_len) + 1));
447 /* This header is longer than the packets payload.. WTF? */
448 if (ext_hdr_len > payload_len)
451 offset += ext_hdr_len;
452 payload_len -= ext_hdr_len;
455 /* Catch broken and empty packets */
456 if (((offset + payload_len) > (unsigned int)len) || (payload_len == 0) ||
457 (payload_len > PCAP_SNAPLEN))
460 if (IPPROTO_UDP != nexthdr)
463 memcpy(buf, (char *)ipv6 + offset, payload_len);
464 if (handle_udp((struct udphdr *)buf, payload_len) == 0)
467 return 1; /* Success */
468 } /* int handle_ipv6 */
469 /* #endif HAVE_IPV6 */
471 #else /* if !HAVE_IPV6 */
472 static int handle_ipv6(__attribute__((unused)) void *pkg,
473 __attribute__((unused)) int len) {
476 #endif /* !HAVE_IPV6 */
478 static int handle_ip(const struct ip *ip, int len) {
479 char buf[PCAP_SNAPLEN];
480 int offset = ip->ip_hl << 2;
481 struct in6_addr c_src_addr;
482 struct in6_addr c_dst_addr;
485 return handle_ipv6((void *)ip, len);
487 in6_addr_from_buffer(&c_src_addr, &ip->ip_src.s_addr,
488 sizeof(ip->ip_src.s_addr), AF_INET);
489 in6_addr_from_buffer(&c_dst_addr, &ip->ip_dst.s_addr,
490 sizeof(ip->ip_dst.s_addr), AF_INET);
491 if (ignore_list_match(&c_src_addr))
493 if (IPPROTO_UDP != ip->ip_p)
495 memcpy(buf, ((char *)ip) + offset, len - offset);
496 if (0 == handle_udp((struct udphdr *)buf, len - offset))
501 #if HAVE_NET_IF_PPP_H
502 static int handle_ppp(const u_char *pkt, int len) {
503 char buf[PCAP_SNAPLEN];
505 unsigned short proto;
508 if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) {
509 pkt += 2; /* ACFC not used */
515 proto = *pkt; /* PFC is used */
519 memcpy(&us, pkt, sizeof(us));
524 if (ETHERTYPE_IP != proto && PPP_IP != proto)
526 memcpy(buf, pkt, len);
527 return handle_ip((struct ip *)buf, len);
529 #endif /* HAVE_NET_IF_PPP_H */
531 static int handle_null(const u_char *pkt, int len) {
533 memcpy(&family, pkt, sizeof(family));
534 if (AF_INET != family)
536 return handle_ip((struct ip *)(pkt + 4), len - 4);
540 static int handle_loop(const u_char *pkt, int len) {
542 memcpy(&family, pkt, sizeof(family));
543 if (AF_INET != ntohl(family))
545 return handle_ip((struct ip *)(pkt + 4), len - 4);
551 static int handle_raw(const u_char *pkt, int len) {
552 return handle_ip((struct ip *)pkt, len);
557 static int handle_ether(const u_char *pkt, int len) {
558 char buf[PCAP_SNAPLEN];
559 struct ether_header *e = (void *)pkt;
560 unsigned short etype = ntohs(e->ether_type);
561 if (len < ETHER_HDR_LEN)
563 pkt += ETHER_HDR_LEN;
564 len -= ETHER_HDR_LEN;
565 if (ETHERTYPE_8021Q == etype) {
566 etype = ntohs(*(unsigned short *)(pkt + 2));
570 if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
572 memcpy(buf, pkt, len);
573 if (ETHERTYPE_IPV6 == etype)
574 return handle_ipv6((void *)buf, len);
576 return handle_ip((struct ip *)buf, len);
580 static int handle_linux_sll(const u_char *pkt, int len) {
590 if ((0 > len) || ((unsigned int)len < sizeof(struct sll_header)))
593 hdr = (struct sll_header *)pkt;
594 pkt = (u_char *)(hdr + 1);
595 len -= sizeof(struct sll_header);
597 etype = ntohs(hdr->proto_type);
599 if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
602 if (ETHERTYPE_IPV6 == etype)
603 return handle_ipv6((void *)pkt, len);
605 return handle_ip((struct ip *)pkt, len);
607 #endif /* DLT_LINUX_SLL */
609 /* public function */
610 void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr,
614 if (hdr->caplen < ETHER_HDR_LEN)
617 switch (pcap_datalink(pcap_obj)) {
619 status = handle_ether(pkt, hdr->caplen);
621 #if HAVE_NET_IF_PPP_H
623 status = handle_ppp(pkt, hdr->caplen);
628 status = handle_loop(pkt, hdr->caplen);
633 status = handle_raw(pkt, hdr->caplen);
638 status = handle_linux_sll(pkt, hdr->caplen);
642 status = handle_null(pkt, hdr->caplen);
646 ERROR("handle_pcap: unsupported data link type %d",
647 pcap_datalink(pcap_obj));
650 } /* switch (pcap_datalink(pcap_obj)) */
659 #endif /* HAVE_PCAP_H */
661 const char *qtype_str(int t) {
665 Built (with minor cleanup) from glibc-2.29 by
666 cat resolv/arpa/nameser.h | grep "ns_t_" | \
667 perl -ne '/ns_t_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
840 ssnprintf(buf, sizeof(buf), "#%i", t);
845 const char *opcode_str(int o) {
859 ssnprintf(buf, sizeof(buf), "Opcode%d", o);
864 const char *rcode_str(int rcode) {
869 Built (with minor cleanup) from glibc-2.29 by
870 cat resolv/arpa/nameser.h | grep "ns_r_" | \
871 perl -ne '/ns_r_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
873 https://tools.ietf.org/html/rfc2671 assigns EDNS Extended RCODE "16" to "BADVERS"
874 https://tools.ietf.org/html/rfc2845 declares 0..15 as DNS RCODE and 16 is BADSIG.
907 ssnprintf(buf, sizeof(buf), "RCode%i", rcode);
910 } /* const char *rcode_str (int rcode) */
914 main(int argc, char *argv[])
916 char errbuf[PCAP_ERRBUF_SIZE];
919 int readfile_state = 0;
920 struct bpf_program fp;
923 SubReport = Sources_report;
924 ignore_addr.s_addr = 0;
925 progname = strdup(strrchr(argv[0], '/') ? strchr(argv[0], '/') + 1 : argv[0]);
929 while ((x = getopt(argc, argv, "ab:f:i:pst")) != -1) {
944 bpf_program_str = strdup(optarg);
947 ignore_addr.s_addr = inet_addr(optarg);
962 device = strdup(argv[0]);
964 if (0 == stat(device, &sb))
966 if (readfile_state) {
967 pcap_obj = pcap_open_offline(device, errbuf);
969 pcap_obj = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1000, errbuf);
971 if (NULL == pcap_obj) {
972 fprintf(stderr, "pcap_open_*: %s\n", errbuf);
976 if (0 == isatty(1)) {
977 if (0 == readfile_state) {
978 fprintf(stderr, "Non-interactive mode requires savefile argument\n");
985 memset(&fp, '\0', sizeof(fp));
986 x = pcap_compile(pcap_obj, &fp, bpf_program_str, 1, 0);
988 fprintf(stderr, "pcap_compile failed\n");
991 x = pcap_setfilter(pcap_obj, &fp);
993 fprintf(stderr, "pcap_setfilter failed\n");
998 * non-blocking call added for Mac OS X bugfix. Sent by Max Horn.
999 * ref http://www.tcpdump.org/lists/workers/2002/09/msg00033.html
1001 x = pcap_setnonblock(pcap_obj, 1, errbuf);
1003 fprintf(stderr, "pcap_setnonblock failed: %s\n", errbuf);
1007 switch (pcap_datalink(pcap_obj)) {
1009 handle_datalink = handle_ether;
1011 #if HAVE_NET_IF_PPP_H
1013 handle_datalink = handle_ppp;
1018 handle_datalink = handle_loop;
1023 handle_datalink = handle_raw;
1027 handle_datalink = handle_null;
1030 fprintf(stderr, "unsupported data link type %d\n",
1031 pcap_datalink(pcap_obj));
1038 if (readfile_state < 2) {
1040 * On some OSes select() might return 0 even when
1041 * there are packets to process. Thus, we always
1042 * ignore its return value and just call pcap_dispatch()
1045 if (0 == readfile_state) /* interactive */
1046 pcap_select(pcap_obj, 1, 0);
1047 x = pcap_dispatch(pcap_obj, 50, handle_pcap, NULL);
1049 if (0 == x && 1 == readfile_state) {
1050 /* block on keyboard until user quits */
1059 endwin(); /* klin, Thu Nov 28 08:56:51 2002 */
1061 while (pcap_dispatch(pcap_obj, 50, handle_pcap, NULL))
1064 Sources_report(); print_func("\n");
1065 Destinatioreport(); print_func("\n");
1066 Qtypes_report(); print_func("\n");
1067 Opcodes_report(); print_func("\n");
1068 Tld_report(); print_func("\n");
1069 Sld_report(); print_func("\n");
1070 Nld_report(); print_func("\n");
1071 SldBySource_report();
1074 pcap_close(pcap_obj);
1076 } /* static int main(int argc, char *argv[]) */