Merge pull request #3108 from rubenk/cirrus-improvements
[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 #if HAVE_ARPA_NAMESER_H
83 #include <arpa/nameser.h>
84 #endif
85 #if HAVE_ARPA_NAMESER_COMPAT_H
86 #include <arpa/nameser_compat.h>
87 #endif
88
89 #if HAVE_NETDB_H
90 #include <netdb.h>
91 #endif
92
93 #if HAVE_PCAP_H
94 #include <pcap.h>
95 #endif
96
97 #define PCAP_SNAPLEN 1460
98 #ifndef ETHER_HDR_LEN
99 #define ETHER_ADDR_LEN 6
100 #define ETHER_TYPE_LEN 2
101 #define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
102 #endif
103 #ifndef ETHERTYPE_8021Q
104 #define ETHERTYPE_8021Q 0x8100
105 #endif
106 #ifndef ETHERTYPE_IPV6
107 #define ETHERTYPE_IPV6 0x86DD
108 #endif
109
110 #ifndef PPP_ADDRESS_VAL
111 #define PPP_ADDRESS_VAL 0xff /* The address byte value */
112 #endif
113 #ifndef PPP_CONTROL_VAL
114 #define PPP_CONTROL_VAL 0x03 /* The control byte value */
115 #endif
116
117 #if HAVE_STRUCT_UDPHDR_UH_DPORT && HAVE_STRUCT_UDPHDR_UH_SPORT
118 #define UDP_DEST uh_dport
119 #define UDP_SRC uh_sport
120 #elif HAVE_STRUCT_UDPHDR_DEST && HAVE_STRUCT_UDPHDR_SOURCE
121 #define UDP_DEST dest
122 #define UDP_SRC source
123 #else
124 #error "`struct udphdr' is unusable."
125 #endif
126
127 #if HAVE_NETINET_IP6_H && HAVE_STRUCT_IP6_EXT
128 #define HAVE_IPV6 1
129 #endif
130
131 #include "utils/dns/dns.h"
132
133 /*
134  * Type definitions
135  */
136 struct ip_list_s {
137   struct in6_addr addr;
138   void *data;
139   struct ip_list_s *next;
140 };
141 typedef struct ip_list_s ip_list_t;
142
143 typedef int(printer)(const char *, ...);
144
145 /*
146  * flags/features for non-interactive mode
147  */
148
149 #ifndef T_A6
150 #define T_A6 38
151 #endif
152 #ifndef T_SRV
153 #define T_SRV 33
154 #endif
155
156 /*
157  * Global variables
158  */
159
160 #if HAVE_PCAP_H
161 static pcap_t *pcap_obj;
162 #endif
163
164 static ip_list_t *IgnoreList;
165
166 #if HAVE_PCAP_H
167 static void (*Callback)(const rfc1035_header_t *);
168
169 static int query_count_intvl;
170 static int query_count_total;
171 #ifdef __OpenBSD__
172 static struct bpf_timeval last_ts;
173 #else
174 static struct timeval last_ts;
175 #endif /* __OpenBSD__ */
176 #endif /* HAVE_PCAP_H */
177
178 static int cmp_in6_addr(const struct in6_addr *a, const struct in6_addr *b) {
179   int i;
180
181   assert(sizeof(struct in6_addr) == 16);
182
183   for (i = 0; i < 16; i++)
184     if (a->s6_addr[i] != b->s6_addr[i])
185       break;
186
187   if (i >= 16)
188     return 0;
189
190   return a->s6_addr[i] > b->s6_addr[i] ? 1 : -1;
191 } /* int cmp_addrinfo */
192
193 static inline int ignore_list_match(const struct in6_addr *addr) {
194   for (ip_list_t *ptr = IgnoreList; ptr != NULL; ptr = ptr->next)
195     if (cmp_in6_addr(addr, &ptr->addr) == 0)
196       return 1;
197   return 0;
198 } /* int ignore_list_match */
199
200 static void ignore_list_add(const struct in6_addr *addr) {
201   ip_list_t *new;
202
203   if (ignore_list_match(addr) != 0)
204     return;
205
206   new = malloc(sizeof(*new));
207   if (new == NULL) {
208     perror("malloc");
209     return;
210   }
211
212   memcpy(&new->addr, addr, sizeof(struct in6_addr));
213   new->next = IgnoreList;
214
215   IgnoreList = new;
216 } /* void ignore_list_add */
217
218 void ignore_list_add_name(const char *name) {
219   struct addrinfo *ai_list;
220   struct in6_addr addr;
221   int status;
222
223   status = getaddrinfo(name, NULL, NULL, &ai_list);
224   if (status != 0)
225     return;
226
227   for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
228        ai_ptr = ai_ptr->ai_next) {
229     if (ai_ptr->ai_family == AF_INET) {
230       memset(&addr, '\0', sizeof(addr));
231       addr.s6_addr[10] = 0xFF;
232       addr.s6_addr[11] = 0xFF;
233       memcpy(addr.s6_addr + 12,
234              &((struct sockaddr_in *)ai_ptr->ai_addr)->sin_addr, 4);
235
236       ignore_list_add(&addr);
237     } else {
238       ignore_list_add(&((struct sockaddr_in6 *)ai_ptr->ai_addr)->sin6_addr);
239     }
240   } /* for */
241
242   freeaddrinfo(ai_list);
243 }
244
245 #if HAVE_PCAP_H
246 static void in6_addr_from_buffer(struct in6_addr *ia, const void *buf,
247                                  size_t buf_len, int family) {
248   memset(ia, 0, sizeof(struct in6_addr));
249   if ((AF_INET == family) && (sizeof(uint32_t) == buf_len)) {
250     ia->s6_addr[10] = 0xFF;
251     ia->s6_addr[11] = 0xFF;
252     memcpy(ia->s6_addr + 12, buf, buf_len);
253   } else if ((AF_INET6 == family) && (sizeof(struct in6_addr) == buf_len)) {
254     memcpy(ia, buf, buf_len);
255   }
256 } /* void in6_addr_from_buffer */
257
258 void dnstop_set_pcap_obj(pcap_t *po) { pcap_obj = po; }
259
260 void dnstop_set_callback(void (*cb)(const rfc1035_header_t *)) {
261   Callback = cb;
262 }
263
264 #define RFC1035_MAXLABELSZ 63
265 static int rfc1035NameUnpack(const char *buf, size_t sz, off_t *off, char *name,
266                              size_t ns) {
267   off_t no = 0;
268   unsigned char c;
269   size_t len;
270   static int loop_detect;
271   if (loop_detect > 2)
272     return 4; /* compression loop */
273   if (ns == 0)
274     return 4; /* probably compression loop */
275   do {
276     if ((*off) >= ((off_t)sz))
277       break;
278     c = *(buf + (*off));
279     if (c > 191) {
280       /* blasted compression */
281       int rc;
282       unsigned short s;
283       off_t ptr;
284       memcpy(&s, buf + (*off), sizeof(s));
285       s = ntohs(s);
286       (*off) += sizeof(s);
287       /* Sanity check */
288       if ((*off) >= ((off_t)sz))
289         return 1; /* message too short */
290       ptr = s & 0x3FFF;
291       /* Make sure the pointer is inside this message */
292       if (ptr >= ((off_t)sz))
293         return 2; /* bad compression ptr */
294       if (ptr < DNS_MSG_HDR_SZ)
295         return 2; /* bad compression ptr */
296       loop_detect++;
297       rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
298       loop_detect--;
299       return rc;
300     } else if (c > RFC1035_MAXLABELSZ) {
301       /*
302        * "(The 10 and 01 combinations are reserved for future use.)"
303        */
304       return 3; /* reserved label/compression flags */
305     } else {
306       (*off)++;
307       len = (size_t)c;
308       if (len == 0)
309         break;
310       if (len > (ns - 1))
311         len = ns - 1;
312       if ((*off) + len > sz)
313         return 4; /* message is too short */
314       if (no + len + 1 > ns)
315         return 5; /* qname would overflow name buffer */
316       memcpy(name + no, buf + (*off), len);
317       (*off) += len;
318       no += len;
319       *(name + (no++)) = '.';
320     }
321   } while (c > 0);
322   if (no > 0)
323     *(name + no - 1) = '\0';
324   /* make sure we didn't allow someone to overflow the name buffer */
325   assert(no <= ((off_t)ns));
326   return 0;
327 }
328
329 static int handle_dns(const char *buf, int len) {
330   rfc1035_header_t qh;
331   uint16_t us;
332   off_t offset;
333   char *t;
334   int status;
335
336   /* The DNS header is 12 bytes long */
337   if (len < DNS_MSG_HDR_SZ)
338     return 0;
339
340   memcpy(&us, buf + 0, 2);
341   qh.id = ntohs(us);
342
343   memcpy(&us, buf + 2, 2);
344   us = ntohs(us);
345   qh.qr = (us >> 15) & 0x01;
346   qh.opcode = (us >> 11) & 0x0F;
347   qh.aa = (us >> 10) & 0x01;
348   qh.tc = (us >> 9) & 0x01;
349   qh.rd = (us >> 8) & 0x01;
350   qh.ra = (us >> 7) & 0x01;
351   qh.z = (us >> 6) & 0x01;
352   qh.ad = (us >> 5) & 0x01;
353   qh.cd = (us >> 4) & 0x01;
354   qh.rcode = us & 0x0F;
355
356   memcpy(&us, buf + 4, 2);
357   qh.qdcount = ntohs(us);
358
359   memcpy(&us, buf + 6, 2);
360   qh.ancount = ntohs(us);
361
362   memcpy(&us, buf + 8, 2);
363   qh.nscount = ntohs(us);
364
365   memcpy(&us, buf + 10, 2);
366   qh.arcount = ntohs(us);
367
368   offset = DNS_MSG_HDR_SZ;
369   memset(qh.qname, '\0', MAX_QNAME_SZ);
370   status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
371   if (status != 0) {
372     INFO("utils_dns: handle_dns: rfc1035NameUnpack failed "
373          "with status %i.",
374          status);
375     return 0;
376   }
377   if ('\0' == qh.qname[0])
378     sstrncpy(qh.qname, ".", sizeof(qh.qname));
379   while ((t = strchr(qh.qname, '\n')))
380     *t = ' ';
381   while ((t = strchr(qh.qname, '\r')))
382     *t = ' ';
383   for (t = qh.qname; *t; t++)
384     *t = tolower((int)*t);
385
386   memcpy(&us, buf + offset, 2);
387   qh.qtype = ntohs(us);
388   memcpy(&us, buf + offset + 2, 2);
389   qh.qclass = ntohs(us);
390
391   qh.length = (uint16_t)len;
392
393   if (Callback != NULL)
394     Callback(&qh);
395
396   return 1;
397 }
398
399 static int handle_udp(const struct udphdr *udp, int len) {
400   char buf[PCAP_SNAPLEN];
401   if ((ntohs(udp->UDP_DEST) != 53) && (ntohs(udp->UDP_SRC) != 53))
402     return 0;
403   memcpy(buf, udp + 1, len - sizeof(*udp));
404   if (0 == handle_dns(buf, len - sizeof(*udp)))
405     return 0;
406   return 1;
407 }
408
409 #if HAVE_IPV6
410 static int handle_ipv6(struct ip6_hdr *ipv6, int len) {
411   char buf[PCAP_SNAPLEN];
412   unsigned int offset;
413   int nexthdr;
414
415   struct in6_addr c_src_addr;
416   uint16_t payload_len;
417
418   if (0 > len)
419     return 0;
420
421   offset = sizeof(struct ip6_hdr);
422   nexthdr = ipv6->ip6_nxt;
423   c_src_addr = ipv6->ip6_src;
424   payload_len = ntohs(ipv6->ip6_plen);
425
426   if (ignore_list_match(&c_src_addr))
427     return 0;
428
429   /* Parse extension headers. This only handles the standard headers, as
430    * defined in RFC 2460, correctly. Fragments are discarded. */
431   while ((IPPROTO_ROUTING == nexthdr)     /* routing header */
432          || (IPPROTO_HOPOPTS == nexthdr)  /* Hop-by-Hop options. */
433          || (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
434          || (IPPROTO_DSTOPTS == nexthdr)  /* destination options. */
435          || (IPPROTO_AH == nexthdr)       /* destination options. */
436          || (IPPROTO_ESP == nexthdr))     /* encapsulating security payload. */
437   {
438     struct ip6_ext ext_hdr;
439     uint16_t ext_hdr_len;
440
441     /* Catch broken packets */
442     if ((offset + sizeof(struct ip6_ext)) > (unsigned int)len)
443       return 0;
444
445     /* Cannot handle fragments. */
446     if (IPPROTO_FRAGMENT == nexthdr)
447       return 0;
448
449     memcpy(&ext_hdr, (char *)ipv6 + offset, sizeof(struct ip6_ext));
450     nexthdr = ext_hdr.ip6e_nxt;
451     ext_hdr_len = (8 * (ntohs(ext_hdr.ip6e_len) + 1));
452
453     /* This header is longer than the packets payload.. WTF? */
454     if (ext_hdr_len > payload_len)
455       return 0;
456
457     offset += ext_hdr_len;
458     payload_len -= ext_hdr_len;
459   } /* while */
460
461   /* Catch broken and empty packets */
462   if (((offset + payload_len) > (unsigned int)len) || (payload_len == 0) ||
463       (payload_len > PCAP_SNAPLEN))
464     return 0;
465
466   if (IPPROTO_UDP != nexthdr)
467     return 0;
468
469   memcpy(buf, (char *)ipv6 + offset, payload_len);
470   if (handle_udp((struct udphdr *)buf, payload_len) == 0)
471     return 0;
472
473   return 1; /* Success */
474 } /* int handle_ipv6 */
475 /* #endif HAVE_IPV6 */
476
477 #else  /* if !HAVE_IPV6 */
478 static int handle_ipv6(__attribute__((unused)) void *pkg,
479                        __attribute__((unused)) int len) {
480   return 0;
481 }
482 #endif /* !HAVE_IPV6 */
483
484 static int handle_ip(const struct ip *ip, int len) {
485   char buf[PCAP_SNAPLEN];
486   int offset = ip->ip_hl << 2;
487   struct in6_addr c_src_addr;
488   struct in6_addr c_dst_addr;
489
490   if (ip->ip_v == 6)
491     return handle_ipv6((void *)ip, len);
492
493   in6_addr_from_buffer(&c_src_addr, &ip->ip_src.s_addr,
494                        sizeof(ip->ip_src.s_addr), AF_INET);
495   in6_addr_from_buffer(&c_dst_addr, &ip->ip_dst.s_addr,
496                        sizeof(ip->ip_dst.s_addr), AF_INET);
497   if (ignore_list_match(&c_src_addr))
498     return 0;
499   if (IPPROTO_UDP != ip->ip_p)
500     return 0;
501   memcpy(buf, ((char *)ip) + offset, len - offset);
502   if (0 == handle_udp((struct udphdr *)buf, len - offset))
503     return 0;
504   return 1;
505 }
506
507 #if HAVE_NET_IF_PPP_H
508 static int handle_ppp(const u_char *pkt, int len) {
509   char buf[PCAP_SNAPLEN];
510   unsigned short us;
511   unsigned short proto;
512   if (len < 2)
513     return 0;
514   if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) {
515     pkt += 2; /* ACFC not used */
516     len -= 2;
517   }
518   if (len < 2)
519     return 0;
520   if (*pkt % 2) {
521     proto = *pkt; /* PFC is used */
522     pkt++;
523     len--;
524   } else {
525     memcpy(&us, pkt, sizeof(us));
526     proto = ntohs(us);
527     pkt += 2;
528     len -= 2;
529   }
530   if (ETHERTYPE_IP != proto && PPP_IP != proto)
531     return 0;
532   memcpy(buf, pkt, len);
533   return handle_ip((struct ip *)buf, len);
534 }
535 #endif /* HAVE_NET_IF_PPP_H */
536
537 static int handle_null(const u_char *pkt, int len) {
538   unsigned int family;
539   memcpy(&family, pkt, sizeof(family));
540   if (AF_INET != family)
541     return 0;
542   return handle_ip((struct ip *)(pkt + 4), len - 4);
543 }
544
545 #ifdef DLT_LOOP
546 static int handle_loop(const u_char *pkt, int len) {
547   unsigned int family;
548   memcpy(&family, pkt, sizeof(family));
549   if (AF_INET != ntohl(family))
550     return 0;
551   return handle_ip((struct ip *)(pkt + 4), len - 4);
552 }
553
554 #endif
555
556 #ifdef DLT_RAW
557 static int handle_raw(const u_char *pkt, int len) {
558   return handle_ip((struct ip *)pkt, len);
559 }
560
561 #endif
562
563 static int handle_ether(const u_char *pkt, int len) {
564   char buf[PCAP_SNAPLEN];
565   struct ether_header *e = (void *)pkt;
566   unsigned short etype = ntohs(e->ether_type);
567   if (len < ETHER_HDR_LEN)
568     return 0;
569   pkt += ETHER_HDR_LEN;
570   len -= ETHER_HDR_LEN;
571   if (ETHERTYPE_8021Q == etype) {
572     etype = ntohs(*(unsigned short *)(pkt + 2));
573     pkt += 4;
574     len -= 4;
575   }
576   if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
577     return 0;
578   memcpy(buf, pkt, len);
579   if (ETHERTYPE_IPV6 == etype)
580     return handle_ipv6((void *)buf, len);
581   else
582     return handle_ip((struct ip *)buf, len);
583 }
584
585 #ifdef DLT_LINUX_SLL
586 static int handle_linux_sll(const u_char *pkt, int len) {
587   struct sll_header {
588     uint16_t pkt_type;
589     uint16_t dev_type;
590     uint16_t addr_len;
591     uint8_t addr[8];
592     uint16_t proto_type;
593   } * hdr;
594   uint16_t etype;
595
596   if ((0 > len) || ((unsigned int)len < sizeof(struct sll_header)))
597     return 0;
598
599   hdr = (struct sll_header *)pkt;
600   pkt = (u_char *)(hdr + 1);
601   len -= sizeof(struct sll_header);
602
603   etype = ntohs(hdr->proto_type);
604
605   if ((ETHERTYPE_IP != etype) && (ETHERTYPE_IPV6 != etype))
606     return 0;
607
608   if (ETHERTYPE_IPV6 == etype)
609     return handle_ipv6((void *)pkt, len);
610   else
611     return handle_ip((struct ip *)pkt, len);
612 }
613 #endif /* DLT_LINUX_SLL */
614
615 /* public function */
616 void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr,
617                  const u_char *pkt) {
618   int status;
619
620   if (hdr->caplen < ETHER_HDR_LEN)
621     return;
622
623   switch (pcap_datalink(pcap_obj)) {
624   case DLT_EN10MB:
625     status = handle_ether(pkt, hdr->caplen);
626     break;
627 #if HAVE_NET_IF_PPP_H
628   case DLT_PPP:
629     status = handle_ppp(pkt, hdr->caplen);
630     break;
631 #endif
632 #ifdef DLT_LOOP
633   case DLT_LOOP:
634     status = handle_loop(pkt, hdr->caplen);
635     break;
636 #endif
637 #ifdef DLT_RAW
638   case DLT_RAW:
639     status = handle_raw(pkt, hdr->caplen);
640     break;
641 #endif
642 #ifdef DLT_LINUX_SLL
643   case DLT_LINUX_SLL:
644     status = handle_linux_sll(pkt, hdr->caplen);
645     break;
646 #endif
647   case DLT_NULL:
648     status = handle_null(pkt, hdr->caplen);
649     break;
650
651   default:
652     ERROR("handle_pcap: unsupported data link type %d",
653           pcap_datalink(pcap_obj));
654     status = 0;
655     break;
656   } /* switch (pcap_datalink(pcap_obj)) */
657
658   if (0 == status)
659     return;
660
661   query_count_intvl++;
662   query_count_total++;
663   last_ts = hdr->ts;
664 }
665 #endif /* HAVE_PCAP_H */
666
667 const char *qtype_str(int t) {
668   static char buf[32];
669   switch (t) {
670 #if (defined(__NAMESER)) && (__NAMESER >= 19991001)
671   case ns_t_a:
672     return "A";
673   case ns_t_ns:
674     return "NS";
675   case ns_t_md:
676     return "MD";
677   case ns_t_mf:
678     return "MF";
679   case ns_t_cname:
680     return "CNAME";
681   case ns_t_soa:
682     return "SOA";
683   case ns_t_mb:
684     return "MB";
685   case ns_t_mg:
686     return "MG";
687   case ns_t_mr:
688     return "MR";
689   case ns_t_null:
690     return "NULL";
691   case ns_t_wks:
692     return "WKS";
693   case ns_t_ptr:
694     return "PTR";
695   case ns_t_hinfo:
696     return "HINFO";
697   case ns_t_minfo:
698     return "MINFO";
699   case ns_t_mx:
700     return "MX";
701   case ns_t_txt:
702     return "TXT";
703   case ns_t_rp:
704     return "RP";
705   case ns_t_afsdb:
706     return "AFSDB";
707   case ns_t_x25:
708     return "X25";
709   case ns_t_isdn:
710     return "ISDN";
711   case ns_t_rt:
712     return "RT";
713   case ns_t_nsap:
714     return "NSAP";
715   case ns_t_nsap_ptr:
716     return "NSAP-PTR";
717   case ns_t_sig:
718     return "SIG";
719   case ns_t_key:
720     return "KEY";
721   case ns_t_px:
722     return "PX";
723   case ns_t_gpos:
724     return "GPOS";
725   case ns_t_aaaa:
726     return "AAAA";
727   case ns_t_loc:
728     return "LOC";
729   case ns_t_nxt:
730     return "NXT";
731   case ns_t_eid:
732     return "EID";
733   case ns_t_nimloc:
734     return "NIMLOC";
735   case ns_t_srv:
736     return "SRV";
737   case ns_t_atma:
738     return "ATMA";
739   case ns_t_naptr:
740     return "NAPTR";
741   case ns_t_opt:
742     return "OPT";
743 #if __NAMESER >= 19991006
744   case ns_t_kx:
745     return "KX";
746   case ns_t_cert:
747     return "CERT";
748   case ns_t_a6:
749     return "A6";
750   case ns_t_dname:
751     return "DNAME";
752   case ns_t_sink:
753     return "SINK";
754   case ns_t_tsig:
755     return "TSIG";
756 #endif
757 #if __NAMESER >= 20090302
758   case ns_t_apl:
759     return "APL";
760   case ns_t_ds:
761     return "DS";
762   case ns_t_sshfp:
763     return "SSHFP";
764   case ns_t_ipseckey:
765     return "IPSECKEY";
766   case ns_t_rrsig:
767     return "RRSIG";
768   case ns_t_nsec:
769     return "NSEC";
770   case ns_t_dnskey:
771     return "DNSKEY";
772   case ns_t_dhcid:
773     return "DHCID";
774   case ns_t_nsec3:
775     return "NSEC3";
776   case ns_t_nsec3param:
777     return "NSEC3PARAM";
778   case ns_t_hip:
779     return "HIP";
780   case ns_t_spf:
781     return "SPF";
782   case ns_t_ixfr:
783     return "IXFR";
784 #endif
785   case ns_t_axfr:
786     return "AXFR";
787   case ns_t_mailb:
788     return "MAILB";
789   case ns_t_maila:
790     return "MAILA";
791   case ns_t_any:
792     return "ANY";
793 #if __NAMESER >= 19991006
794   case ns_t_zxfr:
795     return "ZXFR";
796 #endif
797 #if __NAMESER >= 20090302
798   case ns_t_dlv:
799     return "DLV";
800 #endif
801 /* #endif __NAMESER >= 19991001 */
802 #elif (defined(__BIND)) && (__BIND >= 19950621)
803   case T_A:
804     return "A"; /* 1 ... */
805   case T_NS:
806     return "NS";
807   case T_MD:
808     return "MD";
809   case T_MF:
810     return "MF";
811   case T_CNAME:
812     return "CNAME";
813   case T_SOA:
814     return "SOA";
815   case T_MB:
816     return "MB";
817   case T_MG:
818     return "MG";
819   case T_MR:
820     return "MR";
821   case T_NULL:
822     return "NULL";
823   case T_WKS:
824     return "WKS";
825   case T_PTR:
826     return "PTR";
827   case T_HINFO:
828     return "HINFO";
829   case T_MINFO:
830     return "MINFO";
831   case T_MX:
832     return "MX";
833   case T_TXT:
834     return "TXT";
835   case T_RP:
836     return "RP";
837   case T_AFSDB:
838     return "AFSDB";
839   case T_X25:
840     return "X25";
841   case T_ISDN:
842     return "ISDN";
843   case T_RT:
844     return "RT";
845   case T_NSAP:
846     return "NSAP";
847   case T_NSAP_PTR:
848     return "NSAP_PTR";
849   case T_SIG:
850     return "SIG";
851   case T_KEY:
852     return "KEY";
853   case T_PX:
854     return "PX";
855   case T_GPOS:
856     return "GPOS";
857   case T_AAAA:
858     return "AAAA";
859   case T_LOC:
860     return "LOC";
861   case T_NXT:
862     return "NXT";
863   case T_EID:
864     return "EID";
865   case T_NIMLOC:
866     return "NIMLOC";
867   case T_SRV:
868     return "SRV";
869   case T_ATMA:
870     return "ATMA";
871   case T_NAPTR:
872     return "NAPTR"; /* ... 35 */
873 #if (__BIND >= 19960801)
874   case T_KX:
875     return "KX"; /* 36 ... */
876   case T_CERT:
877     return "CERT";
878   case T_A6:
879     return "A6";
880   case T_DNAME:
881     return "DNAME";
882   case T_SINK:
883     return "SINK";
884   case T_OPT:
885     return "OPT";
886   case T_APL:
887     return "APL";
888   case T_DS:
889     return "DS";
890   case T_SSHFP:
891     return "SSHFP";
892   case T_RRSIG:
893     return "RRSIG";
894   case T_NSEC:
895     return "NSEC";
896   case T_DNSKEY:
897     return "DNSKEY"; /* ... 48 */
898   case T_TKEY:
899     return "TKEY"; /* 249 */
900 #endif /* __BIND >= 19960801 */
901   case T_TSIG:
902     return "TSIG"; /* 250 ... */
903   case T_IXFR:
904     return "IXFR";
905   case T_AXFR:
906     return "AXFR";
907   case T_MAILB:
908     return "MAILB";
909   case T_MAILA:
910     return "MAILA";
911   case T_ANY:
912     return "ANY"; /* ... 255 */
913 #endif /* __BIND >= 19950621 */
914   default:
915     snprintf(buf, sizeof(buf), "#%i", t);
916     return buf;
917   } /* switch (t) */
918 }
919
920 const char *opcode_str(int o) {
921   static char buf[30];
922   switch (o) {
923   case 0:
924     return "Query";
925   case 1:
926     return "Iquery";
927   case 2:
928     return "Status";
929   case 4:
930     return "Notify";
931   case 5:
932     return "Update";
933   default:
934     snprintf(buf, sizeof(buf), "Opcode%d", o);
935     return buf;
936   }
937 }
938
939 const char *rcode_str(int rcode) {
940   static char buf[32];
941   switch (rcode) {
942 #if (defined(__NAMESER)) && (__NAMESER >= 19991006)
943   case ns_r_noerror:
944     return "NOERROR";
945   case ns_r_formerr:
946     return "FORMERR";
947   case ns_r_servfail:
948     return "SERVFAIL";
949   case ns_r_nxdomain:
950     return "NXDOMAIN";
951   case ns_r_notimpl:
952     return "NOTIMPL";
953   case ns_r_refused:
954     return "REFUSED";
955   case ns_r_yxdomain:
956     return "YXDOMAIN";
957   case ns_r_yxrrset:
958     return "YXRRSET";
959   case ns_r_nxrrset:
960     return "NXRRSET";
961   case ns_r_notauth:
962     return "NOTAUTH";
963   case ns_r_notzone:
964     return "NOTZONE";
965   case ns_r_max:
966     return "MAX";
967   case ns_r_badsig:
968     return "BADSIG";
969   case ns_r_badkey:
970     return "BADKEY";
971   case ns_r_badtime:
972     return "BADTIME";
973 /* #endif __NAMESER >= 19991006 */
974 #elif (defined(__BIND)) && (__BIND >= 19950621)
975   case NOERROR:
976     return "NOERROR";
977   case FORMERR:
978     return "FORMERR";
979   case SERVFAIL:
980     return "SERVFAIL";
981   case NXDOMAIN:
982     return "NXDOMAIN";
983   case NOTIMP:
984     return "NOTIMP";
985   case REFUSED:
986     return "REFUSED";
987 #if defined(YXDOMAIN) && defined(NXRRSET)
988   case YXDOMAIN:
989     return "YXDOMAIN";
990   case YXRRSET:
991     return "YXRRSET";
992   case NXRRSET:
993     return "NXRRSET";
994   case NOTAUTH:
995     return "NOTAUTH";
996   case NOTZONE:
997     return "NOTZONE";
998 #endif /* RFC2136 rcodes */
999 #endif /* __BIND >= 19950621 */
1000   default:
1001     snprintf(buf, sizeof(buf), "RCode%i", rcode);
1002     return buf;
1003   }
1004 } /* const char *rcode_str (int rcode) */
1005
1006 #if 0
1007 static int
1008 main(int argc, char *argv[])
1009 {
1010     char errbuf[PCAP_ERRBUF_SIZE];
1011     int x;
1012     struct stat sb;
1013     int readfile_state = 0;
1014     struct bpf_program fp;
1015
1016     port53 = htons(53);
1017     SubReport = Sources_report;
1018     ignore_addr.s_addr = 0;
1019     progname = strdup(strrchr(argv[0], '/') ? strchr(argv[0], '/') + 1 : argv[0]);
1020     srandom(time(NULL));
1021     ResetCounters();
1022
1023     while ((x = getopt(argc, argv, "ab:f:i:pst")) != -1) {
1024         switch (x) {
1025         case 'a':
1026             anon_flag = 1;
1027             break;
1028         case 's':
1029             sld_flag = 1;
1030             break;
1031         case 't':
1032             nld_flag = 1;
1033             break;
1034         case 'p':
1035             promisc_flag = 0;
1036             break;
1037         case 'b':
1038             bpf_program_str = strdup(optarg);
1039             break;
1040         case 'i':
1041             ignore_addr.s_addr = inet_addr(optarg);
1042             break;
1043         case 'f':
1044             set_filter(optarg);
1045             break;
1046         default:
1047             usage();
1048             break;
1049         }
1050     }
1051     argc -= optind;
1052     argv += optind;
1053
1054     if (argc < 1)
1055         usage();
1056     device = strdup(argv[0]);
1057
1058     if (0 == stat(device, &sb))
1059         readfile_state = 1;
1060     if (readfile_state) {
1061         pcap_obj = pcap_open_offline(device, errbuf);
1062     } else {
1063         pcap_obj = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1000, errbuf);
1064     }
1065     if (NULL == pcap_obj) {
1066         fprintf(stderr, "pcap_open_*: %s\n", errbuf);
1067         exit(1);
1068     }
1069
1070     if (0 == isatty(1)) {
1071         if (0 == readfile_state) {
1072             fprintf(stderr, "Non-interactive mode requires savefile argument\n");
1073             exit(1);
1074         }
1075         interactive = 0;
1076         print_func = printf;
1077     }
1078
1079     memset(&fp, '\0', sizeof(fp));
1080     x = pcap_compile(pcap_obj, &fp, bpf_program_str, 1, 0);
1081     if (x < 0) {
1082         fprintf(stderr, "pcap_compile failed\n");
1083         exit(1);
1084     }
1085     x = pcap_setfilter(pcap_obj, &fp);
1086     if (x < 0) {
1087         fprintf(stderr, "pcap_setfilter failed\n");
1088         exit(1);
1089     }
1090
1091     /*
1092      * non-blocking call added for Mac OS X bugfix.  Sent by Max Horn.
1093      * ref http://www.tcpdump.org/lists/workers/2002/09/msg00033.html
1094      */
1095     x = pcap_setnonblock(pcap_obj, 1, errbuf);
1096     if (x < 0) {
1097         fprintf(stderr, "pcap_setnonblock failed: %s\n", errbuf);
1098         exit(1);
1099     }
1100
1101     switch (pcap_datalink(pcap_obj)) {
1102     case DLT_EN10MB:
1103         handle_datalink = handle_ether;
1104         break;
1105 #if HAVE_NET_IF_PPP_H
1106     case DLT_PPP:
1107         handle_datalink = handle_ppp;
1108         break;
1109 #endif
1110 #ifdef DLT_LOOP
1111     case DLT_LOOP:
1112         handle_datalink = handle_loop;
1113         break;
1114 #endif
1115 #ifdef DLT_RAW
1116     case DLT_RAW:
1117         handle_datalink = handle_raw;
1118         break;
1119 #endif
1120     case DLT_NULL:
1121         handle_datalink = handle_null;
1122         break;
1123     default:
1124         fprintf(stderr, "unsupported data link type %d\n",
1125             pcap_datalink(pcap_obj));
1126         return 1;
1127         break;
1128     }
1129     if (interactive) {
1130         init_curses();
1131         while (0 == Quit) {
1132             if (readfile_state < 2) {
1133                 /*
1134                  * On some OSes select() might return 0 even when
1135                  * there are packets to process.  Thus, we always
1136                  * ignore its return value and just call pcap_dispatch()
1137                  * anyway.
1138                  */
1139                 if (0 == readfile_state)        /* interactive */
1140                     pcap_select(pcap_obj, 1, 0);
1141                 x = pcap_dispatch(pcap_obj, 50, handle_pcap, NULL);
1142             }
1143             if (0 == x && 1 == readfile_state) {
1144                 /* block on keyboard until user quits */
1145                 readfile_state++;
1146                 nodelay(w, 0);
1147             }
1148             keyboard();
1149             cron_pre();
1150             report();
1151             cron_post();
1152         }
1153         endwin();               /* klin, Thu Nov 28 08:56:51 2002 */
1154     } else {
1155         while (pcap_dispatch(pcap_obj, 50, handle_pcap, NULL))
1156                 (void) 0;
1157         cron_pre();
1158         Sources_report(); print_func("\n");
1159         Destinatioreport(); print_func("\n");
1160         Qtypes_report(); print_func("\n");
1161         Opcodes_report(); print_func("\n");
1162         Tld_report(); print_func("\n");
1163         Sld_report(); print_func("\n");
1164         Nld_report(); print_func("\n");
1165         SldBySource_report();
1166     }
1167
1168     pcap_close(pcap_obj);
1169     return 0;
1170 } /* static int main(int argc, char *argv[]) */
1171 #endif