1 /*
2  * Copyright (c) 2016-2021, OARC, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 
37 #include "args.h"
38 #include "endpoint.h"
39 #include "iaddr.h"
40 #include "log.h"
41 #include "tcpstate.h"
42 #include "network.h"
43 
44 #include <ldns/ldns.h>
45 
46 /*
47  * OpenBSD and Debian Stretch i386 need file local functions for export
48  * to loaded modules, so use this for all platforms.
49  */
_tcpstate_getcurr(void)50 void* _tcpstate_getcurr(void)
51 {
52     return (void*)tcpstate_getcurr();
53 }
54 
_tcpstate_reset(void * tcpstate,const char * msg)55 void _tcpstate_reset(void* tcpstate, const char* msg)
56 {
57     tcpstate_reset((tcpstate_ptr)tcpstate, msg);
58 }
59 
_ia_str(iaddr ia)60 const char* _ia_str(iaddr ia)
61 {
62     return ia_str(ia);
63 }
64 
65 extern struct ip6_hdr* network_ipv6;
66 extern struct ip*      network_ip;
67 extern struct udphdr*  network_udp;
68 
set_iaddr(iaddr * from,iaddr * to)69 void set_iaddr(iaddr* from, iaddr* to)
70 {
71     if (from) {
72         switch (from->af) {
73         case AF_INET:
74             if (network_ip) {
75                 memcpy(&network_ip->ip_src, &from->u.a4, sizeof(struct in_addr));
76             }
77             break;
78         case AF_INET6:
79             if (network_ipv6) {
80                 memcpy(&network_ipv6->ip6_src, &from->u.a6, sizeof(struct in6_addr));
81             }
82             break;
83         default:
84             from = 0;
85             break;
86         }
87     }
88     if (to) {
89         switch (to->af) {
90         case AF_INET:
91             if (network_ip) {
92                 memcpy(&network_ip->ip_dst, &to->u.a4, sizeof(struct in_addr));
93             }
94             break;
95         case AF_INET6:
96             if (network_ipv6) {
97                 memcpy(&network_ipv6->ip6_dst, &to->u.a6, sizeof(struct in6_addr));
98             }
99             break;
100         default:
101             to = 0;
102             break;
103         }
104     }
105     if (from || to) {
106         if (network_ip) {
107             network_ip->ip_sum = 0;
108             network_ip->ip_sum = ~in_checksum((u_char*)network_ip, sizeof *network_ip);
109         }
110         if (network_udp) {
111             network_udp->uh_sum = 0;
112         }
113     }
114 }
115 
116 #ifdef __linux__
117 extern char* strptime(const char*, const char*, struct tm*);
118 #endif
119 
xtimegm(struct tm * tmp)120 time_t xtimegm(struct tm* tmp)
121 {
122 #if defined(__SVR4) && defined(__sun)
123     char tz[3] = "TZ=";
124     putenv((char*)tz);
125     return mktime(tmp);
126 #else
127     return timegm(tmp);
128 #endif
129 }
130 
usage(const char * msg)131 void usage(const char* msg)
132 {
133     struct plugin* p;
134 
135     fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
136     fprintf(stderr, "\n");
137 
138     help_1();
139 
140     for (p = HEAD(plugins); p != NULL; p = NEXT(p, link))
141         if (p->usage)
142             (*p->usage)();
143 
144     fprintf(stderr,
145         "\nnote: the -? or -\\? option will display full help text\n");
146 
147     exit(1);
148 }
149 
help_1(void)150 void help_1(void)
151 {
152     fprintf(stderr, "%s: version %s\n\n", ProgramName, PACKAGE_VERSION);
153     fprintf(stderr,
154         "usage: %s\n"
155         "  [-?VbNpd1gfTI"
156 #ifdef USE_SECCOMP
157         "y"
158 #endif
159         "SMD] [-o option=value]+\n"
160         "  [-i <if>]+ [-r <file>]+ [-l <vlan>]+ [-L <vlan>]+\n"
161         "  [-u <port>] [-m [qun]] [-e [nytfsxir]] [-h [ir]] [-s [ir]]\n"
162         "  [-a <host>]+ [-z <host>]+ [-A <host>]+ [-Z <host>]+ [-Y <host>]+\n"
163         "  [-w <base> [-W <suffix>] [-k <cmd>] -F <format>]\n"
164         "  [-t <lim>] [-c <lim>] [-C <lim>]\n"
165         "  [-x <pat>]+ [-X <pat>]+\n"
166         "  [-B <datetime>] [-E <datetime>]\n"
167         "  [-U <str>] [-q <num|str>] [-Q <num|str>]\n"
168         "  [-P plugin.so <plugin options...>]\n",
169         ProgramName);
170 }
171 
help_2(void)172 void help_2(void)
173 {
174     help_1();
175     fprintf(stderr,
176         "\noptions:\n"
177         "  -? or -\\?  print these instructions and exit\n"
178         "  -V         print version and exit\n"
179         "  -o opt=val extended options, see man page for list of options\n"
180         "  -b         run in background as daemon\n"
181         "  -N         do not attempt to drop privileges, this is implicit\n"
182         "             if only reading offline pcap files\n"
183         "  -p         do not put interface in promiscuous mode\n"
184         "  -d         dump verbose trace information to stderr, specify multiple\n"
185         "             times to increase debugging\n"
186         "  -1         flush output on every packet\n"
187         "  -g         dump packets dig-style on stderr\n"
188         "  -f         include fragmented packets\n"
189         "  -T         include TCP packets (DNS header filters will inspect only the\n"
190         "             first DNS header, and the result will apply to all messages\n"
191         "             in the TCP stream; DNS payload filters will not be applied.)\n"
192         "  -I         include ICMP and ICMPv6 packets\n"
193         "  -i <if>    select this live interface(s)\n"
194         "  -r <file>  read this pcap file\n"
195         "  -l <vlan>  select only these vlan(s) (4095 for all)\n"
196         "  -L <vlan>  select these vlan(s) and non-VLAN frames (4095 for all)\n"
197         "  -u <port>  dns port (default: 53)\n"
198         "  -m [qun]   select messages: query, update, notify\n"
199         "  -e [nytfsxir] select error/response code\n"
200         "                 n = no error\n"
201         "                 y = any error\n"
202         "                 t = truncated response\n"
203         "                 f = format error (rcode 1)\n"
204         "                 s = server failure (rcode 2)\n"
205         "                 x = nxdomain (rcode 3)\n"
206         "                 i = not implemented (rcode 4)\n"
207         "                 r = refused (rcode 5)\n"
208         "  -h [ir]    hide initiators and/or responders\n"
209         "  -s [ir]    select sides: initiations, responses\n"
210         "  -a <host>  want messages from these initiator(s)\n"
211         "  -z <host>  want messages from these responder(s)\n"
212         "  -A <host>  want messages NOT to/from these initiator(s)\n"
213         "  -Z <host>  want messages NOT to/from these responder(s)\n"
214         "  -Y <host>  drop responses from these responder(s)\n"
215         "  -w <base>  dump to <base>.<timesec>.<timeusec>\n"
216         "  -W <suffix> add suffix to dump file name, e.g. '.pcap'\n"
217         "  -k <cmd>   kick off <cmd> when each dump closes\n"
218         "  -F <format> dump format: pcap (default), cbor, cds\n"
219         "  -t <lim>   close dump or exit every/after <lim> secs\n"
220         "  -c <lim>   close dump or exit every/after <lim> pkts\n"
221         "  -C <lim>   close dump or exit every/after <lim> bytes captured\n"
222         "  -x <pat>   select messages matching regex <pat>\n"
223         "  -X <pat>   select messages not matching regex <pat>\n"
224 #ifdef USE_SECCOMP
225         "  -y         enable seccomp-bpf\n"
226 #endif
227         "  -S         show summarized statistics\n"
228         "  -B <datetime> begin collecting at this date and time\n"
229         "  -E <datetime> end collecting at this date and time\n"
230         "  -M         set monitor mode on interfaces\n"
231         "  -D         set immediate mode on interfaces\n"
232         "  -U <str>   append 'and <str>' to the pcap filter\n"
233         "  -q <num|str> select messages based on QTYPE\n"
234         "  -Q <num|str> filter out messages based on QTYPE\n"
235         "  -P <plugin.so> load plugin, any argument after this is sent to the plugin!\n");
236 }
237 
check_gzip()238 void check_gzip()
239 {
240     char* dot = strrchr(dump_suffix, '.');
241     if (dot) {
242         wantgzip = (strcmp(dot, ".gz") == 0) ? TRUE : FALSE;
243     }
244 
245 #if !(HAVE_GZOPEN && (HAVE_FUNOPEN || HAVE_FOPENCOOKIE))
246     if (wantgzip) {
247         fprintf(stderr, "error: gzip compression requested but not supported\n");
248         exit(1);
249     }
250 #endif
251 }
252 
is_responder(iaddr ia)253 int is_responder(iaddr ia)
254 {
255     if (EMPTY(responders))
256         return 1;
257     if (ep_present(&responders, ia))
258         return 1;
259     return 0;
260 }
261 
parse_args(int argc,char * argv[])262 void parse_args(int argc, char* argv[])
263 {
264     mypcap_ptr    mypcap;
265     unsigned long ul;
266     vlan_ptr      vlan;
267     unsigned      u;
268     int           ch;
269     char *        p, *match_qtype_arg = 0;
270 
271     if ((p = strrchr(argv[0], '/')) == NULL)
272         ProgramName = argv[0];
273     else
274         ProgramName = p + 1;
275     INIT_LIST(vlans_incl);
276     INIT_LIST(vlans_excl);
277     INIT_LIST(mypcaps);
278     INIT_LIST(initiators);
279     INIT_LIST(responders);
280     INIT_LIST(not_initiators);
281     INIT_LIST(not_responders);
282     INIT_LIST(drop_responders);
283     INIT_LIST(myregexes);
284     INIT_LIST(plugins);
285     while ((ch = getopt(argc, argv,
286                 "a:bc:de:fgh:i:k:l:m:o:pr:s:t:u:w:x:yz:q:"
287                 "A:B:C:DE:F:IL:MNP:STU:VW:X:Y:Z:Q:1?"))
288            != EOF) {
289         switch (ch) {
290         case 'o':
291             if (option_parse(&options, optarg)) {
292                 fprintf(stderr, "%s: unknown or invalid extended -o option: %s\n", ProgramName, optarg);
293                 exit(1);
294             }
295             break;
296         case 'b':
297             background = TRUE;
298             break;
299         case 'N':
300             dont_drop_privileges = TRUE;
301             break;
302         case 'p':
303             promisc = FALSE;
304             break;
305         case 'd':
306             dumptrace++;
307             break;
308         case '1':
309             flush = TRUE;
310             break;
311         case 'g':
312             preso = TRUE;
313             break;
314         case 'f':
315             wantfrags = TRUE;
316             break;
317         case 'I':
318             wanticmp = TRUE;
319             break;
320         case 'V':
321             printf("%s version %s\n", ProgramName, PACKAGE_VERSION);
322             exit(0);
323         case 'i':
324             if (pcap_offline != NULL)
325                 usage("-i makes no sense after -r");
326             mypcap = calloc(1, sizeof *mypcap);
327             assert(mypcap != NULL);
328             INIT_LINK(mypcap, link);
329             mypcap->name = strdup(optarg);
330             assert(mypcap->name != NULL);
331             APPEND(mypcaps, mypcap, link);
332             break;
333         case 'r':
334             if (!EMPTY(mypcaps))
335                 usage("-r makes no sense after -i");
336             pcap_offline = calloc(1, sizeof *pcap_offline);
337             assert(pcap_offline != NULL);
338             INIT_LINK(pcap_offline, link);
339             pcap_offline->name = strdup(optarg);
340             assert(pcap_offline->name != NULL);
341             APPEND(mypcaps, pcap_offline, link);
342             only_offline_pcaps = TRUE;
343             break;
344         case 'l':
345             ul = strtoul(optarg, &p, 0);
346             if (*p != '\0' || ul > MAX_VLAN)
347                 usage("-l vlan must be an integer 0..4095");
348             vlan = calloc(1, sizeof *vlan);
349             assert(vlan != NULL);
350             INIT_LINK(vlan, link);
351             vlan->vlan = (unsigned)ul;
352             APPEND(vlans_excl, vlan, link);
353             if (0 == ul)
354                 fprintf(stderr, "Warning: previous versions of %s "
355                                 "interpreted 0 as all VLANs. "
356                                 "If you want all VLANs now you must "
357                                 "specify %u.\n",
358                     ProgramName, MAX_VLAN);
359             break;
360         case 'L':
361             ul = strtoul(optarg, &p, 0);
362             if (*p != '\0' || ul > MAX_VLAN)
363                 usage("-L vlan must be an integer 0..4095");
364             vlan = calloc(1, sizeof *vlan);
365             assert(vlan != NULL);
366             INIT_LINK(vlan, link);
367             vlan->vlan = (unsigned)ul;
368             APPEND(vlans_incl, vlan, link);
369             if (0 == ul)
370                 fprintf(stderr, "Warning: previous versions of %s "
371                                 "interpreted 0 as all VLANs. "
372                                 "If you want all VLANs now you must "
373                                 "specify %u.\n",
374                     ProgramName, MAX_VLAN);
375             break;
376         case 'T':
377             wanttcp = TRUE;
378             break;
379         case 'u':
380             ul = strtoul(optarg, &p, 0);
381             if (*p != '\0' || ul < 1U || ul > 65535U)
382                 usage("port must be an integer 1..65535");
383             dns_port = (unsigned)ul;
384             break;
385         case 'm':
386             u = 0;
387             for (p = optarg; *p; p++)
388                 switch (*p) {
389                 case 'q':
390                     u |= MSG_QUERY;
391                     break;
392                 case 'u':
393                     u |= MSG_UPDATE;
394                     break;
395                 case 'n':
396                     u |= MSG_NOTIFY;
397                     break;
398                 default:
399                     usage("-m takes only [qun]");
400                 }
401             msg_wanted = u;
402             break;
403         case 's':
404             u = 0;
405             for (p = optarg; *p; p++)
406                 switch (*p) {
407                 case 'i':
408                     u |= DIR_INITIATE;
409                     break;
410                 case 'r':
411                     u |= DIR_RESPONSE;
412                     break;
413                 default:
414                     usage("-s takes only [ir]");
415                 }
416             dir_wanted = u;
417             break;
418         case 'h':
419             u = 0;
420             for (p = optarg; *p; p++)
421                 switch (*p) {
422                 case 'i':
423                     u |= END_INITIATOR;
424                     break;
425                 case 'r':
426                     u |= END_RESPONDER;
427                     break;
428                 default:
429                     usage("-h takes only [ir]");
430                 }
431             end_hide = u;
432             break;
433         case 'e':
434             u = 0;
435             for (p = optarg; *p; p++)
436                 switch (*p) {
437                 case 'n':
438                     u |= ERR_NO;
439                     break;
440                 case 'y':
441                     u |= ERR_YES;
442                     break;
443                 case 't':
444                     u |= ERR_TRUNC;
445                     break;
446                 case 'f':
447                     u |= ERR_FORMERR;
448                     break;
449                 case 's':
450                     u |= ERR_SERVFAIL;
451                     break;
452                 case 'x':
453                     u |= ERR_NXDOMAIN;
454                     break;
455                 case 'i':
456                     u |= ERR_NOTIMPL;
457                     break;
458                 case 'r':
459                     u |= ERR_REFUSED;
460                     break;
461                 default:
462                     usage("-e takes only [nytfsxir]");
463                 }
464             err_wanted = u;
465             break;
466         case 'a':
467             endpoint_arg(&initiators, optarg);
468             break;
469         case 'z':
470             endpoint_arg(&responders, optarg);
471             break;
472         case 'A':
473             endpoint_arg(&not_initiators, optarg);
474             break;
475         case 'Z':
476             endpoint_arg(&not_responders, optarg);
477             break;
478         case 'Y':
479             endpoint_arg(&drop_responders, optarg);
480             break;
481         case 'w':
482             dump_base = optarg;
483             if (strcmp(optarg, "-") == 0)
484                 dump_type = to_stdout;
485             else
486                 dump_type = to_file;
487             break;
488         case 'W':
489             if (dump_suffix)
490                 free(dump_suffix);
491             dump_suffix = strdup(optarg);
492             check_gzip();
493             break;
494         case 'k':
495             if (dump_type != to_file)
496                 usage("-k depends on -w"
497                       " (note: can't be stdout)");
498             kick_cmd = optarg;
499             break;
500         case 'F':
501             if (!strcmp(optarg, "pcap")) {
502                 options.dump_format = pcap;
503             } else if (!strcmp(optarg, "cbor")) {
504                 options.dump_format = cbor;
505             } else if (!strcmp(optarg, "cds")) {
506                 options.dump_format = cds;
507             } else {
508                 usage("invalid output format for -F");
509             }
510             break;
511         case 't':
512             ul = strtoul(optarg, &p, 0);
513             if (*p != '\0')
514                 usage("argument to -t must be an integer");
515             limit_seconds = (unsigned)ul;
516             break;
517         case 'c':
518             ul = strtoul(optarg, &p, 0);
519             if (*p != '\0')
520                 usage("argument to -c must be an integer");
521             limit_packets = (unsigned)ul;
522             break;
523         case 'C':
524             ul = strtoul(optarg, &p, 0);
525             if (*p != '\0')
526                 usage("argument to -C must be an integer");
527             limit_pcapfilesize = (unsigned)ul;
528             break;
529         case 'x':
530         /* FALLTHROUGH */
531         case 'X': {
532             int         i;
533             myregex_ptr myregex = calloc(1, sizeof *myregex);
534             assert(myregex != NULL);
535             INIT_LINK(myregex, link);
536             myregex->str = strdup(optarg);
537             i            = regcomp(&myregex->reg, myregex->str, REGEX_CFLAGS);
538             if (i != 0) {
539                 regerror(i, &myregex->reg,
540                     errbuf, sizeof errbuf);
541                 usage(errbuf);
542             }
543             myregex->not = (ch == 'X');
544             APPEND(myregexes, myregex, link);
545         } break;
546         case 'B': {
547             struct tm tm;
548             memset(&tm, '\0', sizeof(tm));
549             if (NULL == strptime(optarg, "%F %T", &tm))
550                 usage("-B arg must have format YYYY-MM-DD HH:MM:SS");
551             start_time = xtimegm(&tm);
552         } break;
553         case 'E': {
554             struct tm tm;
555             memset(&tm, '\0', sizeof(tm));
556             if (NULL == strptime(optarg, "%F %T", &tm))
557                 usage("-E arg must have format YYYY-MM-DD HH:MM:SS");
558             stop_time = xtimegm(&tm);
559         } break;
560         case 'S':
561             print_pcap_stats = TRUE;
562             break;
563         case 'P': {
564             char*          fn = strdup(optarg);
565             char*          t;
566             char           sn[256];
567             struct plugin* p = calloc(1, sizeof(*p));
568             assert(p != NULL);
569             INIT_LINK(p, link);
570             t       = strrchr(fn, '/');
571             p->name = strdup(t ? t + 1 : fn);
572             if ((t = strstr(p->name, ".so")))
573                 *t = 0;
574             p->handle = dlopen(fn, RTLD_NOW);
575             if (!p->handle) {
576                 logerr("%s: %s", fn, dlerror());
577                 exit(1);
578             }
579             snprintf(sn, sizeof(sn), "%s_type", p->name);
580             p->type = dlsym(p->handle, sn);
581             if (p->type) {
582                 p->pt = (*p->type)();
583                 switch (p->pt) {
584                 case plugin_output:
585                 case plugin_filter:
586                     break;
587                 default:
588                     logerr("invalid plugin type for plugin '%s'", p->name);
589                     exit(1);
590                 }
591             } else {
592                 p->pt = plugin_output;
593             }
594             snprintf(sn, sizeof(sn), "%s_start", p->name);
595             p->start = dlsym(p->handle, sn);
596             snprintf(sn, sizeof(sn), "%s_stop", p->name);
597             p->stop = dlsym(p->handle, sn);
598             snprintf(sn, sizeof(sn), "%s_open", p->name);
599             p->open = dlsym(p->handle, sn);
600             snprintf(sn, sizeof(sn), "%s_close", p->name);
601             p->close = dlsym(p->handle, sn);
602             snprintf(sn, sizeof(sn), "%s_output", p->name);
603             p->output = dlsym(p->handle, sn);
604             if (p->pt == plugin_output && !p->output) {
605                 logerr("%s", dlerror());
606                 exit(1);
607             }
608             snprintf(sn, sizeof(sn), "%s_filter", p->name);
609             p->filter = dlsym(p->handle, sn);
610             if (p->pt == plugin_filter && !p->filter) {
611                 logerr("%s", dlerror());
612                 exit(1);
613             }
614             snprintf(sn, sizeof(sn), "%s_usage", p->name);
615             p->usage = dlsym(p->handle, sn);
616             snprintf(sn, sizeof(sn), "%s_extension", p->name);
617             p->extension = dlsym(p->handle, sn);
618             if (p->extension) {
619                 (*p->extension)(DNSCAP_EXT_IS_RESPONDER, (void*)is_responder);
620                 (*p->extension)(DNSCAP_EXT_IA_STR, (void*)_ia_str);
621                 (*p->extension)(DNSCAP_EXT_TCPSTATE_GETCURR, (void*)_tcpstate_getcurr);
622                 (*p->extension)(DNSCAP_EXT_TCPSTATE_RESET, (void*)_tcpstate_reset);
623                 (*p->extension)(DNSCAP_EXT_SET_IADDR, (void*)set_iaddr);
624             }
625             snprintf(sn, sizeof(sn), "%s_getopt", p->name);
626             p->getopt = dlsym(p->handle, sn);
627             if (p->getopt)
628                 (*p->getopt)(&argc, &argv);
629             APPEND(plugins, p, link);
630             if (dumptrace)
631                 fprintf(stderr, "Plugin '%s' loaded\n", p->name);
632             free(fn);
633         } break;
634         case 'U':
635             if (extra_bpf)
636                 free(extra_bpf);
637             extra_bpf = strdup(optarg);
638             break;
639         case 'y':
640 #ifdef USE_SECCOMP
641             use_seccomp = TRUE;
642             break;
643 #else
644             usage("-y: seccomp-bpf not enabled");
645 #endif
646         case 'M':
647             monitor_mode = TRUE;
648             break;
649         case 'D':
650             immediate_mode = TRUE;
651             break;
652         case 'q': {
653             if (nmatch_qtype) {
654                 usage("-q and -Q can't be used together");
655             }
656             free(match_qtype_arg); // fix clang scan-build
657             match_qtype_arg = strdup(optarg);
658             match_qtype     = ldns_get_rr_type_by_name(optarg);
659             if (!match_qtype) {
660                 ul = strtoul(optarg, &p, 0);
661                 if (*p != '\0' || ul < 1U || ul > 65535U)
662                     usage("-q QTYPE must be a valid type or an integer 1..65535");
663                 match_qtype = (ldns_rr_type)ul;
664             }
665             break;
666         }
667         case 'Q': {
668             if (match_qtype) {
669                 usage("-q and -Q can't be used together");
670             }
671             free(match_qtype_arg); // fix clang scan-build
672             match_qtype_arg = strdup(optarg);
673             nmatch_qtype    = ldns_get_rr_type_by_name(optarg);
674             if (!nmatch_qtype) {
675                 ul = strtoul(optarg, &p, 0);
676                 if (*p != '\0' || ul < 1U || ul > 65535U)
677                     usage("-Q QTYPE must be a valid type or an integer 1..65535");
678                 nmatch_qtype = (ldns_rr_type)ul;
679             }
680             break;
681         }
682         case '?':
683             if (!optopt || optopt == '?') {
684                 help_2();
685                 options_free(&options);
686                 exit(0);
687             }
688             // fallthrough
689         default:
690             usage("unrecognized command line option");
691         }
692     }
693     assert(msg_wanted != 0U);
694     assert(err_wanted != 0U);
695     if (dump_type != nowhere && options.use_layers)
696         usage("use_layers is only compatible with -g so far");
697     if (dump_type == nowhere && !preso && EMPTY(plugins))
698         usage("without -w or -g, there would be no output");
699     if (end_hide != 0U && wantfrags)
700         usage("the -h and -f options are incompatible");
701     if (!EMPTY(vlans_incl) && !EMPTY(vlans_excl))
702         usage("the -L and -l options are mutually exclusive");
703     if (background && (dumptrace || preso))
704         usage("the -b option is incompatible with -d and -g");
705     if (dumptrace >= 1) {
706         endpoint_ptr ep;
707         const char*  sep;
708         myregex_ptr  mr;
709 
710         fprintf(stderr, "%s: version %s\n", ProgramName, PACKAGE_VERSION);
711         fprintf(stderr,
712             "%s: msg %c%c%c, side %c%c, hide %c%c, err %c%c%c%c%c%c%c%c, t %u, c %u, C %zu, %sq %s\n",
713             ProgramName,
714             (msg_wanted & MSG_QUERY) != 0 ? 'Q' : '.',
715             (msg_wanted & MSG_UPDATE) != 0 ? 'U' : '.',
716             (msg_wanted & MSG_NOTIFY) != 0 ? 'N' : '.',
717             (dir_wanted & DIR_INITIATE) != 0 ? 'I' : '.',
718             (dir_wanted & DIR_RESPONSE) != 0 ? 'R' : '.',
719             (end_hide & END_INITIATOR) != 0 ? 'I' : '.',
720             (end_hide & END_RESPONDER) != 0 ? 'R' : '.',
721             (err_wanted & ERR_NO) != 0 ? 'N' : '.',
722             (err_wanted & ERR_YES) == ERR_YES ? 'Y' : '.',
723             (err_wanted & ERR_TRUNC) != 0 ? 't' : '.',
724             (err_wanted & ERR_FORMERR) != 0 ? 'f' : '.',
725             (err_wanted & ERR_SERVFAIL) != 0 ? 's' : '.',
726             (err_wanted & ERR_NXDOMAIN) != 0 ? 'x' : '.',
727             (err_wanted & ERR_NOTIMPL) != 0 ? 'i' : '.',
728             (err_wanted & ERR_REFUSED) != 0 ? 'r' : '.',
729             limit_seconds, limit_packets, limit_pcapfilesize,
730             nmatch_qtype ? "!" : "", match_qtype_arg);
731         sep = "\tinit";
732         for (ep = HEAD(initiators);
733              ep != NULL;
734              ep = NEXT(ep, link)) {
735             fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
736             sep = "";
737         }
738         if (!EMPTY(initiators))
739             fprintf(stderr, "\n");
740         sep = "\tresp";
741         for (ep = HEAD(responders);
742              ep != NULL;
743              ep = NEXT(ep, link)) {
744             fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
745             sep = "";
746         }
747         if (!EMPTY(responders))
748             fprintf(stderr, "\n");
749         sep = "\t!init";
750         for (ep = HEAD(not_initiators);
751              ep != NULL;
752              ep = NEXT(ep, link)) {
753             fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
754             sep = "";
755         }
756         if (!EMPTY(not_initiators))
757             fprintf(stderr, "\n");
758         sep = "\t!resp";
759         for (ep = HEAD(not_responders);
760              ep != NULL;
761              ep = NEXT(ep, link)) {
762             fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
763             sep = "";
764         }
765         if (!EMPTY(not_responders))
766             fprintf(stderr, "\n");
767         sep = "\t!dropresp";
768         for (ep = HEAD(drop_responders);
769              ep != NULL;
770              ep = NEXT(ep, link)) {
771             fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
772             sep = "";
773         }
774         if (!EMPTY(drop_responders))
775             fprintf(stderr, "\n");
776         if (!EMPTY(myregexes)) {
777             fprintf(stderr, "%s: pat:", ProgramName);
778             for (mr = HEAD(myregexes);
779                  mr != NULL;
780                  mr = NEXT(mr, link))
781                 fprintf(stderr, " %s/%s/",
782                     mr->not ? "!" : "", mr->str);
783             fprintf(stderr, "\n");
784         }
785     }
786     if (EMPTY(mypcaps)) {
787         pcap_if_t* pcapdev = 0;
788         int        res;
789         res = pcap_findalldevs(&pcapdev, errbuf);
790         if (res == -1) {
791             fprintf(stderr, "%s: pcap_findalldevs: %s\n",
792                 ProgramName, errbuf);
793             exit(1);
794         } else if (pcapdev == NULL) {
795             fprintf(stderr, "%s: pcap_findalldevs: no devices found\n",
796                 ProgramName);
797             exit(1);
798         }
799         mypcap = calloc(1, sizeof *mypcap);
800         assert(mypcap != NULL);
801         INIT_LINK(mypcap, link);
802         mypcap->name = strdup(pcapdev->name);
803         APPEND(mypcaps, mypcap, link);
804         pcap_freealldevs(pcapdev);
805     }
806     if (start_time && stop_time && start_time >= stop_time)
807         usage("start time must be before stop time");
808 
809     if (options.dump_format == cbor) {
810         if (!have_cbor_support()) {
811             usage("no built in cbor support");
812         }
813         cbor_set_size(options.cbor_chunk_size);
814     } else if (options.dump_format == cds) {
815         if (!have_cds_support()) {
816             usage("no built in cds support");
817         }
818         cds_set_cbor_size(options.cds_cbor_size);
819         cds_set_message_size(options.cds_message_size);
820         cds_set_max_rlabels(options.cds_max_rlabels);
821         cds_set_min_rlabel_size(options.cds_min_rlabel_size);
822         if (options.cds_use_rdata_index && options.cds_use_rdata_rindex) {
823             usage("can't use both CDS rdata index and rindex");
824         }
825         cds_set_use_rdata_index(options.cds_use_rdata_index);
826         cds_set_use_rdata_rindex(options.cds_use_rdata_rindex);
827         cds_set_rdata_index_min_size(options.cds_rdata_index_min_size);
828         cds_set_rdata_rindex_min_size(options.cds_rdata_rindex_min_size);
829         cds_set_rdata_rindex_size(options.cds_rdata_rindex_size);
830     }
831 
832     if (!options.use_layers && (options.defrag_ipv4 || options.defrag_ipv6)) {
833         usage("can't defragment IP packets without use_layers=yes");
834     }
835 
836     if (options.reassemble_tcp_bfbparsedns) {
837         if (!options.reassemble_tcp) {
838             usage("can't do byte for byte parsing of DNS without reassemble_tcp=yes");
839         }
840     }
841 
842     free(match_qtype_arg);
843 }
844