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(¬_initiators, optarg);
474 break;
475 case 'Z':
476 endpoint_arg(¬_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