Fix warning in test_strunescape
[collectd.git] / src / utils / dns / dns.c
1 /*
2  * collectd - src/utils_dns.c
3  * Copyright (C) 2006       Florian octo Forster
4  * Copyright (C) 2002       The Measurement Factory, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
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.
18  *
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.
30  *
31  * Authors:
32  *   The Measurement Factory, Inc. <http://www.measurement-factory.com/>
33  *   Florian octo Forster <octo at collectd.org>
34  */
35
36 #define _DEFAULT_SOURCE
37 #define _BSD_SOURCE
38
39 #include "collectd.h"
40
41 #include "plugin.h"
42 #include "utils/common/common.h"
43
44 #if HAVE_NET_IF_ARP_H
45 #include <net/if_arp.h>
46 #endif
47 #if HAVE_NET_IF_H
48 #include <net/if.h>
49 #endif
50 #if HAVE_NET_PPP_DEFS_H
51 #include <net/ppp_defs.h>
52 #endif
53 #if HAVE_NET_IF_PPP_H
54 #include <net/if_ppp.h>
55 #endif
56
57 #if HAVE_NETINET_IN_SYSTM_H
58 #include <netinet/in_systm.h>
59 #endif
60 #if HAVE_NETINET_IN_H
61 #include <netinet/in.h>
62 #endif
63 #if HAVE_NETINET_IP6_H
64 #include <netinet/ip6.h>
65 #endif
66 #if HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
68 #endif
69 #if HAVE_NETINET_IP_H
70 #include <netinet/ip.h>
71 #endif
72 #ifdef HAVE_NETINET_IP_VAR_H
73 #include <netinet/ip_var.h>
74 #endif
75 #if HAVE_NETINET_UDP_H
76 #include <netinet/udp.h>
77 #endif
78
79 #if HAVE_ARPA_INET_H
80 #include <arpa/inet.h>
81 #endif
82
83 #if HAVE_NETDB_H
84 #include <netdb.h>
85 #endif
86
87 #if HAVE_PCAP_H
88 #include <pcap.h>
89 #endif
90
91 #define PCAP_SNAPLEN 1460
92 #ifndef ETHER_HDR_LEN
93 #define ETHER_ADDR_LEN 6
94 #define ETHER_TYPE_LEN 2
95 #define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
96 #endif
97 #ifndef ETHERTYPE_8021Q
98 #define ETHERTYPE_8021Q 0x8100
99 #endif
100 #ifndef ETHERTYPE_IPV6
101 #define ETHERTYPE_IPV6 0x86DD
102 #endif
103
104 #ifndef PPP_ADDRESS_VAL
105 #define PPP_ADDRESS_VAL 0xff /* The address byte value */
106 #endif
107 #ifndef PPP_CONTROL_VAL
108 #define PPP_CONTROL_VAL 0x03 /* The control byte value */
109 #endif
110
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
117 #else
118 #error "`struct udphdr' is unusable."
119 #endif
120
121 #if HAVE_NETINET_IP6_H && HAVE_STRUCT_IP6_EXT
122 #define HAVE_IPV6 1
123 #endif
124
125 #include "utils/dns/dns.h"
126
127 /*
128  * Type definitions
129  */
130 struct ip_list_s {
131   struct in6_addr addr;
132   void *data;
133   struct ip_list_s *next;
134 };
135 typedef struct ip_list_s ip_list_t;
136
137 typedef int(printer)(const char *, ...);
138
139 /*
140  * flags/features for non-interactive mode
141  */
142
143 #ifndef T_A6
144 #define T_A6 38
145 #endif
146 #ifndef T_SRV
147 #define T_SRV 33
148 #endif
149
150 /*
151  * Global variables
152  */
153
154 #if HAVE_PCAP_H
155 static pcap_t *pcap_obj;
156 #endif
157
158 static ip_list_t *IgnoreList;
159
160 #if HAVE_PCAP_H
161 static void (*Callback)(const rfc1035_header_t *);
162
163 static int query_count_intvl;
164 static int query_count_total;
165 #ifdef __OpenBSD__
166 static struct bpf_timeval last_ts;
167 #else
168 static struct timeval last_ts;
169 #endif /* __OpenBSD__ */
170 #endif /* HAVE_PCAP_H */
171
172 static int cmp_in6_addr(const struct in6_addr *a, const struct in6_addr *b) {
173   int i;
174
175   assert(sizeof(struct in6_addr) == 16);
176
177   for (i = 0; i < 16; i++)
178     if (a->s6_addr[i] != b->s6_addr[i])
179       break;
180
181   if (i >= 16)
182     return 0;
183
184   return a->s6_addr[i] > b->s6_addr[i] ? 1 : -1;
185 } /* int cmp_addrinfo */
186
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)
190       return 1;
191   return 0;
192 } /* int ignore_list_match */
193
194 static void ignore_list_add(const struct in6_addr *addr) {
195   ip_list_t *new;
196
197   if (ignore_list_match(addr) != 0)
198     return;
199
200   new = malloc(sizeof(*new));
201   if (new == NULL) {
202     perror("malloc");
203     return;
204   }
205
206   memcpy(&new->addr, addr, sizeof(struct in6_addr));
207   new->next = IgnoreList;
208
209   IgnoreList = new;
210 } /* void ignore_list_add */
211
212 void ignore_list_add_name(const char *name) {
213   struct addrinfo *ai_list;
214   struct in6_addr addr;
215   int status;
216
217   status = getaddrinfo(name, NULL, NULL, &ai_list);
218   if (status != 0)
219     return;
220
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);
229
230       ignore_list_add(&addr);
231     } else {
232       ignore_list_add(&((struct sockaddr_in6 *)ai_ptr->ai_addr)->sin6_addr);
233     }
234   } /* for */
235
236   freeaddrinfo(ai_list);
237 }
238
239 #if HAVE_PCAP_H
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);
249   }
250 } /* void in6_addr_from_buffer */
251
252 void dnstop_set_pcap_obj(pcap_t *po) { pcap_obj = po; }
253
254 void dnstop_set_callback(void (*cb)(const rfc1035_header_t *)) {
255   Callback = cb;
256 }
257
258 #define RFC1035_MAXLABELSZ 63
259 static int rfc1035NameUnpack(const char *buf, size_t sz, off_t *off, char *name,
260                              size_t ns) {
261   off_t no = 0;
262   unsigned char c;
263   size_t len;
264   static int loop_detect;
265   if (loop_detect > 2)
266     return 4; /* compression loop */
267   if (ns == 0)
268     return 4; /* probably compression loop */
269   do {
270     if ((*off) >= ((off_t)sz))
271       break;
272     c = *(buf + (*off));
273     if (c > 191) {
274       /* blasted compression */
275       int rc;
276       unsigned short s;
277       off_t ptr;
278       memcpy(&s, buf + (*off), sizeof(s));
279       s = ntohs(s);
280       (*off) += sizeof(s);
281       /* Sanity check */
282       if ((*off) >= ((off_t)sz))
283         return 1; /* message too short */
284       ptr = s & 0x3FFF;
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 */
290       loop_detect++;
291       rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
292       loop_detect--;
293       return rc;
294     } else if (c > RFC1035_MAXLABELSZ) {
295       /*
296        * "(The 10 and 01 combinations are reserved for future use.)"
297        */
298       return 3; /* reserved label/compression flags */
299     } else {
300       (*off)++;
301       len = (size_t)c;
302       if (len == 0)
303         break;
304       if (len > (ns - 1))
305         len = ns - 1;
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);
311       (*off) += len;
312       no += len;
313       *(name + (no++)) = '.';
314     }
315   } while (c > 0);
316   if (no > 0)
317     *(name + no - 1) = '\0';
318   /* make sure we didn't allow someone to overflow the name buffer */
319   assert(no <= ((off_t)ns));
320   return 0;
321 }
322
323 static int handle_dns(const char *buf, int len) {
324   rfc1035_header_t qh;
325   uint16_t us;
326   off_t offset;
327   char *t;
328   int status;
329
330   /* The DNS header is 12 bytes long */
331   if (len < DNS_MSG_HDR_SZ)
332     return 0;
333
334   memcpy(&us, buf + 0, 2);
335   qh.id = ntohs(us);
336
337   memcpy(&us, buf + 2, 2);
338   us = ntohs(us);
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;
349
350   memcpy(&us, buf + 4, 2);
351   qh.qdcount = ntohs(us);
352
353   memcpy(&us, buf + 6, 2);
354   qh.ancount = ntohs(us);
355
356   memcpy(&us, buf + 8, 2);
357   qh.nscount = ntohs(us);
358
359   memcpy(&us, buf + 10, 2);
360   qh.arcount = ntohs(us);
361
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);
365   if (status != 0) {
366     INFO("utils_dns: handle_dns: rfc1035NameUnpack failed "
367          "with status %i.",
368          status);
369     return 0;
370   }
371   if ('\0' == qh.qname[0])
372     sstrncpy(qh.qname, ".", sizeof(qh.qname));
373   while ((t = strchr(qh.qname, '\n')))
374     *t = ' ';
375   while ((t = strchr(qh.qname, '\r')))
376     *t = ' ';
377   for (t = qh.qname; *t; t++)
378     *t = tolower((int)*t);
379
380   memcpy(&us, buf + offset, 2);
381   qh.qtype = ntohs(us);
382   memcpy(&us, buf + offset + 2, 2);
383   qh.qclass = ntohs(us);
384
385   qh.length = (uint16_t)len;
386
387   if (Callback != NULL)
388     Callback(&qh);
389
390   return 1;
391 }
392
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))
396     return 0;
397   memcpy(buf, udp + 1, len - sizeof(*udp));
398   if (0 == handle_dns(buf, len - sizeof(*udp)))
399     return 0;
400   return 1;
401 }
402
403 #if HAVE_IPV6
404 static int handle_ipv6(struct ip6_hdr *ipv6, int len) {
405   char buf[PCAP_SNAPLEN];
406   unsigned int offset;
407   int nexthdr;
408
409   struct in6_addr c_src_addr;
410   uint16_t payload_len;
411
412   if (0 > len)
413     return 0;
414
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);
419
420   if (ignore_list_match(&c_src_addr))
421     return 0;
422
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. */
431   {
432     struct ip6_ext ext_hdr;
433     uint16_t ext_hdr_len;
434
435     /* Catch broken packets */
436     if ((offset + sizeof(struct ip6_ext)) > (unsigned int)len)
437       return 0;
438
439     /* Cannot handle fragments. */
440     if (IPPROTO_FRAGMENT == nexthdr)
441       return 0;
442
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));
446
447     /* This header is longer than the packets payload.. WTF? */
448     if (ext_hdr_len > payload_len)
449       return 0;
450
451     offset += ext_hdr_len;
452     payload_len -= ext_hdr_len;
453   } /* while */
454
455   /* Catch broken and empty packets */
456   if (((offset + payload_len) > (unsigned int)len) || (payload_len == 0) ||
457       (payload_len > PCAP_SNAPLEN))
458     return 0;
459
460   if (IPPROTO_UDP != nexthdr)
461     return 0;
462
463   memcpy(buf, (char *)ipv6 + offset, payload_len);
464   if (handle_udp((struct udphdr *)buf, payload_len) == 0)
465     return 0;
466
467   return 1; /* Success */
468 } /* int handle_ipv6 */
469   /* #endif HAVE_IPV6 */
470
471 #else  /* if !HAVE_IPV6 */
472 static int handle_ipv6(__attribute__((unused)) void *pkg,
473                        __attribute__((unused)) int len) {
474   return 0;
475 }
476 #endif /* !HAVE_IPV6 */
477
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;
483
484   if (ip->ip_v == 6)
485     return handle_ipv6((void *)ip, len);
486
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))
492     return 0;
493   if (IPPROTO_UDP != ip->ip_p)
494     return 0;
495   memcpy(buf, ((char *)ip) + offset, len - offset);
496   if (0 == handle_udp((struct udphdr *)buf, len - offset))
497     return 0;
498   return 1;
499 }
500
501 #if HAVE_NET_IF_PPP_H
502 static int handle_ppp(const u_char *pkt, int len) {
503   char buf[PCAP_SNAPLEN];
504   unsigned short us;
505   unsigned short proto;
506   if (len < 2)
507     return 0;
508   if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) {
509     pkt += 2; /* ACFC not used */
510     len -= 2;
511   }
512   if (len < 2)
513     return 0;
514   if (*pkt % 2) {
515     proto = *pkt; /* PFC is used */
516     pkt++;
517     len--;
518   } else {
519     memcpy(&us, pkt, sizeof(us));
520     proto = ntohs(us);
521     pkt += 2;
522     len -= 2;
523   }
524   if (ETHERTYPE_IP != proto && PPP_IP != proto)
525     return 0;
526   memcpy(buf, pkt, len);
527   return handle_ip((struct ip *)buf, len);
528 }
529 #endif /* HAVE_NET_IF_PPP_H */
530
531 static int handle_null(const u_char *pkt, int len) {
532   unsigned int family;
533   memcpy(&family, pkt, sizeof(family));
534   if (AF_INET != family)
535     return 0;
536   return handle_ip((struct ip *)(pkt + 4), len - 4);
537 }
538
539 #ifdef DLT_LOOP
540 static int handle_loop(const u_char *pkt, int len) {
541   unsigned int family;
542   memcpy(&family, pkt, sizeof(family));
543   if (AF_INET != ntohl(family))
544     return 0;
545   return handle_ip((struct ip *)(pkt + 4), len - 4);
546 }
547
548 #endif
549
550 #ifdef DLT_RAW
551 static int handle_raw(const u_char *pkt, int len) {
552   return handle_ip((struct ip *)pkt, len);
553 }
554
555 #endif
556
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)
562     return 0;
563   pkt += ETHER_HDR_LEN;
564   len -= ETHER_HDR_LEN;
565   if (ETHERTYPE_8021Q == etype) {
566     etype = ntohs(*(unsigned short *)(pkt + 2));
567     pkt += 4;
568     len -= 4;
569   }
570   if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
571     return 0;
572   memcpy(buf, pkt, len);
573   if (ETHERTYPE_IPV6 == etype)
574     return handle_ipv6((void *)buf, len);
575   else
576     return handle_ip((struct ip *)buf, len);
577 }
578
579 #ifdef DLT_LINUX_SLL
580 static int handle_linux_sll(const u_char *pkt, int len) {
581   struct sll_header {
582     uint16_t pkt_type;
583     uint16_t dev_type;
584     uint16_t addr_len;
585     uint8_t addr[8];
586     uint16_t proto_type;
587   } * hdr;
588   uint16_t etype;
589
590   if ((0 > len) || ((unsigned int)len < sizeof(struct sll_header)))
591     return 0;
592
593   hdr = (struct sll_header *)pkt;
594   pkt = (u_char *)(hdr + 1);
595   len -= sizeof(struct sll_header);
596
597   etype = ntohs(hdr->proto_type);
598
599   if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
600     return 0;
601
602   if (ETHERTYPE_IPV6 == etype)
603     return handle_ipv6((void *)pkt, len);
604   else
605     return handle_ip((struct ip *)pkt, len);
606 }
607 #endif /* DLT_LINUX_SLL */
608
609 /* public function */
610 void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr,
611                  const u_char *pkt) {
612   int status;
613
614   if (hdr->caplen < ETHER_HDR_LEN)
615     return;
616
617   switch (pcap_datalink(pcap_obj)) {
618   case DLT_EN10MB:
619     status = handle_ether(pkt, hdr->caplen);
620     break;
621 #if HAVE_NET_IF_PPP_H
622   case DLT_PPP:
623     status = handle_ppp(pkt, hdr->caplen);
624     break;
625 #endif
626 #ifdef DLT_LOOP
627   case DLT_LOOP:
628     status = handle_loop(pkt, hdr->caplen);
629     break;
630 #endif
631 #ifdef DLT_RAW
632   case DLT_RAW:
633     status = handle_raw(pkt, hdr->caplen);
634     break;
635 #endif
636 #ifdef DLT_LINUX_SLL
637   case DLT_LINUX_SLL:
638     status = handle_linux_sll(pkt, hdr->caplen);
639     break;
640 #endif
641   case DLT_NULL:
642     status = handle_null(pkt, hdr->caplen);
643     break;
644
645   default:
646     ERROR("handle_pcap: unsupported data link type %d",
647           pcap_datalink(pcap_obj));
648     status = 0;
649     break;
650   } /* switch (pcap_datalink(pcap_obj)) */
651
652   if (0 == status)
653     return;
654
655   query_count_intvl++;
656   query_count_total++;
657   last_ts = hdr->ts;
658 }
659 #endif /* HAVE_PCAP_H */
660
661 const char *qtype_str(int t) {
662   static char buf[32];
663   // clang-format off
664   /*
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";'
668   */
669   // clang-format on
670   switch (t) {
671   case 1:
672     return "A";
673   case 2:
674     return "NS";
675   case 3:
676     return "MD";
677   case 4:
678     return "MF";
679   case 5:
680     return "CNAME";
681   case 6:
682     return "SOA";
683   case 7:
684     return "MB";
685   case 8:
686     return "MG";
687   case 9:
688     return "MR";
689   case 10:
690     return "NULL";
691   case 11:
692     return "WKS";
693   case 12:
694     return "PTR";
695   case 13:
696     return "HINFO";
697   case 14:
698     return "MINFO";
699   case 15:
700     return "MX";
701   case 16:
702     return "TXT";
703   case 17:
704     return "RP";
705   case 18:
706     return "AFSDB";
707   case 19:
708     return "X25";
709   case 20:
710     return "ISDN";
711   case 21:
712     return "RT";
713   case 22:
714     return "NSAP";
715   case 23:
716     return "NSAP-PTR";
717   case 24:
718     return "SIG";
719   case 25:
720     return "KEY";
721   case 26:
722     return "PX";
723   case 27:
724     return "GPOS";
725   case 28:
726     return "AAAA";
727   case 29:
728     return "LOC";
729   case 30:
730     return "NXT";
731   case 31:
732     return "EID";
733   case 32:
734     return "NIMLOC";
735   case 33:
736     return "SRV";
737   case 34:
738     return "ATMA";
739   case 35:
740     return "NAPTR";
741   case 36:
742     return "KX";
743   case 37:
744     return "CERT";
745   case 38:
746     return "A6";
747   case 39:
748     return "DNAME";
749   case 40:
750     return "SINK";
751   case 41:
752     return "OPT";
753   case 42:
754     return "APL";
755   case 43:
756     return "DS";
757   case 44:
758     return "SSHFP";
759   case 45:
760     return "IPSECKEY";
761   case 46:
762     return "RRSIG";
763   case 47:
764     return "NSEC";
765   case 48:
766     return "DNSKEY";
767   case 49:
768     return "DHCID";
769   case 50:
770     return "NSEC3";
771   case 51:
772     return "NSEC3PARAM";
773   case 52:
774     return "TLSA";
775   case 53:
776     return "SMIMEA";
777   case 55:
778     return "HIP";
779   case 56:
780     return "NINFO";
781   case 57:
782     return "RKEY";
783   case 58:
784     return "TALINK";
785   case 59:
786     return "CDS";
787   case 60:
788     return "CDNSKEY";
789   case 61:
790     return "OPENPGPKEY";
791   case 62:
792     return "CSYNC";
793   case 99:
794     return "SPF";
795   case 100:
796     return "UINFO";
797   case 101:
798     return "UID";
799   case 102:
800     return "GID";
801   case 103:
802     return "UNSPEC";
803   case 104:
804     return "NID";
805   case 105:
806     return "L32";
807   case 106:
808     return "L64";
809   case 107:
810     return "LP";
811   case 108:
812     return "EUI48";
813   case 109:
814     return "EUI64";
815   case 249:
816     return "TKEY";
817   case 250:
818     return "TSIG";
819   case 251:
820     return "IXFR";
821   case 252:
822     return "AXFR";
823   case 253:
824     return "MAILB";
825   case 254:
826     return "MAILA";
827   case 255:
828     return "ANY";
829   case 256:
830     return "URI";
831   case 257:
832     return "CAA";
833   case 258:
834     return "AVC";
835   case 32768:
836     return "TA";
837   case 32769:
838     return "DLV";
839   default:
840     ssnprintf(buf, sizeof(buf), "#%i", t);
841     return buf;
842   } /* switch (t) */
843 }
844
845 const char *opcode_str(int o) {
846   static char buf[30];
847   switch (o) {
848   case 0:
849     return "Query";
850   case 1:
851     return "Iquery";
852   case 2:
853     return "Status";
854   case 4:
855     return "Notify";
856   case 5:
857     return "Update";
858   default:
859     ssnprintf(buf, sizeof(buf), "Opcode%d", o);
860     return buf;
861   }
862 }
863
864 const char *rcode_str(int rcode) {
865   static char buf[32];
866   /* RFC2136 rcodes */
867   // clang-format off
868   /*
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";'
872
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.
875   */
876   // clang-format on
877   switch (rcode) {
878   case 1:
879     return "FORMERR";
880   case 2:
881     return "SERVFAIL";
882   case 3:
883     return "NXDOMAIN";
884   case 4:
885     return "NOTIMPL";
886   case 5:
887     return "REFUSED";
888   case 6:
889     return "YXDOMAIN";
890   case 7:
891     return "YXRRSET";
892   case 8:
893     return "NXRRSET";
894   case 9:
895     return "NOTAUTH";
896   case 10:
897     return "NOTZONE";
898   case 11:
899     return "MAX";
900   case 16:
901     return "BADSIG";
902   case 17:
903     return "BADKEY";
904   case 18:
905     return "BADTIME";
906   default:
907     ssnprintf(buf, sizeof(buf), "RCode%i", rcode);
908     return buf;
909   }
910 } /* const char *rcode_str (int rcode) */
911
912 #if 0
913 static int
914 main(int argc, char *argv[])
915 {
916     char errbuf[PCAP_ERRBUF_SIZE];
917     int x;
918     struct stat sb;
919     int readfile_state = 0;
920     struct bpf_program fp;
921
922     port53 = htons(53);
923     SubReport = Sources_report;
924     ignore_addr.s_addr = 0;
925     progname = strdup(strrchr(argv[0], '/') ? strchr(argv[0], '/') + 1 : argv[0]);
926     srandom(time(NULL));
927     ResetCounters();
928
929     while ((x = getopt(argc, argv, "ab:f:i:pst")) != -1) {
930         switch (x) {
931         case 'a':
932             anon_flag = 1;
933             break;
934         case 's':
935             sld_flag = 1;
936             break;
937         case 't':
938             nld_flag = 1;
939             break;
940         case 'p':
941             promisc_flag = 0;
942             break;
943         case 'b':
944             bpf_program_str = strdup(optarg);
945             break;
946         case 'i':
947             ignore_addr.s_addr = inet_addr(optarg);
948             break;
949         case 'f':
950             set_filter(optarg);
951             break;
952         default:
953             usage();
954             break;
955         }
956     }
957     argc -= optind;
958     argv += optind;
959
960     if (argc < 1)
961         usage();
962     device = strdup(argv[0]);
963
964     if (0 == stat(device, &sb))
965         readfile_state = 1;
966     if (readfile_state) {
967         pcap_obj = pcap_open_offline(device, errbuf);
968     } else {
969         pcap_obj = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1000, errbuf);
970     }
971     if (NULL == pcap_obj) {
972         fprintf(stderr, "pcap_open_*: %s\n", errbuf);
973         exit(1);
974     }
975
976     if (0 == isatty(1)) {
977         if (0 == readfile_state) {
978             fprintf(stderr, "Non-interactive mode requires savefile argument\n");
979             exit(1);
980         }
981         interactive = 0;
982         print_func = printf;
983     }
984
985     memset(&fp, '\0', sizeof(fp));
986     x = pcap_compile(pcap_obj, &fp, bpf_program_str, 1, 0);
987     if (x < 0) {
988         fprintf(stderr, "pcap_compile failed\n");
989         exit(1);
990     }
991     x = pcap_setfilter(pcap_obj, &fp);
992     if (x < 0) {
993         fprintf(stderr, "pcap_setfilter failed\n");
994         exit(1);
995     }
996
997     /*
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
1000      */
1001     x = pcap_setnonblock(pcap_obj, 1, errbuf);
1002     if (x < 0) {
1003         fprintf(stderr, "pcap_setnonblock failed: %s\n", errbuf);
1004         exit(1);
1005     }
1006
1007     switch (pcap_datalink(pcap_obj)) {
1008     case DLT_EN10MB:
1009         handle_datalink = handle_ether;
1010         break;
1011 #if HAVE_NET_IF_PPP_H
1012     case DLT_PPP:
1013         handle_datalink = handle_ppp;
1014         break;
1015 #endif
1016 #ifdef DLT_LOOP
1017     case DLT_LOOP:
1018         handle_datalink = handle_loop;
1019         break;
1020 #endif
1021 #ifdef DLT_RAW
1022     case DLT_RAW:
1023         handle_datalink = handle_raw;
1024         break;
1025 #endif
1026     case DLT_NULL:
1027         handle_datalink = handle_null;
1028         break;
1029     default:
1030         fprintf(stderr, "unsupported data link type %d\n",
1031             pcap_datalink(pcap_obj));
1032         return 1;
1033         break;
1034     }
1035     if (interactive) {
1036         init_curses();
1037         while (0 == Quit) {
1038             if (readfile_state < 2) {
1039                 /*
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()
1043                  * anyway.
1044                  */
1045                 if (0 == readfile_state)        /* interactive */
1046                     pcap_select(pcap_obj, 1, 0);
1047                 x = pcap_dispatch(pcap_obj, 50, handle_pcap, NULL);
1048             }
1049             if (0 == x && 1 == readfile_state) {
1050                 /* block on keyboard until user quits */
1051                 readfile_state++;
1052                 nodelay(w, 0);
1053             }
1054             keyboard();
1055             cron_pre();
1056             report();
1057             cron_post();
1058         }
1059         endwin();               /* klin, Thu Nov 28 08:56:51 2002 */
1060     } else {
1061         while (pcap_dispatch(pcap_obj, 50, handle_pcap, NULL))
1062                 (void) 0;
1063         cron_pre();
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();
1072     }
1073
1074     pcap_close(pcap_obj);
1075     return 0;
1076 } /* static int main(int argc, char *argv[]) */
1077 #endif