Merge branches 'ff/dns' and 'sh/email' into next
[collectd.git] / src / utils_dns.c
1 /*
2  * collectd - src/utils_dns.c
3  * Modifications 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 verplant.org>
34  */
35
36 #include "collectd.h"
37
38 #if HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41 #if HAVE_PCAP_H
42 # include <pcap.h>
43 #endif
44 #if HAVE_ARPA_INET_H
45 # include <arpa/inet.h>
46 #endif
47
48 #if HAVE_ARPA_NAMESER_H
49 # include <arpa/nameser.h>
50 #elif HAVE_ARPA_NAMESER_COMPAT_H
51 # include <arpa/nameser_compat.h>
52 #endif
53
54 #if HAVE_NET_IF_ARP_H
55 # include <net/if_arp.h>
56 #endif
57 #if HAVE_NET_IF_H
58 # include <net/if.h>
59 #endif
60 #if HAVE_NETINET_IF_ETHER_H
61 # include <netinet/if_ether.h>
62 #endif
63 #if HAVE_NET_IF_PPP_H
64 # include <net/if_ppp.h>
65 #endif
66
67 #if HAVE_SYS_SOCKET_H
68 # include <sys/socket.h>
69 #endif
70 #if HAVE_NETDB_H
71 # include <netdb.h>
72 #endif
73
74 #if HAVE_NETINET_IN_SYSTM_H
75 # include <netinet/in_systm.h>
76 #endif
77 #if HAVE_NETINET_IN_H
78 # include <netinet/in.h>
79 #endif
80 #if HAVE_NETINET_IP_H
81 # include <netinet/ip.h>
82 #endif
83 #ifdef HAVE_NETINET_IP_VAR_H
84 # include <netinet/ip_var.h>
85 #endif
86 #if HAVE_NETINET_IP6_H
87 # include <netinet/ip6.h>
88 #endif
89 #if HAVE_NETINET_UDP_H
90 # include <netinet/udp.h>
91 #endif
92
93 #define PCAP_SNAPLEN 1460
94 #ifndef ETHER_HDR_LEN
95 #define ETHER_ADDR_LEN 6
96 #define ETHER_TYPE_LEN 2
97 #define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
98 #endif
99 #ifndef ETHERTYPE_8021Q
100 # define ETHERTYPE_8021Q 0x8100
101 #endif
102 #ifndef ETHERTYPE_IPV6
103 # define ETHERTYPE_IPV6 0x86DD
104 #endif
105
106 #ifndef PPP_ADDRESS_VAL
107 # define PPP_ADDRESS_VAL 0xff   /* The address byte value */
108 #endif
109 #ifndef PPP_CONTROL_VAL
110 # define PPP_CONTROL_VAL 0x03   /* The control byte value */
111 #endif
112
113 #ifdef __linux__
114 #define uh_sport source
115 #define uh_dport dest
116 #endif
117
118 #include "utils_dns.h"
119
120 /*
121  * Type definitions
122  */
123 struct ip_list_s
124 {
125     struct in6_addr addr;
126     void *data;
127     struct ip_list_s *next;
128 };
129 typedef struct ip_list_s ip_list_t;
130
131 typedef int (printer)(const char *, ...);
132
133 /*
134  * flags/features for non-interactive mode
135  */
136
137 #ifndef T_A6
138 #define T_A6 38
139 #endif
140 #ifndef T_SRV
141 #define T_SRV 33
142 #endif
143
144 /*
145  * Global variables
146  */
147 int qtype_counts[T_MAX];
148 int opcode_counts[OP_MAX];
149 int qclass_counts[C_MAX];
150
151 #if HAVE_PCAP_H
152 static pcap_t *pcap_obj = NULL;
153 #endif
154
155 static ip_list_t *IgnoreList = NULL;
156
157 static void (*Callback) (const rfc1035_header_t *) = NULL;
158
159 static int query_count_intvl = 0;
160 static int query_count_total = 0;
161 #ifdef __OpenBSD__
162 static struct bpf_timeval last_ts;
163 #else
164 static struct timeval last_ts;
165 #endif
166
167 static int cmp_in6_addr (const struct in6_addr *a,
168         const struct in6_addr *b)
169 {
170     int i;
171
172     for (i = 0; i < 4; i++)
173         if (a->s6_addr32[i] != b->s6_addr32[i])
174             break;
175
176     if (i >= 4)
177         return (0);
178
179     return (a->s6_addr32[i] > b->s6_addr32[i] ? 1 : -1);
180 } /* int cmp_addrinfo */
181
182 static inline int ignore_list_match (const struct in6_addr *addr)
183 {
184     ip_list_t *ptr;
185
186     for (ptr = IgnoreList; ptr != NULL; ptr = ptr->next)
187         if (cmp_in6_addr (addr, &ptr->addr) == 0)
188             return (1);
189     return (0);
190 } /* int ignore_list_match */
191
192 static void ignore_list_add (const struct in6_addr *addr)
193 {
194     ip_list_t *new;
195
196     if (ignore_list_match (addr) != 0)
197         return;
198
199     new = malloc (sizeof (ip_list_t));
200     if (new == NULL)
201     {
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 {
214     struct addrinfo *ai_list;
215     struct addrinfo *ai_ptr;
216     struct in6_addr  addr;
217     int status;
218
219     status = getaddrinfo (name, NULL, NULL, &ai_list);
220     if (status != 0)
221         return;
222
223     for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
224     {
225         if (ai_ptr->ai_family == AF_INET)
226         {
227             addr.s6_addr32[0] = 0;
228             addr.s6_addr32[1] = 0;
229             addr.s6_addr32[2] = htonl (0x0000FFFF);
230             addr.s6_addr32[3] = ((struct sockaddr_in *) ai_ptr->ai_addr)->sin_addr.s_addr;
231
232             ignore_list_add (&addr);
233         }
234         else
235         {
236             ignore_list_add (&((struct sockaddr_in6 *) ai_ptr->ai_addr)->sin6_addr);
237         }
238     } /* for */
239
240     freeaddrinfo (ai_list);
241 }
242
243 static void in6_addr_from_buffer (struct in6_addr *ia,
244         const void *buf, size_t buf_len,
245         int family)
246 {
247     memset (ia, 0, sizeof (struct in6_addr));
248     if ((AF_INET == family) && (sizeof (uint32_t) == buf_len))
249     {
250         ia->s6_addr32[2] = htonl (0x0000FFFF);
251         ia->s6_addr32[3] = *((uint32_t *) buf);
252     }
253     else if ((AF_INET6 == family) && (sizeof (struct in6_addr) == buf_len))
254     {
255         memcpy (ia, buf, buf_len);
256     }
257 } /* void in6_addr_from_buffer */
258
259 #if HAVE_PCAP_H
260 void dnstop_set_pcap_obj (pcap_t *po)
261 {
262         pcap_obj = po;
263 }
264 #endif
265
266 void dnstop_set_callback (void (*cb) (const rfc1035_header_t *))
267 {
268         Callback = cb;
269 }
270
271 #define RFC1035_MAXLABELSZ 63
272 static int
273 rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
274 )
275 {
276     off_t no = 0;
277     unsigned char c;
278     size_t len;
279     assert(ns > 0);
280     do {
281         if ((*off) >= sz)
282             break;
283         c = *(buf + (*off));
284         if (c > 191) {
285             /* blasted compression */
286             unsigned short s;
287             off_t ptr;
288             memcpy(&s, buf + (*off), sizeof(s));
289             s = ntohs(s);
290             (*off) += sizeof(s);
291             /* Sanity check */
292             if ((*off) >= sz)
293                 return 1;
294             ptr = s & 0x3FFF;
295             /* Make sure the pointer is inside this message */
296             if (ptr >= sz)
297                 return 2;
298             return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
299         } else if (c > RFC1035_MAXLABELSZ) {
300             /*
301              * "(The 10 and 01 combinations are reserved for future use.)"
302              */
303             break;
304             return 3;
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)      /* message is too short */
313                 return 4;
314             memcpy(name + no, buf + (*off), len);
315             (*off) += len;
316             no += len;
317             *(name + (no++)) = '.';
318         }
319     } while (c > 0);
320     *(name + no - 1) = '\0';
321     /* make sure we didn't allow someone to overflow the name buffer */
322     assert(no <= ns);
323     return 0;
324 }
325
326 static int
327 handle_dns(const char *buf, int len,
328         const struct in6_addr *s_addr,
329         const struct in6_addr *d_addr)
330 {
331     rfc1035_header_t qh;
332     uint16_t us;
333     off_t offset;
334     char *t;
335     int x;
336
337     /* The DNS header is 12 bytes long */
338     if (len < 12)
339         return 0;
340
341     memcpy(&us, buf + 0, 2);
342     qh.id = ntohs(us);
343
344     memcpy(&us, buf + 2, 2);
345     us = ntohs(us);
346     fprintf (stderr, "Bytes 0, 1: 0x%04hx\n", us);
347     qh.qr = (us >> 15) & 0x01;
348     qh.opcode = (us >> 11) & 0x0F;
349     qh.aa = (us >> 10) & 0x01;
350     qh.tc = (us >> 9) & 0x01;
351     qh.rd = (us >> 8) & 0x01;
352     qh.ra = (us >> 7) & 0x01;
353     qh.z  = (us >> 6) & 0x01;
354     qh.ad = (us >> 5) & 0x01;
355     qh.cd = (us >> 4) & 0x01;
356     qh.rcode = us & 0x0F;
357
358     memcpy(&us, buf + 4, 2);
359     qh.qdcount = ntohs(us);
360
361     memcpy(&us, buf + 6, 2);
362     qh.ancount = ntohs(us);
363
364     memcpy(&us, buf + 8, 2);
365     qh.nscount = ntohs(us);
366
367     memcpy(&us, buf + 10, 2);
368     qh.arcount = ntohs(us);
369
370     offset = 12;
371     memset(qh.qname, '\0', MAX_QNAME_SZ);
372     x = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
373     if (0 != x)
374         return 0;
375     if ('\0' == qh.qname[0])
376         strcpy(qh.qname, ".");
377     while ((t = strchr(qh.qname, '\n')))
378         *t = ' ';
379     while ((t = strchr(qh.qname, '\r')))
380         *t = ' ';
381     for (t = qh.qname; *t; t++)
382         *t = tolower(*t);
383
384     memcpy(&us, buf + offset, 2);
385     qh.qtype = ntohs(us);
386     memcpy(&us, buf + offset + 2, 2);
387     qh.qclass = ntohs(us);
388
389     qh.length = (uint16_t) len;
390
391     /* gather stats */
392     qtype_counts[qh.qtype]++;
393     qclass_counts[qh.qclass]++;
394     opcode_counts[qh.opcode]++;
395
396     if (Callback != NULL)
397             Callback (&qh);
398
399     return 1;
400 }
401
402 static int
403 handle_udp(const struct udphdr *udp, int len,
404         const struct in6_addr *s_addr,
405         const struct in6_addr *d_addr)
406 {
407     char buf[PCAP_SNAPLEN];
408     if ((ntohs (udp->uh_dport) != 53)
409                     && (ntohs (udp->uh_sport) != 53))
410         return 0;
411     memcpy(buf, udp + 1, len - sizeof(*udp));
412     if (0 == handle_dns(buf, len - sizeof(*udp), s_addr, d_addr))
413         return 0;
414     return 1;
415 }
416
417 static int
418 handle_ipv6 (struct ip6_hdr *ipv6, int len)
419 {
420     char buf[PCAP_SNAPLEN];
421     int offset;
422     int nexthdr;
423
424     struct in6_addr s_addr;
425     struct in6_addr d_addr;
426     uint16_t payload_len;
427
428     offset = sizeof (struct ip6_hdr);
429     nexthdr = ipv6->ip6_nxt;
430     s_addr = ipv6->ip6_src;
431     d_addr = ipv6->ip6_dst;
432     payload_len = ntohs (ipv6->ip6_plen);
433
434     if (ignore_list_match (&s_addr))
435             return (0);
436
437     /* Parse extension headers. This only handles the standard headers, as
438      * defined in RFC 2460, correctly. Fragments are discarded. */
439     while ((IPPROTO_ROUTING == nexthdr) /* routing header */
440             || (IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */
441             || (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
442             || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
443             || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
444             || (IPPROTO_AH == nexthdr) /* destination options. */
445             || (IPPROTO_ESP == nexthdr)) /* encapsulating security payload. */
446     {
447         struct ip6_ext ext_hdr;
448         uint16_t ext_hdr_len;
449
450         /* Catch broken packets */
451         if ((offset + sizeof (struct ip6_ext)) > len)
452             return (0);
453
454         /* Cannot handle fragments. */
455         if (IPPROTO_FRAGMENT == nexthdr)
456             return (0);
457
458         memcpy (&ext_hdr, (char *) ipv6 + offset, sizeof (struct ip6_ext));
459         nexthdr = ext_hdr.ip6e_nxt;
460         ext_hdr_len = (8 * (ntohs (ext_hdr.ip6e_len) + 1));
461
462         /* This header is longer than the packets payload.. WTF? */
463         if (ext_hdr_len > payload_len)
464             return (0);
465
466         offset += ext_hdr_len;
467         payload_len -= ext_hdr_len;
468     } /* while */
469
470     /* Catch broken and empty packets */
471     if (((offset + payload_len) > len)
472             || (payload_len == 0)
473             || (payload_len > PCAP_SNAPLEN))
474         return (0);
475
476     if (IPPROTO_UDP != nexthdr)
477         return (0);
478
479     memcpy (buf, (char *) ipv6 + offset, payload_len);
480     if (handle_udp ((struct udphdr *) buf, payload_len, &s_addr, &d_addr) == 0)
481         return (0);
482
483     return (1); /* Success */
484 } /* int handle_ipv6 */
485
486 static int
487 handle_ip(const struct ip *ip, int len)
488 {
489     char buf[PCAP_SNAPLEN];
490     int offset = ip->ip_hl << 2;
491     struct in6_addr s_addr;
492     struct in6_addr d_addr;
493
494     if (ip->ip_v == 6)
495         return (handle_ipv6 ((struct ip6_hdr *) ip, len));
496
497     in6_addr_from_buffer (&s_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
498     in6_addr_from_buffer (&d_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
499     if (ignore_list_match (&s_addr))
500             return (0);
501     if (IPPROTO_UDP != ip->ip_p)
502         return 0;
503     memcpy(buf, (void *) ip + offset, len - offset);
504     if (0 == handle_udp((struct udphdr *) buf, len - offset, &s_addr, &d_addr))
505         return 0;
506     return 1;
507 }
508
509 static int
510 handle_ppp(const u_char * pkt, int len)
511 {
512     char buf[PCAP_SNAPLEN];
513     unsigned short us;
514     unsigned short proto;
515     if (len < 2)
516         return 0;
517     if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) {
518         pkt += 2;               /* ACFC not used */
519         len -= 2;
520     }
521     if (len < 2)
522         return 0;
523     if (*pkt % 2) {
524         proto = *pkt;           /* PFC is used */
525         pkt++;
526         len--;
527     } else {
528         memcpy(&us, pkt, sizeof(us));
529         proto = ntohs(us);
530         pkt += 2;
531         len -= 2;
532     }
533     if (ETHERTYPE_IP != proto && PPP_IP != proto)
534         return 0;
535     memcpy(buf, pkt, len);
536     return handle_ip((struct ip *) buf, len);
537 }
538
539 static int
540 handle_null(const u_char * pkt, int len)
541 {
542     unsigned int family;
543     memcpy(&family, pkt, sizeof(family));
544     if (AF_INET != family)
545         return 0;
546     return handle_ip((struct ip *) (pkt + 4), len - 4);
547 }
548
549 #ifdef DLT_LOOP
550 static int
551 handle_loop(const u_char * pkt, int len)
552 {
553     unsigned int family;
554     memcpy(&family, pkt, sizeof(family));
555     if (AF_INET != ntohl(family))
556         return 0;
557     return handle_ip((struct ip *) (pkt + 4), len - 4);
558 }
559
560 #endif
561
562 #ifdef DLT_RAW
563 static int
564 handle_raw(const u_char * pkt, int len)
565 {
566     return handle_ip((struct ip *) pkt, len);
567 }
568
569 #endif
570
571 static int
572 handle_ether(const u_char * pkt, int len)
573 {
574     char buf[PCAP_SNAPLEN];
575     struct ether_header *e = (void *) pkt;
576     unsigned short etype = ntohs(e->ether_type);
577     if (len < ETHER_HDR_LEN)
578         return 0;
579     pkt += ETHER_HDR_LEN;
580     len -= ETHER_HDR_LEN;
581     if (ETHERTYPE_8021Q == etype) {
582         etype = ntohs(*(unsigned short *) (pkt + 2));
583         pkt += 4;
584         len -= 4;
585     }
586     if ((ETHERTYPE_IP != etype)
587             && (ETHERTYPE_IPV6 != etype))
588         return 0;
589     memcpy(buf, pkt, len);
590     if (ETHERTYPE_IPV6 == etype)
591         return (handle_ipv6 ((struct ip6_hdr *) buf, len));
592     else
593         return handle_ip((struct ip *) buf, len);
594 }
595
596 /* public function */
597 #if HAVE_PCAP_H
598 void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt)
599 {
600     int status;
601
602     fprintf (stderr, "handle_pcap (udata = %p, hdr = %p, pkt = %p): hdr->caplen = %i\n",
603                     (void *) udata, (void *) hdr, (void *) pkt,
604                     hdr->caplen);
605
606     if (hdr->caplen < ETHER_HDR_LEN)
607         return;
608
609     switch (pcap_datalink (pcap_obj))
610     {
611         case DLT_EN10MB:
612             status = handle_ether (pkt, hdr->caplen);
613             break;
614         case DLT_PPP:
615             status = handle_ppp (pkt, hdr->caplen);
616             break;
617 #ifdef DLT_LOOP
618         case DLT_LOOP:
619             status = handle_loop (pkt, hdr->caplen);
620             break;
621 #endif
622 #ifdef DLT_RAW
623         case DLT_RAW:
624             status = handle_raw (pkt, hdr->caplen);
625             break;
626 #endif
627         case DLT_NULL:
628             status = handle_null (pkt, hdr->caplen);
629             break;
630
631         default:
632             fprintf (stderr, "unsupported data link type %d\n",
633                     pcap_datalink(pcap_obj));
634             status = 0;
635             break;
636     } /* switch (pcap_datalink(pcap_obj)) */
637
638     if (0 == status)
639         return;
640
641     query_count_intvl++;
642     query_count_total++;
643     last_ts = hdr->ts;
644 }
645 #endif
646
647 const char *qtype_str(int t)
648 {
649     static char buf[32];
650     switch (t) {
651             case ns_t_a:        return ("A");
652             case ns_t_ns:       return ("NS");
653             case ns_t_md:       return ("MD");
654             case ns_t_mf:       return ("MF");
655             case ns_t_cname:    return ("CNAME");
656             case ns_t_soa:      return ("SOA");
657             case ns_t_mb:       return ("MB");
658             case ns_t_mg:       return ("MG");
659             case ns_t_mr:       return ("MR");
660             case ns_t_null:     return ("NULL");
661             case ns_t_wks:      return ("WKS");
662             case ns_t_ptr:      return ("PTR");
663             case ns_t_hinfo:    return ("HINFO");
664             case ns_t_minfo:    return ("MINFO");
665             case ns_t_mx:       return ("MX");
666             case ns_t_txt:      return ("TXT");
667             case ns_t_rp:       return ("RP");
668             case ns_t_afsdb:    return ("AFSDB");
669             case ns_t_x25:      return ("X25");
670             case ns_t_isdn:     return ("ISDN");
671             case ns_t_rt:       return ("RT");
672             case ns_t_nsap:     return ("NSAP");
673             case ns_t_nsap_ptr: return ("NSAP-PTR");
674             case ns_t_sig:      return ("SIG");
675             case ns_t_key:      return ("KEY");
676             case ns_t_px:       return ("PX");
677             case ns_t_gpos:     return ("GPOS");
678             case ns_t_aaaa:     return ("AAAA");
679             case ns_t_loc:      return ("LOC");
680             case ns_t_nxt:      return ("NXT");
681             case ns_t_eid:      return ("EID");
682             case ns_t_nimloc:   return ("NIMLOC");
683             case ns_t_srv:      return ("SRV");
684             case ns_t_atma:     return ("ATMA");
685             case ns_t_naptr:    return ("NAPTR");
686             case ns_t_kx:       return ("KX");
687             case ns_t_cert:     return ("CERT");
688             case ns_t_a6:       return ("A6");
689             case ns_t_dname:    return ("DNAME");
690             case ns_t_sink:     return ("SINK");
691             case ns_t_opt:      return ("OPT");
692             case ns_t_tsig:     return ("TSIG");
693             case ns_t_ixfr:     return ("IXFR");
694             case ns_t_axfr:     return ("AXFR");
695             case ns_t_mailb:    return ("MAILB");
696             case ns_t_maila:    return ("MAILA");
697             case ns_t_any:      return ("ANY");
698             case ns_t_zxfr:     return ("ZXFR");
699             default:
700                     snprintf (buf, 32, "#%i", t);
701                     buf[31] = '\0';
702                     return (buf);
703     }; /* switch (t) */
704     /* NOTREACHED */
705     return (NULL);
706 }
707
708 const char *opcode_str (int o)
709 {
710     static char buf[30];
711     switch (o) {
712     case 0:
713         return "Query";
714         break;
715     case 1:
716         return "Iquery";
717         break;
718     case 2:
719         return "Status";
720         break;
721     case 4:
722         return "Notify";
723         break;
724     case 5:
725         return "Update";
726         break;
727     default:
728         snprintf(buf, 30, "Opcode%d", o);
729         return buf;
730     }
731     /* NOTREACHED */
732 }
733
734 const char *rcode_str (int rcode)
735 {
736         static char buf[32];
737         switch (rcode)
738         {
739                 case ns_r_noerror:  return ("NOERROR");
740                 case ns_r_formerr:  return ("FORMERR");
741                 case ns_r_servfail: return ("SERVFAIL");
742                 case ns_r_nxdomain: return ("NXDOMAIN");
743                 case ns_r_notimpl:  return ("NOTIMPL");
744                 case ns_r_refused:  return ("REFUSED");
745                 case ns_r_yxdomain: return ("YXDOMAIN");
746                 case ns_r_yxrrset:  return ("YXRRSET");
747                 case ns_r_nxrrset:  return ("NXRRSET");
748                 case ns_r_notauth:  return ("NOTAUTH");
749                 case ns_r_notzone:  return ("NOTZONE");
750                 case ns_r_max:      return ("MAX");
751                 case ns_r_badsig:   return ("BADSIG");
752                 case ns_r_badkey:   return ("BADKEY");
753                 case ns_r_badtime:  return ("BADTIME");
754                 default:
755                         snprintf (buf, 32, "RCode%i", rcode);
756                         buf[31] = '\0';
757                         return (buf);
758         }
759         /* Never reached */
760         return (NULL);
761 } /* const char *rcode_str (int rcode) */
762
763 #if 0
764 static int
765 main(int argc, char *argv[])
766 {
767     char errbuf[PCAP_ERRBUF_SIZE];
768     int x;
769     struct stat sb;
770     int readfile_state = 0;
771     struct bpf_program fp;
772
773     port53 = htons(53);
774     SubReport = Sources_report;
775     ignore_addr.s_addr = 0;
776     progname = strdup(strrchr(argv[0], '/') ? strchr(argv[0], '/') + 1 : argv[0]);
777     srandom(time(NULL));
778     ResetCounters();
779
780     while ((x = getopt(argc, argv, "ab:f:i:pst")) != -1) {
781         switch (x) {
782         case 'a':
783             anon_flag = 1;
784             break;
785         case 's':
786             sld_flag = 1;
787             break;
788         case 't':
789             nld_flag = 1;
790             break;
791         case 'p':
792             promisc_flag = 0;
793             break;
794         case 'b':
795             bpf_program_str = strdup(optarg);
796             break;
797         case 'i':
798             ignore_addr.s_addr = inet_addr(optarg);
799             break;
800         case 'f':
801             set_filter(optarg);
802             break;
803         default:
804             usage();
805             break;
806         }
807     }
808     argc -= optind;
809     argv += optind;
810
811     if (argc < 1)
812         usage();
813     device = strdup(argv[0]);
814
815     if (0 == stat(device, &sb))
816         readfile_state = 1;
817     if (readfile_state) {
818         pcap_obj = pcap_open_offline(device, errbuf);
819     } else {
820         pcap_obj = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1000, errbuf);
821     }
822     if (NULL == pcap_obj) {
823         fprintf(stderr, "pcap_open_*: %s\n", errbuf);
824         exit(1);
825     }
826
827     if (0 == isatty(1)) {
828         if (0 == readfile_state) {
829             fprintf(stderr, "Non-interactive mode requires savefile argument\n");
830             exit(1);
831         }
832         interactive = 0;
833         print_func = printf;
834     }
835
836     memset(&fp, '\0', sizeof(fp));
837     x = pcap_compile(pcap_obj, &fp, bpf_program_str, 1, 0);
838     if (x < 0) {
839         fprintf(stderr, "pcap_compile failed\n");
840         exit(1);
841     }
842     x = pcap_setfilter(pcap_obj, &fp);
843     if (x < 0) {
844         fprintf(stderr, "pcap_setfilter failed\n");
845         exit(1);
846     }
847
848     /*
849      * non-blocking call added for Mac OS X bugfix.  Sent by Max Horn.
850      * ref http://www.tcpdump.org/lists/workers/2002/09/msg00033.html
851      */
852     x = pcap_setnonblock(pcap_obj, 1, errbuf);
853     if (x < 0) {
854         fprintf(stderr, "pcap_setnonblock failed: %s\n", errbuf);
855         exit(1);
856     }
857
858     switch (pcap_datalink(pcap_obj)) {
859     case DLT_EN10MB:
860         handle_datalink = handle_ether;
861         break;
862 #if USE_PPP
863     case DLT_PPP:
864         handle_datalink = handle_ppp;
865         break;
866 #endif
867 #ifdef DLT_LOOP
868     case DLT_LOOP:
869         handle_datalink = handle_loop;
870         break;
871 #endif
872 #ifdef DLT_RAW
873     case DLT_RAW:
874         handle_datalink = handle_raw;
875         break;
876 #endif
877     case DLT_NULL:
878         handle_datalink = handle_null;
879         break;
880     default:
881         fprintf(stderr, "unsupported data link type %d\n",
882             pcap_datalink(pcap_obj));
883         return 1;
884         break;
885     }
886     if (interactive) {
887         init_curses();
888         while (0 == Quit) {
889             if (readfile_state < 2) {
890                 /*
891                  * On some OSes select() might return 0 even when
892                  * there are packets to process.  Thus, we always
893                  * ignore its return value and just call pcap_dispatch()
894                  * anyway.
895                  */
896                 if (0 == readfile_state)        /* interactive */
897                     pcap_select(pcap_obj, 1, 0);
898                 x = pcap_dispatch(pcap_obj, 50, handle_pcap, NULL);
899             }
900             if (0 == x && 1 == readfile_state) {
901                 /* block on keyboard until user quits */
902                 readfile_state++;
903                 nodelay(w, 0);
904             }
905             keyboard();
906             cron_pre();
907             report();
908             cron_post();
909         }
910         endwin();               /* klin, Thu Nov 28 08:56:51 2002 */
911     } else {
912         while (pcap_dispatch(pcap_obj, 50, handle_pcap, NULL))
913                 (void) 0;
914         cron_pre();
915         Sources_report(); print_func("\n");
916         Destinatioreport(); print_func("\n");
917         Qtypes_report(); print_func("\n");
918         Opcodes_report(); print_func("\n");
919         Tld_report(); print_func("\n");
920         Sld_report(); print_func("\n");
921         Nld_report(); print_func("\n");
922         SldBySource_report();
923     }
924
925     pcap_close(pcap_obj);
926     return 0;
927 } /* static int main(int argc, char *argv[]) */
928 #endif