1 /*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <arpa/inet.h>
18 #include <locale.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 
23 #include "utils/kdig/kdig_params.h"
24 #include "utils/common/cert.h"
25 #include "utils/common/hex.h"
26 #include "utils/common/msg.h"
27 #include "utils/common/netio.h"
28 #include "utils/common/params.h"
29 #include "utils/common/resolv.h"
30 #include "libknot/descriptor.h"
31 #include "libknot/libknot.h"
32 #include "contrib/base64.h"
33 #include "contrib/sockaddr.h"
34 #include "contrib/string.h"
35 #include "contrib/strtonum.h"
36 #include "contrib/ucw/lists.h"
37 #include "libdnssec/error.h"
38 #include "libdnssec/random.h"
39 
40 #define PROGRAM_NAME "kdig"
41 
42 #define DEFAULT_RETRIES_DIG		2
43 #define DEFAULT_TIMEOUT_DIG		5
44 #define DEFAULT_ALIGNMENT_SIZE		128
45 #define DEFAULT_TLS_OCSP_STAPLING	(7 * 24 * 3600)
46 
47 #define BADCOOKIE_RETRY_MAX		10
48 
49 static const flags_t DEFAULT_FLAGS_DIG = {
50 	.aa_flag = false,
51 	.tc_flag = false,
52 	.rd_flag = true,
53 	.ra_flag = false,
54 	.z_flag  = false,
55 	.ad_flag = false,
56 	.cd_flag = false,
57 	.do_flag = false
58 };
59 
60 static const style_t DEFAULT_STYLE_DIG = {
61 	.format = FORMAT_FULL,
62 	.style = {
63 		.wrap = false,
64 		.show_class = true,
65 		.show_ttl = true,
66 		.verbose = false,
67 		.original_ttl = false,
68 		.empty_ttl = false,
69 		.human_ttl = false,
70 		.human_tmstamp = true,
71 		.generic = false,
72 		.ascii_to_idn = name_to_idn
73 	},
74 	.show_query = false,
75 	.show_header = true,
76 	.show_section = true,
77 	.show_edns = true,
78 	.show_question = true,
79 	.show_answer = true,
80 	.show_authority = true,
81 	.show_additional = true,
82 	.show_tsig = true,
83 	.show_footer = true
84 };
85 
opt_multiline(const char * arg,void * query)86 static int opt_multiline(const char *arg, void *query)
87 {
88 	query_t *q = query;
89 
90 	q->style.style.wrap = true;
91 	q->style.format = FORMAT_FULL;
92 	q->style.show_header = true;
93 	q->style.show_edns = true;
94 	q->style.show_footer = true;
95 	q->style.style.verbose = true;
96 
97 	return KNOT_EOK;
98 }
99 
opt_nomultiline(const char * arg,void * query)100 static int opt_nomultiline(const char *arg, void *query)
101 {
102 	query_t *q = query;
103 
104 	q->style.style.wrap = false;
105 
106 	return KNOT_EOK;
107 }
108 
opt_short(const char * arg,void * query)109 static int opt_short(const char *arg, void *query)
110 {
111 	query_t *q = query;
112 
113 	q->style.format = FORMAT_DIG;
114 	q->style.show_header = false;
115 	q->style.show_edns = false;
116 	q->style.show_footer = false;
117 
118 	return KNOT_EOK;
119 }
120 
opt_noshort(const char * arg,void * query)121 static int opt_noshort(const char *arg, void *query)
122 {
123 	query_t *q = query;
124 
125 	q->style.format = FORMAT_FULL;
126 
127 	return KNOT_EOK;
128 }
129 
opt_generic(const char * arg,void * query)130 static int opt_generic(const char *arg, void *query)
131 {
132 	query_t *q = query;
133 
134 	q->style.style.generic = true;
135 
136 	return KNOT_EOK;
137 }
138 
opt_nogeneric(const char * arg,void * query)139 static int opt_nogeneric(const char *arg, void *query)
140 {
141 	query_t *q = query;
142 
143 	q->style.style.generic = false;
144 
145 	return KNOT_EOK;
146 }
147 
opt_aaflag(const char * arg,void * query)148 static int opt_aaflag(const char *arg, void *query)
149 {
150 	query_t *q = query;
151 
152 	q->flags.aa_flag = true;
153 
154 	return KNOT_EOK;
155 }
156 
opt_noaaflag(const char * arg,void * query)157 static int opt_noaaflag(const char *arg, void *query)
158 {
159 	query_t *q = query;
160 
161 	q->flags.aa_flag = false;
162 
163 	return KNOT_EOK;
164 }
165 
opt_tcflag(const char * arg,void * query)166 static int opt_tcflag(const char *arg, void *query)
167 {
168 	query_t *q = query;
169 
170 	q->flags.tc_flag = true;
171 
172 	return KNOT_EOK;
173 }
174 
opt_notcflag(const char * arg,void * query)175 static int opt_notcflag(const char *arg, void *query)
176 {
177 	query_t *q = query;
178 
179 	q->flags.tc_flag = false;
180 
181 	return KNOT_EOK;
182 }
183 
opt_rdflag(const char * arg,void * query)184 static int opt_rdflag(const char *arg, void *query)
185 {
186 	query_t *q = query;
187 
188 	q->flags.rd_flag = true;
189 
190 	return KNOT_EOK;
191 }
192 
opt_nordflag(const char * arg,void * query)193 static int opt_nordflag(const char *arg, void *query)
194 {
195 	query_t *q = query;
196 
197 	q->flags.rd_flag = false;
198 
199 	return KNOT_EOK;
200 }
201 
opt_raflag(const char * arg,void * query)202 static int opt_raflag(const char *arg, void *query)
203 {
204 	query_t *q = query;
205 
206 	q->flags.ra_flag = true;
207 
208 	return KNOT_EOK;
209 }
210 
opt_noraflag(const char * arg,void * query)211 static int opt_noraflag(const char *arg, void *query)
212 {
213 	query_t *q = query;
214 
215 	q->flags.ra_flag = false;
216 
217 	return KNOT_EOK;
218 }
219 
opt_zflag(const char * arg,void * query)220 static int opt_zflag(const char *arg, void *query)
221 {
222 	query_t *q = query;
223 
224 	q->flags.z_flag = true;
225 
226 	return KNOT_EOK;
227 }
228 
opt_nozflag(const char * arg,void * query)229 static int opt_nozflag(const char *arg, void *query)
230 {
231 	query_t *q = query;
232 
233 	q->flags.z_flag = false;
234 
235 	return KNOT_EOK;
236 }
237 
opt_adflag(const char * arg,void * query)238 static int opt_adflag(const char *arg, void *query)
239 {
240 	query_t *q = query;
241 
242 	q->flags.ad_flag = true;
243 
244 	return KNOT_EOK;
245 }
246 
opt_noadflag(const char * arg,void * query)247 static int opt_noadflag(const char *arg, void *query)
248 {
249 	query_t *q = query;
250 
251 	q->flags.ad_flag = false;
252 
253 	return KNOT_EOK;
254 }
255 
opt_cdflag(const char * arg,void * query)256 static int opt_cdflag(const char *arg, void *query)
257 {
258 	query_t *q = query;
259 
260 	q->flags.cd_flag = true;
261 
262 	return KNOT_EOK;
263 }
264 
opt_nocdflag(const char * arg,void * query)265 static int opt_nocdflag(const char *arg, void *query)
266 {
267 	query_t *q = query;
268 
269 	q->flags.cd_flag = false;
270 
271 	return KNOT_EOK;
272 }
273 
opt_doflag(const char * arg,void * query)274 static int opt_doflag(const char *arg, void *query)
275 {
276 	query_t *q = query;
277 
278 	q->flags.do_flag = true;
279 
280 	return KNOT_EOK;
281 }
282 
opt_nodoflag(const char * arg,void * query)283 static int opt_nodoflag(const char *arg, void *query)
284 {
285 	query_t *q = query;
286 
287 	q->flags.do_flag = false;
288 
289 	return KNOT_EOK;
290 }
291 
opt_all(const char * arg,void * query)292 static int opt_all(const char *arg, void *query)
293 {
294 	query_t *q = query;
295 
296 	q->style.show_header = true;
297 	q->style.show_section = true;
298 	q->style.show_edns = true;
299 	q->style.show_question = true;
300 	q->style.show_answer = true;
301 	q->style.show_authority = true;
302 	q->style.show_additional = true;
303 	q->style.show_tsig = true;
304 	q->style.show_footer = true;
305 
306 	return KNOT_EOK;
307 }
308 
opt_noall(const char * arg,void * query)309 static int opt_noall(const char *arg, void *query)
310 {
311 	query_t *q = query;
312 
313 	q->style.show_header = false;
314 	q->style.show_section = false;
315 	q->style.show_edns = false;
316 	q->style.show_query = false;
317 	q->style.show_question = false;
318 	q->style.show_answer = false;
319 	q->style.show_authority = false;
320 	q->style.show_additional = false;
321 	q->style.show_tsig = false;
322 	q->style.show_footer = false;
323 
324 	return KNOT_EOK;
325 }
326 
opt_qr(const char * arg,void * query)327 static int opt_qr(const char *arg, void *query)
328 {
329 	query_t *q = query;
330 
331 	q->style.show_query = true;
332 
333 	return KNOT_EOK;
334 }
335 
opt_noqr(const char * arg,void * query)336 static int opt_noqr(const char *arg, void *query)
337 {
338 	query_t *q = query;
339 
340 	q->style.show_query = false;
341 
342 	return KNOT_EOK;
343 }
344 
opt_header(const char * arg,void * query)345 static int opt_header(const char *arg, void *query)
346 {
347 	query_t *q = query;
348 
349 	q->style.show_header = true;
350 
351 	return KNOT_EOK;
352 }
353 
opt_noheader(const char * arg,void * query)354 static int opt_noheader(const char *arg, void *query)
355 {
356 	query_t *q = query;
357 
358 	q->style.show_header = false;
359 
360 	return KNOT_EOK;
361 }
362 
opt_comments(const char * arg,void * query)363 static int opt_comments(const char *arg, void *query)
364 {
365 	query_t *q = query;
366 
367 	q->style.show_section = true;
368 
369 	return KNOT_EOK;
370 }
371 
opt_nocomments(const char * arg,void * query)372 static int opt_nocomments(const char *arg, void *query)
373 {
374 	query_t *q = query;
375 
376 	q->style.show_section = false;
377 
378 	return KNOT_EOK;
379 }
380 
opt_opt(const char * arg,void * query)381 static int opt_opt(const char *arg, void *query)
382 {
383 	query_t *q = query;
384 
385 	q->style.show_edns = true;
386 
387 	return KNOT_EOK;
388 }
389 
opt_noopt(const char * arg,void * query)390 static int opt_noopt(const char *arg, void *query)
391 {
392 	query_t *q = query;
393 
394 	q->style.show_edns = false;
395 
396 	return KNOT_EOK;
397 }
398 
opt_opttext(const char * arg,void * query)399 static int opt_opttext(const char *arg, void *query)
400 {
401 	query_t *q = query;
402 
403 	q->style.show_edns_opt_text = true;
404 
405 	return KNOT_EOK;
406 }
407 
opt_noopttext(const char * arg,void * query)408 static int opt_noopttext(const char *arg, void *query)
409 {
410 	query_t *q = query;
411 
412 	q->style.show_edns_opt_text = false;
413 
414 	return KNOT_EOK;
415 }
416 
opt_question(const char * arg,void * query)417 static int opt_question(const char *arg, void *query)
418 {
419 	query_t *q = query;
420 
421 	q->style.show_question = true;
422 
423 	return KNOT_EOK;
424 }
425 
opt_noquestion(const char * arg,void * query)426 static int opt_noquestion(const char *arg, void *query)
427 {
428 	query_t *q = query;
429 
430 	q->style.show_question = false;
431 
432 	return KNOT_EOK;
433 }
434 
opt_answer(const char * arg,void * query)435 static int opt_answer(const char *arg, void *query)
436 {
437 	query_t *q = query;
438 
439 	q->style.show_answer = true;
440 
441 	return KNOT_EOK;
442 }
443 
opt_noanswer(const char * arg,void * query)444 static int opt_noanswer(const char *arg, void *query)
445 {
446 	query_t *q = query;
447 
448 	q->style.show_answer = false;
449 
450 	return KNOT_EOK;
451 }
452 
opt_authority(const char * arg,void * query)453 static int opt_authority(const char *arg, void *query)
454 {
455 	query_t *q = query;
456 
457 	q->style.show_authority = true;
458 
459 	return KNOT_EOK;
460 }
461 
opt_noauthority(const char * arg,void * query)462 static int opt_noauthority(const char *arg, void *query)
463 {
464 	query_t *q = query;
465 
466 	q->style.show_authority = false;
467 
468 	return KNOT_EOK;
469 }
470 
opt_additional(const char * arg,void * query)471 static int opt_additional(const char *arg, void *query)
472 {
473 	query_t *q = query;
474 
475 	q->style.show_additional = true;
476 
477 	return KNOT_EOK;
478 }
479 
opt_noadditional(const char * arg,void * query)480 static int opt_noadditional(const char *arg, void *query)
481 {
482 	query_t *q = query;
483 
484 	q->style.show_additional = false;
485 	q->style.show_edns = false;
486 	q->style.show_tsig = false;
487 
488 	return KNOT_EOK;
489 }
490 
opt_tsig(const char * arg,void * query)491 static int opt_tsig(const char *arg, void *query)
492 {
493 	query_t *q = query;
494 
495 	q->style.show_tsig = true;
496 
497 	return KNOT_EOK;
498 }
499 
opt_notsig(const char * arg,void * query)500 static int opt_notsig(const char *arg, void *query)
501 {
502 	query_t *q = query;
503 
504 	q->style.show_tsig = false;
505 
506 	return KNOT_EOK;
507 }
508 
opt_stats(const char * arg,void * query)509 static int opt_stats(const char *arg, void *query)
510 {
511 	query_t *q = query;
512 
513 	q->style.show_footer = true;
514 
515 	return KNOT_EOK;
516 }
517 
opt_nostats(const char * arg,void * query)518 static int opt_nostats(const char *arg, void *query)
519 {
520 	query_t *q = query;
521 
522 	q->style.show_footer = false;
523 
524 	return KNOT_EOK;
525 }
526 
opt_class(const char * arg,void * query)527 static int opt_class(const char *arg, void *query)
528 {
529 	query_t *q = query;
530 
531 	q->style.style.show_class = true;
532 
533 	return KNOT_EOK;
534 }
535 
opt_noclass(const char * arg,void * query)536 static int opt_noclass(const char *arg, void *query)
537 {
538 	query_t *q = query;
539 
540 	q->style.style.show_class = false;
541 
542 	return KNOT_EOK;
543 }
544 
opt_ttl(const char * arg,void * query)545 static int opt_ttl(const char *arg, void *query)
546 {
547 	query_t *q = query;
548 
549 	q->style.style.show_ttl = true;
550 
551 	return KNOT_EOK;
552 }
553 
opt_nottl(const char * arg,void * query)554 static int opt_nottl(const char *arg, void *query)
555 {
556 	query_t *q = query;
557 
558 	q->style.style.show_ttl = false;
559 
560 	return KNOT_EOK;
561 }
562 
opt_ignore(const char * arg,void * query)563 static int opt_ignore(const char *arg, void *query)
564 {
565 	query_t *q = query;
566 
567 	q->ignore_tc = true;
568 
569 	return KNOT_EOK;
570 }
571 
opt_noignore(const char * arg,void * query)572 static int opt_noignore(const char *arg, void *query)
573 {
574 	query_t *q = query;
575 
576 	q->ignore_tc = false;
577 
578 	return KNOT_EOK;
579 }
580 
opt_crypto(const char * arg,void * query)581 static int opt_crypto(const char *arg, void *query)
582 {
583 	query_t *q = query;
584 
585 	q->style.style.hide_crypto = false;
586 
587 	return KNOT_EOK;
588 }
589 
opt_nocrypto(const char * arg,void * query)590 static int opt_nocrypto(const char *arg, void *query)
591 {
592 	query_t *q = query;
593 
594 	q->style.style.hide_crypto = true;
595 
596 	return KNOT_EOK;
597 }
598 
opt_tcp(const char * arg,void * query)599 static int opt_tcp(const char *arg, void *query)
600 {
601 	query_t *q = query;
602 
603 	q->protocol = PROTO_TCP;
604 
605 	return KNOT_EOK;
606 }
607 
opt_notcp(const char * arg,void * query)608 static int opt_notcp(const char *arg, void *query)
609 {
610 	query_t *q = query;
611 
612 	q->protocol = PROTO_UDP;
613 	return opt_ignore(arg, query);
614 }
615 
opt_fastopen(const char * arg,void * query)616 static int opt_fastopen(const char *arg, void *query)
617 {
618 	query_t *q = query;
619 
620 	q->fastopen = true;
621 
622 	return opt_tcp(arg, query);
623 }
624 
opt_nofastopen(const char * arg,void * query)625 static int opt_nofastopen(const char *arg, void *query)
626 {
627 	query_t *q = query;
628 
629 	q->fastopen = false;
630 
631 	return KNOT_EOK;
632 }
633 
opt_keepopen(const char * arg,void * query)634 static int opt_keepopen(const char *arg, void *query)
635 {
636 	query_t *q = query;
637 
638 	q->keepopen = true;
639 
640 	return KNOT_EOK;
641 }
642 
opt_nokeepopen(const char * arg,void * query)643 static int opt_nokeepopen(const char *arg, void *query)
644 {
645 	query_t *q = query;
646 
647 	q->keepopen = false;
648 
649 	return KNOT_EOK;
650 }
651 
opt_tls(const char * arg,void * query)652 static int opt_tls(const char *arg, void *query)
653 {
654 	query_t *q = query;
655 
656 	q->tls.enable = true;
657 	return opt_tcp(arg, query);
658 }
659 
opt_notls(const char * arg,void * query)660 static int opt_notls(const char *arg, void *query)
661 {
662 	query_t *q = query;
663 
664 	tls_params_clean(&q->tls);
665 	tls_params_init(&q->tls);
666 
667 	return KNOT_EOK;
668 }
669 
opt_tls_ca(const char * arg,void * query)670 static int opt_tls_ca(const char *arg, void *query)
671 {
672 	query_t *q = query;
673 
674 	if (arg == NULL) {
675 		q->tls.system_ca = true;
676 		return opt_tls(arg, query);
677 	} else {
678 		if (ptrlist_add(&q->tls.ca_files, strdup(arg), NULL) == NULL) {
679 			return KNOT_ENOMEM;
680 		}
681 		return opt_tls(arg, query);
682 	}
683 }
684 
opt_notls_ca(const char * arg,void * query)685 static int opt_notls_ca(const char *arg, void *query)
686 {
687 	query_t *q = query;
688 
689 	q->tls.system_ca = false;
690 
691 	ptrnode_t *node, *nxt;
692 	WALK_LIST_DELSAFE(node, nxt, q->tls.ca_files) {
693 		free(node->d);
694 	}
695 	ptrlist_free(&q->tls.ca_files, NULL);
696 
697 	return KNOT_EOK;
698 }
699 
opt_tls_pin(const char * arg,void * query)700 static int opt_tls_pin(const char *arg, void *query)
701 {
702 	query_t *q = query;
703 
704 	uint8_t pin[64] = { 0 };
705 
706 	int ret = knot_base64_decode((const uint8_t *)arg, strlen(arg), pin, sizeof(pin));
707 	if (ret < 0) {
708 		ERR("invalid +tls-pin=%s\n", arg);
709 		return ret;
710 	} else if (ret != CERT_PIN_LEN) { // Check for 256-bit value.
711 		ERR("invalid sha256 hash length +tls-pin=%s\n", arg);
712 		return KNOT_EINVAL;
713 	}
714 
715 	uint8_t *item = malloc(1 + ret); // 1 ~ leading data length.
716 	if (item == NULL) {
717 		return KNOT_ENOMEM;
718 	}
719 	item[0] = ret;
720 	memcpy(&item[1], pin, ret);
721 
722 	if (ptrlist_add(&q->tls.pins, item, NULL) == NULL) {
723 		return KNOT_ENOMEM;
724 	}
725 
726 	return opt_tls(arg, query);
727 }
728 
opt_notls_pin(const char * arg,void * query)729 static int opt_notls_pin(const char *arg, void *query)
730 {
731 	query_t *q = query;
732 
733 	ptrnode_t *node, *nxt;
734 	WALK_LIST_DELSAFE(node, nxt, q->tls.pins) {
735 		free(node->d);
736 	}
737 	ptrlist_free(&q->tls.pins, NULL);
738 
739 	return KNOT_EOK;
740 }
741 
opt_tls_hostname(const char * arg,void * query)742 static int opt_tls_hostname(const char *arg, void *query)
743 {
744 	query_t *q = query;
745 
746 	free(q->tls.hostname);
747 	q->tls.hostname = strdup(arg);
748 
749 	return opt_tls(arg, query);
750 }
751 
opt_notls_hostname(const char * arg,void * query)752 static int opt_notls_hostname(const char *arg, void *query)
753 {
754 	query_t *q = query;
755 
756 	free(q->tls.hostname);
757 	q->tls.hostname = NULL;
758 
759 	return KNOT_EOK;
760 }
761 
opt_tls_sni(const char * arg,void * query)762 static int opt_tls_sni(const char *arg, void *query)
763 {
764 	query_t *q = query;
765 
766 	free(q->tls.sni);
767 	q->tls.sni = strdup(arg);
768 
769 	return opt_tls(arg, query);
770 }
771 
opt_notls_sni(const char * arg,void * query)772 static int opt_notls_sni(const char *arg, void *query)
773 {
774 	query_t *q = query;
775 
776 	free(q->tls.sni);
777 	q->tls.sni = NULL;
778 
779 	return KNOT_EOK;
780 }
781 
opt_tls_keyfile(const char * arg,void * query)782 static int opt_tls_keyfile(const char *arg, void *query)
783 {
784 	query_t *q = query;
785 
786 	free(q->tls.keyfile);
787 	q->tls.keyfile = strdup(arg);
788 
789 	return opt_tls(arg, query);
790 }
791 
opt_notls_keyfile(const char * arg,void * query)792 static int opt_notls_keyfile(const char *arg, void *query)
793 {
794 	query_t *q = query;
795 
796 	free(q->tls.keyfile);
797 	q->tls.keyfile = NULL;
798 
799 	return KNOT_EOK;
800 }
801 
opt_tls_certfile(const char * arg,void * query)802 static int opt_tls_certfile(const char *arg, void *query)
803 {
804 	query_t *q = query;
805 
806 	free(q->tls.certfile);
807 	q->tls.certfile = strdup(arg);
808 
809 	return opt_tls(arg, query);
810 }
811 
opt_notls_certfile(const char * arg,void * query)812 static int opt_notls_certfile(const char *arg, void *query)
813 {
814 	query_t *q = query;
815 
816 	free(q->tls.certfile);
817 	q->tls.certfile = NULL;
818 
819 	return KNOT_EOK;
820 }
821 
opt_tls_ocsp_stapling(const char * arg,void * query)822 static int opt_tls_ocsp_stapling(const char *arg, void *query)
823 {
824 	query_t *q = query;
825 
826 	if (arg == NULL) {
827 		q->tls.ocsp_stapling = DEFAULT_TLS_OCSP_STAPLING;
828 		return opt_tls(arg, query);
829 	} else {
830 		uint32_t num = 0;
831 		if (str_to_u32(arg, &num) != KNOT_EOK || num == 0) {
832 			ERR("invalid +tls-ocsp-stapling=%s\n", arg);
833 			return KNOT_EINVAL;
834 		}
835 
836 		q->tls.ocsp_stapling = 3600 * num;
837 		return opt_tls(arg, query);
838 	}
839 }
840 
opt_notls_ocsp_stapling(const char * arg,void * query)841 static int opt_notls_ocsp_stapling(const char *arg, void *query)
842 {
843 	query_t *q = query;
844 
845 	q->tls.ocsp_stapling = 0;
846 
847 	return KNOT_EOK;
848 }
849 
opt_https(const char * arg,void * query)850 static int opt_https(const char *arg, void *query)
851 {
852 #ifdef LIBNGHTTP2
853 	query_t *q = query;
854 
855 	q->https.enable = true;
856 
857 	if (arg != NULL) {
858 		char *resource = strstr(arg, "://");
859 		if (resource == NULL) {
860 			resource = (char *)arg;
861 		} else {
862 			resource += 3;  // strlen("://")
863 			if (*resource == '\0') {
864 				ERR("invalid +https=%s\n", arg);
865 				return KNOT_EINVAL;
866 			}
867 		}
868 
869 		char *tmp_path = strchr(resource, '/');
870 		if (tmp_path) {
871 			free(q->https.path);
872 			q->https.path = strdup(tmp_path);
873 
874 			if (tmp_path != resource) {
875 				free(q->tls.hostname);
876 				q->tls.hostname = strndup(resource, (size_t)(tmp_path - resource));
877 			}
878 			return opt_tls(arg, query);
879 		} else {
880 			return opt_tls_hostname(arg, query);
881 		}
882 
883 	}
884 
885 	return opt_tls(arg, query);
886 
887 #else
888 	return KNOT_ENOTSUP;
889 #endif //LIBNGHTTP2
890 }
891 
opt_nohttps(const char * arg,void * query)892 static int opt_nohttps(const char *arg, void *query)
893 {
894 #ifdef LIBNGHTTP2
895 	query_t *q = query;
896 
897 	https_params_clean(&q->https);
898 
899 	return opt_notls(arg, query);
900 #else
901 	return KNOT_ENOTSUP;
902 #endif //LIBNGHTTP2
903 }
904 
opt_https_get(const char * arg,void * query)905 static int opt_https_get(const char *arg, void *query)
906 {
907 #ifdef LIBNGHTTP2
908 	query_t *q = query;
909 
910 	q->https.method = GET;
911 
912 	return opt_https(arg, query);
913 #else
914 	return KNOT_ENOTSUP;
915 #endif //LIBNGHTTP2
916 }
917 
opt_nohttps_get(const char * arg,void * query)918 static int opt_nohttps_get(const char *arg, void *query)
919 {
920 #ifdef LIBNGHTTP2
921 	query_t *q = query;
922 
923 	q->https.method = POST;
924 
925 	return KNOT_EOK;
926 #else
927 	return KNOT_ENOTSUP;
928 #endif
929 }
930 
opt_nsid(const char * arg,void * query)931 static int opt_nsid(const char *arg, void *query)
932 {
933 	query_t *q = query;
934 
935 	q->nsid = true;
936 
937 	return KNOT_EOK;
938 }
939 
opt_nonsid(const char * arg,void * query)940 static int opt_nonsid(const char *arg, void *query)
941 {
942 	query_t *q = query;
943 
944 	q->nsid = false;
945 
946 	return KNOT_EOK;
947 }
948 
opt_bufsize(const char * arg,void * query)949 static int opt_bufsize(const char *arg, void *query)
950 {
951 	query_t *q = query;
952 
953 	uint16_t num = 0;
954 	if (str_to_u16(arg, &num) != KNOT_EOK) {
955 		ERR("invalid +bufsize=%s\n", arg);
956 		return KNOT_EINVAL;
957 	}
958 
959 	// Disable EDNS if zero bufsize.
960 	if (num == 0) {
961 		q->udp_size = -1;
962 	} else if (num < KNOT_WIRE_HEADER_SIZE) {
963 		q->udp_size = KNOT_WIRE_HEADER_SIZE;
964 	} else {
965 		q->udp_size = num;
966 	}
967 
968 	return KNOT_EOK;
969 }
970 
opt_nobufsize(const char * arg,void * query)971 static int opt_nobufsize(const char *arg, void *query)
972 {
973 	query_t *q = query;
974 
975 	q->udp_size = -1;
976 
977 	return KNOT_EOK;
978 }
979 
opt_cookie(const char * arg,void * query)980 static int opt_cookie(const char *arg, void *query)
981 {
982 	query_t *q = query;
983 
984 	if (arg != NULL) {
985 		uint8_t *input = NULL;
986 		size_t input_len;
987 
988 		int ret = hex_decode(arg, &input, &input_len);
989 		if (ret != KNOT_EOK) {
990 			ERR("invalid +cookie=%s\n", arg);
991 			return KNOT_EINVAL;
992 		}
993 
994 		if (input_len < KNOT_EDNS_COOKIE_CLNT_SIZE) {
995 			ERR("too short client +cookie=%s\n", arg);
996 			free(input);
997 			return KNOT_EINVAL;
998 		}
999 		q->cc.len = KNOT_EDNS_COOKIE_CLNT_SIZE;
1000 		memcpy(q->cc.data, input, q->cc.len);
1001 
1002 		input_len -= q->cc.len;
1003 		if (input_len > 0) {
1004 			if (input_len < KNOT_EDNS_COOKIE_SRVR_MIN_SIZE) {
1005 				ERR("too short server +cookie=%s\n", arg);
1006 				free(input);
1007 				return KNOT_EINVAL;
1008 			}
1009 			if (input_len > KNOT_EDNS_COOKIE_SRVR_MAX_SIZE) {
1010 				ERR("too long server +cookie=%s\n", arg);
1011 				free(input);
1012 				return KNOT_EINVAL;
1013 			}
1014 			q->sc.len = input_len;
1015 			memcpy(q->sc.data, input + q->cc.len, q->sc.len);
1016 		}
1017 
1018 		free(input);
1019 	} else {
1020 		q->cc.len = KNOT_EDNS_COOKIE_CLNT_SIZE;
1021 
1022 		int ret = dnssec_random_buffer(q->cc.data, q->cc.len);
1023 		if (ret != DNSSEC_EOK) {
1024 			return knot_error_from_libdnssec(ret);
1025 		}
1026 	}
1027 
1028 	return KNOT_EOK;
1029 }
1030 
opt_nocookie(const char * arg,void * query)1031 static int opt_nocookie(const char *arg, void *query)
1032 {
1033 	query_t *q = query;
1034 	q->cc.len = 0;
1035 	q->sc.len = 0;
1036 	return KNOT_EOK;
1037 }
1038 
opt_badcookie(const char * arg,void * query)1039 static int opt_badcookie(const char *arg, void *query)
1040 {
1041 	query_t *q = query;
1042 	q->badcookie = BADCOOKIE_RETRY_MAX;
1043 	return KNOT_EOK;
1044 }
1045 
opt_nobadcookie(const char * arg,void * query)1046 static int opt_nobadcookie(const char *arg, void *query)
1047 {
1048 	query_t *q = query;
1049 	q->badcookie = 0;
1050 	return KNOT_EOK;
1051 }
1052 
opt_padding(const char * arg,void * query)1053 static int opt_padding(const char *arg, void *query)
1054 {
1055 	query_t *q = query;
1056 
1057 	if (arg == NULL) {
1058 		q->padding = -2;
1059 		return KNOT_EOK;
1060 	} else {
1061 		uint16_t num = 0;
1062 		if (str_to_u16(arg, &num) != KNOT_EOK) {
1063 			ERR("invalid +padding=%s\n", arg);
1064 			return KNOT_EINVAL;
1065 		}
1066 
1067 		q->padding = num;
1068 		return KNOT_EOK;
1069 	}
1070 }
1071 
opt_nopadding(const char * arg,void * query)1072 static int opt_nopadding(const char *arg, void *query)
1073 {
1074 	query_t *q = query;
1075 
1076 	q->padding = -3;
1077 
1078 	return KNOT_EOK;
1079 }
1080 
opt_alignment(const char * arg,void * query)1081 static int opt_alignment(const char *arg, void *query)
1082 {
1083 	query_t *q = query;
1084 
1085 	if (arg == NULL) {
1086 		q->alignment = DEFAULT_ALIGNMENT_SIZE;
1087 		return KNOT_EOK;
1088 	} else {
1089 		uint16_t num = 0;
1090 		if (str_to_u16(arg, &num) != KNOT_EOK || num < 2) {
1091 			ERR("invalid +alignment=%s\n", arg);
1092 			return KNOT_EINVAL;
1093 		}
1094 
1095 		q->alignment = num;
1096 		return KNOT_EOK;
1097 	}
1098 }
1099 
opt_noalignment(const char * arg,void * query)1100 static int opt_noalignment(const char *arg, void *query)
1101 {
1102 	query_t *q = query;
1103 
1104 	q->alignment = 0;
1105 
1106 	return KNOT_EOK;
1107 }
1108 
opt_subnet(const char * arg,void * query)1109 static int opt_subnet(const char *arg, void *query)
1110 {
1111 	query_t *q = query;
1112 
1113 	char         *sep = NULL;
1114 	const size_t arg_len = strlen(arg);
1115 	const char   *arg_end = arg + arg_len;
1116 	size_t       addr_len = 0;
1117 
1118 	// Separate address and network mask.
1119 	if ((sep = strchr(arg, '/')) != NULL) {
1120 		addr_len = sep - arg;
1121 	} else {
1122 		addr_len = arg_len;
1123 	}
1124 
1125 	// Check IP address.
1126 
1127 	struct sockaddr_storage ss = { 0 };
1128 	struct addrinfo hints = { .ai_flags = AI_NUMERICHOST };
1129 	struct addrinfo *ai = NULL;
1130 
1131 	char *addr_str = strndup(arg, addr_len);
1132 	if (getaddrinfo(addr_str, NULL, &hints, &ai) != 0) {
1133 		free(addr_str);
1134 		ERR("invalid address +subnet=%s\n", arg);
1135 		return KNOT_EINVAL;
1136 	}
1137 
1138 	memcpy(&ss, ai->ai_addr, ai->ai_addrlen);
1139 	freeaddrinfo(ai);
1140 	free(addr_str);
1141 
1142 	if (knot_edns_client_subnet_set_addr(&q->subnet, &ss) != KNOT_EOK) {
1143 		ERR("invalid address +subnet=%s\n", arg);
1144 		return KNOT_EINVAL;
1145 	}
1146 
1147 	// Parse network mask.
1148 	const char *mask = arg;
1149 	if (mask + addr_len < arg_end) {
1150 		mask += addr_len + 1;
1151 		uint8_t num = 0;
1152 		if (str_to_u8(mask, &num) != KNOT_EOK || num > q->subnet.source_len) {
1153 			ERR("invalid network mask +subnet=%s\n", arg);
1154 			return KNOT_EINVAL;
1155 		}
1156 		q->subnet.source_len = num;
1157 	}
1158 
1159 	return KNOT_EOK;
1160 }
1161 
opt_nosubnet(const char * arg,void * query)1162 static int opt_nosubnet(const char *arg, void *query)
1163 {
1164 	query_t *q = query;
1165 
1166 	q->subnet.family = AF_UNSPEC;
1167 
1168 	return KNOT_EOK;
1169 }
1170 
opt_edns(const char * arg,void * query)1171 static int opt_edns(const char *arg, void *query)
1172 {
1173 	query_t *q = query;
1174 
1175 	if (arg == NULL) {
1176 		q->edns = 0;
1177 		return KNOT_EOK;
1178 	} else {
1179 		uint8_t num = 0;
1180 		if (str_to_u8(arg, &num) != KNOT_EOK) {
1181 			ERR("invalid +edns=%s\n", arg);
1182 			return KNOT_EINVAL;
1183 		}
1184 
1185 		q->edns = num;
1186 		return KNOT_EOK;
1187 	}
1188 }
1189 
opt_noedns(const char * arg,void * query)1190 static int opt_noedns(const char *arg, void *query)
1191 {
1192 	query_t *q = query;
1193 
1194 	q->edns = -1;
1195 	opt_nodoflag(arg, query);
1196 	opt_nonsid(arg, query);
1197 	opt_nobufsize(arg, query);
1198 	opt_nocookie(arg, query);
1199 	opt_nopadding(arg, query);
1200 	opt_noalignment(arg, query);
1201 	opt_nosubnet(arg, query);
1202 
1203 	return KNOT_EOK;
1204 }
1205 
opt_timeout(const char * arg,void * query)1206 static int opt_timeout(const char *arg, void *query)
1207 {
1208 	query_t *q = query;
1209 
1210 	if (params_parse_wait(arg, &q->wait) != KNOT_EOK) {
1211 		ERR("invalid +timeout=%s\n", arg);
1212 		return KNOT_EINVAL;
1213 	}
1214 
1215 	return KNOT_EOK;
1216 }
1217 
opt_notimeout(const char * arg,void * query)1218 static int opt_notimeout(const char *arg, void *query)
1219 {
1220 	query_t *q = query;
1221 
1222 	(void)params_parse_wait("0", &q->wait);
1223 
1224 	return KNOT_EOK;
1225 }
1226 
opt_retry(const char * arg,void * query)1227 static int opt_retry(const char *arg, void *query)
1228 {
1229 	query_t *q = query;
1230 
1231 	if (str_to_u32(arg, &q->retries) != KNOT_EOK) {
1232 		ERR("invalid +retry=%s\n", arg);
1233 		return KNOT_EINVAL;
1234 	}
1235 
1236 	return KNOT_EOK;
1237 }
1238 
opt_noretry(const char * arg,void * query)1239 static int opt_noretry(const char *arg, void *query)
1240 {
1241 	query_t *q = query;
1242 
1243 	q->retries = 0;
1244 
1245 	return KNOT_EOK;
1246 }
1247 
parse_ednsopt(const char * arg,ednsopt_t ** opt_ptr)1248 static int parse_ednsopt(const char *arg, ednsopt_t **opt_ptr)
1249 {
1250 	errno = 0;
1251 	char *end = NULL;
1252 	unsigned long code = strtoul(arg, &end, 10);
1253 	if (errno != 0 || arg == end || code > UINT16_MAX) {
1254 		return KNOT_EINVAL;
1255 	}
1256 
1257 	size_t length = 0;
1258 	uint8_t *data = NULL;
1259 	if (end[0] == ':') {
1260 		if (end[1] != '\0') {
1261 			int ret = hex_decode(end + 1, &data, &length);
1262 			if (ret != KNOT_EOK) {
1263 				return ret;
1264 			}
1265 			if (length > UINT16_MAX) {
1266 				free(data);
1267 				return KNOT_ERANGE;
1268 			}
1269 		}
1270 	} else if (end[0] != '\0') {
1271 		return KNOT_EINVAL;
1272 	}
1273 
1274 	ednsopt_t *opt = ednsopt_create(code, length, data);
1275 	if (opt == NULL) {
1276 		free(data);
1277 		return KNOT_ENOMEM;
1278 	}
1279 
1280 	*opt_ptr = opt;
1281 	return KNOT_EOK;
1282 }
1283 
opt_ednsopt(const char * arg,void * query)1284 static int opt_ednsopt(const char *arg, void *query)
1285 {
1286 	query_t *q = query;
1287 
1288 	ednsopt_t *opt = NULL;
1289 	int ret = parse_ednsopt(arg, &opt);
1290 	if (ret != KNOT_EOK) {
1291 		ERR("invalid +ednsopt=%s\n", arg);
1292 		return KNOT_EINVAL;
1293 	}
1294 
1295 	add_tail(&q->edns_opts, &opt->n);
1296 
1297 	return KNOT_EOK;
1298 }
1299 
opt_noednsopt(const char * arg,void * query)1300 static int opt_noednsopt(const char *arg, void *query)
1301 {
1302 	query_t *q = query;
1303 
1304 	ednsopt_list_deinit(&q->edns_opts);
1305 
1306 	return KNOT_EOK;
1307 }
1308 
opt_noidn(const char * arg,void * query)1309 static int opt_noidn(const char *arg, void *query)
1310 {
1311 	query_t *q = query;
1312 
1313 	q->idn = false;
1314 	q->style.style.ascii_to_idn = NULL;
1315 
1316 	return KNOT_EOK;
1317 }
1318 
1319 static const param_t kdig_opts2[] = {
1320 	{ "multiline",      ARG_NONE,     opt_multiline },
1321 	{ "nomultiline",    ARG_NONE,     opt_nomultiline },
1322 
1323 	{ "short",          ARG_NONE,     opt_short },
1324 	{ "noshort",        ARG_NONE,     opt_noshort },
1325 
1326 	{ "generic",        ARG_NONE,     opt_generic },
1327 	{ "nogeneric",      ARG_NONE,     opt_nogeneric },
1328 
1329 	{ "aaflag",         ARG_NONE,     opt_aaflag },
1330 	{ "noaaflag",       ARG_NONE,     opt_noaaflag },
1331 
1332 	{ "tcflag",         ARG_NONE,     opt_tcflag },
1333 	{ "notcflag",       ARG_NONE,     opt_notcflag },
1334 
1335 	{ "rdflag",         ARG_NONE,     opt_rdflag },
1336 	{ "nordflag",       ARG_NONE,     opt_nordflag },
1337 
1338 	{ "recurse",        ARG_NONE,     opt_rdflag },
1339 	{ "norecurse",      ARG_NONE,     opt_nordflag },
1340 
1341 	{ "raflag",         ARG_NONE,     opt_raflag },
1342 	{ "noraflag",       ARG_NONE,     opt_noraflag },
1343 
1344 	{ "zflag",          ARG_NONE,     opt_zflag },
1345 	{ "nozflag",        ARG_NONE,     opt_nozflag },
1346 
1347 	{ "adflag",         ARG_NONE,     opt_adflag },
1348 	{ "noadflag",       ARG_NONE,     opt_noadflag },
1349 
1350 	{ "cdflag",         ARG_NONE,     opt_cdflag },
1351 	{ "nocdflag",       ARG_NONE,     opt_nocdflag },
1352 
1353 	{ "dnssec",         ARG_NONE,     opt_doflag },
1354 	{ "nodnssec",       ARG_NONE,     opt_nodoflag },
1355 
1356 	{ "all",            ARG_NONE,     opt_all },
1357 	{ "noall",          ARG_NONE,     opt_noall },
1358 
1359 	{ "qr",             ARG_NONE,     opt_qr },
1360 	{ "noqr",           ARG_NONE,     opt_noqr },
1361 
1362 	{ "header",         ARG_NONE,     opt_header },
1363 	{ "noheader",       ARG_NONE,     opt_noheader },
1364 
1365 	{ "comments",       ARG_NONE,     opt_comments },
1366 	{ "nocomments",     ARG_NONE,     opt_nocomments },
1367 
1368 	{ "opt",            ARG_NONE,     opt_opt },
1369 	{ "noopt",          ARG_NONE,     opt_noopt },
1370 
1371 	{ "opttext",        ARG_NONE,     opt_opttext },
1372 	{ "noopttext",      ARG_NONE,     opt_noopttext },
1373 
1374 	{ "question",       ARG_NONE,     opt_question },
1375 	{ "noquestion",     ARG_NONE,     opt_noquestion },
1376 
1377 	{ "answer",         ARG_NONE,     opt_answer },
1378 	{ "noanswer",       ARG_NONE,     opt_noanswer },
1379 
1380 	{ "authority",      ARG_NONE,     opt_authority },
1381 	{ "noauthority",    ARG_NONE,     opt_noauthority },
1382 
1383 	{ "additional",     ARG_NONE,     opt_additional },
1384 	{ "noadditional",   ARG_NONE,     opt_noadditional },
1385 
1386 	{ "tsig",           ARG_NONE,     opt_tsig },
1387 	{ "notsig",         ARG_NONE,     opt_notsig },
1388 
1389 	{ "stats",          ARG_NONE,     opt_stats },
1390 	{ "nostats",        ARG_NONE,     opt_nostats },
1391 
1392 	{ "class",          ARG_NONE,     opt_class },
1393 	{ "noclass",        ARG_NONE,     opt_noclass },
1394 
1395 	{ "ttl",            ARG_NONE,     opt_ttl },
1396 	{ "nottl",          ARG_NONE,     opt_nottl },
1397 
1398 	{ "crypto",         ARG_NONE,     opt_crypto },
1399 	{ "nocrypto",       ARG_NONE,     opt_nocrypto },
1400 
1401 	{ "tcp",            ARG_NONE,     opt_tcp },
1402 	{ "notcp",          ARG_NONE,     opt_notcp },
1403 
1404 	{ "fastopen",       ARG_NONE,     opt_fastopen },
1405 	{ "nofastopen",     ARG_NONE,     opt_nofastopen },
1406 
1407 	{ "ignore",         ARG_NONE,     opt_ignore },
1408 	{ "noignore",       ARG_NONE,     opt_noignore },
1409 
1410 	{ "keepopen",       ARG_NONE,     opt_keepopen },
1411 	{ "nokeepopen",     ARG_NONE,     opt_nokeepopen },
1412 
1413 	{ "tls",            ARG_NONE,     opt_tls },
1414 	{ "notls",          ARG_NONE,     opt_notls },
1415 
1416 	{ "tls-ca",         ARG_OPTIONAL, opt_tls_ca },
1417 	{ "notls-ca",       ARG_NONE,     opt_notls_ca },
1418 
1419 	{ "tls-pin",        ARG_REQUIRED, opt_tls_pin },
1420 	{ "notls-pin",      ARG_NONE,     opt_notls_pin },
1421 
1422 	{ "tls-hostname",   ARG_REQUIRED, opt_tls_hostname },
1423 	{ "notls-hostname", ARG_NONE,     opt_notls_hostname },
1424 
1425 	{ "tls-sni",        ARG_REQUIRED, opt_tls_sni },
1426 	{ "notls-sni",      ARG_NONE,     opt_notls_sni },
1427 
1428 	{ "tls-keyfile",    ARG_REQUIRED, opt_tls_keyfile },
1429 	{ "notls-keyfile",  ARG_NONE,     opt_notls_keyfile },
1430 
1431 	{ "tls-certfile",   ARG_REQUIRED, opt_tls_certfile },
1432 	{ "notls-certfile", ARG_NONE,     opt_notls_certfile },
1433 
1434 	{ "tls-ocsp-stapling",   ARG_OPTIONAL, opt_tls_ocsp_stapling },
1435 	{ "notls-ocsp-stapling", ARG_NONE,     opt_notls_ocsp_stapling },
1436 
1437 	{ "https",          ARG_OPTIONAL, opt_https },
1438 	{ "nohttps",        ARG_NONE,     opt_nohttps },
1439 
1440 	{ "https-get",      ARG_NONE,     opt_https_get },
1441 	{ "nohttps-get",    ARG_NONE,     opt_nohttps_get },
1442 
1443 	{ "nsid",           ARG_NONE,     opt_nsid },
1444 	{ "nonsid",         ARG_NONE,     opt_nonsid },
1445 
1446 	{ "bufsize",        ARG_REQUIRED, opt_bufsize },
1447 	{ "nobufsize",      ARG_NONE,     opt_nobufsize },
1448 
1449 	{ "padding",        ARG_OPTIONAL, opt_padding },
1450 	{ "nopadding",      ARG_NONE,     opt_nopadding },
1451 
1452 	{ "alignment",      ARG_OPTIONAL, opt_alignment },
1453 	{ "noalignment",    ARG_NONE,     opt_noalignment },
1454 
1455 	{ "subnet",         ARG_REQUIRED, opt_subnet },
1456 	{ "nosubnet",       ARG_NONE,     opt_nosubnet },
1457 
1458 	// Obsolete aliases.
1459 	{ "client",         ARG_REQUIRED, opt_subnet },
1460 	{ "noclient",       ARG_NONE,     opt_nosubnet },
1461 
1462 	{ "edns",           ARG_OPTIONAL, opt_edns },
1463 	{ "noedns",         ARG_NONE,     opt_noedns },
1464 
1465 	{ "timeout",        ARG_REQUIRED, opt_timeout },
1466 	{ "notimeout",      ARG_NONE,     opt_notimeout },
1467 
1468 	{ "retry",          ARG_REQUIRED, opt_retry },
1469 	{ "noretry",        ARG_NONE,     opt_noretry },
1470 
1471 	{ "cookie",         ARG_OPTIONAL, opt_cookie },
1472 	{ "nocookie",       ARG_NONE,     opt_nocookie },
1473 
1474 	{ "badcookie",      ARG_NONE,     opt_badcookie },
1475 	{ "nobadcookie",    ARG_NONE,     opt_nobadcookie },
1476 
1477 	{ "ednsopt",        ARG_REQUIRED, opt_ednsopt },
1478 	{ "noednsopt",      ARG_NONE,     opt_noednsopt },
1479 
1480 	/* "idn" doesn't work since it must be called before query creation. */
1481 	{ "noidn",          ARG_NONE,     opt_noidn },
1482 
1483 	{ NULL }
1484 };
1485 
query_create(const char * owner,const query_t * conf)1486 query_t *query_create(const char *owner, const query_t *conf)
1487 {
1488 	// Create output structure.
1489 	query_t *query = calloc(1, sizeof(query_t));
1490 
1491 	if (query == NULL) {
1492 		DBG_NULL;
1493 		return NULL;
1494 	}
1495 
1496 	// Initialization with defaults or with reference query.
1497 	if (conf == NULL) {
1498 		query->conf = NULL;
1499 		query->local = NULL;
1500 		query->operation = OPERATION_QUERY;
1501 		query->ip = IP_ALL;
1502 		query->protocol = PROTO_ALL;
1503 		query->fastopen = false;
1504 		query->port = strdup("");
1505 		query->udp_size = -1;
1506 		query->retries = DEFAULT_RETRIES_DIG;
1507 		query->wait = DEFAULT_TIMEOUT_DIG;
1508 		query->ignore_tc = false;
1509 		query->class_num = -1;
1510 		query->type_num = -1;
1511 		query->serial = -1;
1512 		query->notify = false;
1513 		query->flags = DEFAULT_FLAGS_DIG;
1514 		query->style = DEFAULT_STYLE_DIG;
1515 		query->idn = true;
1516 		query->nsid = false;
1517 		query->edns = -1;
1518 		query->cc.len = 0;
1519 		query->sc.len = 0;
1520 		query->badcookie = BADCOOKIE_RETRY_MAX;
1521 		query->padding = -1;
1522 		query->alignment = 0;
1523 		tls_params_init(&query->tls);
1524 		//query->tsig_key
1525 		query->subnet.family = AF_UNSPEC;
1526 		ednsopt_list_init(&query->edns_opts);
1527 #if USE_DNSTAP
1528 		query->dt_reader = NULL;
1529 		query->dt_writer = NULL;
1530 #endif // USE_DNSTAP
1531 	} else {
1532 		*query = *conf;
1533 		query->conf = conf;
1534 		if (conf->local != NULL) {
1535 			query->local = srv_info_create(conf->local->name,
1536 			                               conf->local->service);
1537 			if (query->local == NULL) {
1538 				query_free(query);
1539 				return NULL;
1540 			}
1541 		} else {
1542 			query->local = NULL;
1543 		}
1544 		query->port = strdup(conf->port);
1545 		tls_params_copy(&query->tls, &conf->tls);
1546 		https_params_copy(&query->https, &conf->https);
1547 		if (conf->tsig_key.name != NULL) {
1548 			int ret = knot_tsig_key_copy(&query->tsig_key,
1549 			                             &conf->tsig_key);
1550 			if (ret != KNOT_EOK) {
1551 				query_free(query);
1552 				return NULL;
1553 			}
1554 		}
1555 
1556 		int ret = ednsopt_list_dup(&query->edns_opts, &conf->edns_opts);
1557 		if (ret != KNOT_EOK) {
1558 			query_free(query);
1559 			return NULL;
1560 		}
1561 
1562 #if USE_DNSTAP
1563 		query->dt_reader = conf->dt_reader;
1564 		query->dt_writer = conf->dt_writer;
1565 #endif // USE_DNSTAP
1566 	}
1567 
1568 	// Initialize list of servers.
1569 	init_list(&query->servers);
1570 
1571 	// Set the query owner if any.
1572 	if (owner != NULL) {
1573 		if ((query->owner = strdup(owner)) == NULL) {
1574 			query_free(query);
1575 			return NULL;
1576 		}
1577 	}
1578 
1579 	// Check dynamic allocation.
1580 	if (query->port == NULL) {
1581 		query_free(query);
1582 		return NULL;
1583 	}
1584 
1585 	return query;
1586 }
1587 
query_free(query_t * query)1588 void query_free(query_t *query)
1589 {
1590 	node_t *n, *nxt;
1591 
1592 	if (query == NULL) {
1593 		DBG_NULL;
1594 		return;
1595 	}
1596 
1597 	// Cleanup servers.
1598 	WALK_LIST_DELSAFE(n, nxt, query->servers) {
1599 		srv_info_free((srv_info_t *)n);
1600 	}
1601 
1602 	// Cleanup local address.
1603 	if (query->local != NULL) {
1604 		srv_info_free(query->local);
1605 	}
1606 
1607 	tls_params_clean(&query->tls);
1608 	https_params_clean(&query->https);
1609 
1610 	// Cleanup signing key.
1611 	knot_tsig_key_deinit(&query->tsig_key);
1612 
1613 	// Cleanup EDNS options.
1614 	ednsopt_list_deinit(&query->edns_opts);
1615 
1616 #if USE_DNSTAP
1617 	if (query->dt_reader != NULL) {
1618 		dt_reader_free(query->dt_reader);
1619 	}
1620 	if (query->dt_writer != NULL) {
1621 		// Global writer can be shared!
1622 		if (query->conf == NULL ||
1623 		    query->conf->dt_writer != query->dt_writer) {
1624 			dt_writer_free(query->dt_writer);
1625 		}
1626 	}
1627 #endif // USE_DNSTAP
1628 
1629 	free(query->owner);
1630 	free(query->port);
1631 	free(query);
1632 }
1633 
ednsopt_create(uint16_t code,uint16_t length,uint8_t * data)1634 ednsopt_t *ednsopt_create(uint16_t code, uint16_t length, uint8_t *data)
1635 {
1636 	ednsopt_t *opt = calloc(1, sizeof(*opt));
1637 	if (opt == NULL) {
1638 		return NULL;
1639 	}
1640 
1641 	opt->code = code;
1642 	opt->length = length;
1643 	opt->data = data;
1644 
1645 	return opt;
1646 }
1647 
ednsopt_dup(const ednsopt_t * opt)1648 ednsopt_t *ednsopt_dup(const ednsopt_t *opt)
1649 {
1650 	ednsopt_t *dup = calloc(1, sizeof(*opt));
1651 	if (dup == NULL) {
1652 		return NULL;
1653 	}
1654 
1655 	dup->code = opt->code;
1656 	dup->length = opt->length;
1657 	dup->data = memdup(opt->data, opt->length);
1658 	if (dup->data == NULL) {
1659 		free(dup);
1660 		return NULL;
1661 	}
1662 
1663 	return dup;
1664 }
1665 
ednsopt_free(ednsopt_t * opt)1666 void ednsopt_free(ednsopt_t *opt)
1667 {
1668 	if (opt == NULL) {
1669 		return;
1670 	}
1671 
1672 	free(opt->data);
1673 	free(opt);
1674 }
1675 
ednsopt_list_init(list_t * list)1676 void ednsopt_list_init(list_t *list)
1677 {
1678 	init_list(list);
1679 }
1680 
ednsopt_list_deinit(list_t * list)1681 void ednsopt_list_deinit(list_t *list)
1682 {
1683 	node_t *n, *next;
1684 	WALK_LIST_DELSAFE(n, next, *list) {
1685 		ednsopt_t *opt = (ednsopt_t *)n;
1686 		ednsopt_free(opt);
1687 	}
1688 
1689 	init_list(list);
1690 }
1691 
ednsopt_list_dup(list_t * dest,const list_t * src)1692 int ednsopt_list_dup(list_t *dest, const list_t *src)
1693 {
1694 	list_t backup = *dest;
1695 	init_list(dest);
1696 
1697 	node_t *n;
1698 	WALK_LIST(n, *src) {
1699 		ednsopt_t *opt = (ednsopt_t *)n;
1700 		ednsopt_t *dup = ednsopt_dup(opt);
1701 		if (dup == NULL) {
1702 			ednsopt_list_deinit(dest);
1703 			*dest = backup;
1704 			return KNOT_ENOMEM;
1705 		}
1706 
1707 		add_tail(dest, &dup->n);
1708 	}
1709 
1710 	return KNOT_EOK;
1711 }
1712 
ednsopt_list_empty(const list_t * list)1713 bool ednsopt_list_empty(const list_t *list)
1714 {
1715 	return EMPTY_LIST(*list);
1716 }
1717 
kdig_init(kdig_params_t * params)1718 int kdig_init(kdig_params_t *params)
1719 {
1720 	if (params == NULL) {
1721 		DBG_NULL;
1722 		return KNOT_EINVAL;
1723 	}
1724 
1725 	memset(params, 0, sizeof(*params));
1726 
1727 	params->stop = false;
1728 
1729 	// Initialize list of queries.
1730 	init_list(&params->queries);
1731 
1732 	// Create config query.
1733 	if ((params->config = query_create(NULL, NULL)) == NULL) {
1734 		return KNOT_ENOMEM;
1735 	}
1736 
1737 	return KNOT_EOK;
1738 }
1739 
kdig_clean(kdig_params_t * params)1740 void kdig_clean(kdig_params_t *params)
1741 {
1742 	node_t *n, *nxt;
1743 
1744 	if (params == NULL) {
1745 		DBG_NULL;
1746 		return;
1747 	}
1748 
1749 	// Clean up queries.
1750 	WALK_LIST_DELSAFE(n, nxt, params->queries) {
1751 		query_free((query_t *)n);
1752 	}
1753 
1754 	// Clean up config.
1755 	query_free(params->config);
1756 
1757 	// Clean up the structure.
1758 	memset(params, 0, sizeof(*params));
1759 }
1760 
parse_class(const char * value,query_t * query)1761 static int parse_class(const char *value, query_t *query)
1762 {
1763 	uint16_t rclass;
1764 
1765 	if (params_parse_class(value, &rclass) != KNOT_EOK) {
1766 		return KNOT_EINVAL;
1767 	}
1768 
1769 	query->class_num = rclass;
1770 
1771 	return KNOT_EOK;
1772 }
1773 
parse_keyfile(const char * value,query_t * query)1774 static int parse_keyfile(const char *value, query_t *query)
1775 {
1776 	knot_tsig_key_deinit(&query->tsig_key);
1777 
1778 	if (knot_tsig_key_init_file(&query->tsig_key, value) != KNOT_EOK) {
1779 		return KNOT_EINVAL;
1780 	}
1781 
1782 	return KNOT_EOK;
1783 }
1784 
parse_local(const char * value,query_t * query)1785 static int parse_local(const char *value, query_t *query)
1786 {
1787 	srv_info_t *local = parse_nameserver(value, "0");
1788 	if (local == NULL) {
1789 		return KNOT_EINVAL;
1790 	}
1791 
1792 	if (query->local != NULL) {
1793 		srv_info_free(query->local);
1794 	}
1795 
1796 	query->local = local;
1797 
1798 	return KNOT_EOK;
1799 }
1800 
parse_name(const char * value,list_t * queries,const query_t * conf)1801 static int parse_name(const char *value, list_t *queries, const query_t *conf)
1802 {
1803 	query_t	*query = NULL;
1804 	char	*ascii_name = (char *)value;
1805 	char	*fqd_name = NULL;
1806 
1807 	if (value != NULL) {
1808 		if (conf->idn) {
1809 			ascii_name = name_from_idn(value);
1810 			if (ascii_name == NULL) {
1811 				return KNOT_EINVAL;
1812 			}
1813 		}
1814 
1815 		// If name is not FQDN, append trailing dot.
1816 		fqd_name = get_fqd_name(ascii_name);
1817 
1818 		if (conf->idn) {
1819 			free(ascii_name);
1820 		}
1821 	}
1822 
1823 	// Create new query.
1824 	query = query_create(fqd_name, conf);
1825 
1826 	free(fqd_name);
1827 
1828 	if (query == NULL) {
1829 		return KNOT_ENOMEM;
1830 	}
1831 
1832 	// Add new query to the queries.
1833 	add_tail(queries, (node_t *)query);
1834 
1835 	return KNOT_EOK;
1836 }
1837 
parse_port(const char * value,query_t * query)1838 static int parse_port(const char *value, query_t *query)
1839 {
1840 	char **port;
1841 
1842 	// Set current server port (last or query default).
1843 	if (list_size(&query->servers) > 0) {
1844 		srv_info_t *server = TAIL(query->servers);
1845 		port = &(server->service);
1846 	} else {
1847 		port = &(query->port);
1848 	}
1849 
1850 	char *new_port = strdup(value);
1851 
1852 	if (new_port == NULL) {
1853 		return KNOT_ENOMEM;
1854 	}
1855 
1856 	// Deallocate old string.
1857 	free(*port);
1858 
1859 	*port = new_port;
1860 
1861 	return KNOT_EOK;
1862 }
1863 
parse_reverse(const char * value,list_t * queries,const query_t * conf)1864 static int parse_reverse(const char *value, list_t *queries, const query_t *conf)
1865 {
1866 	query_t *query = NULL;
1867 
1868 	// Create reverse name.
1869 	char *reverse = get_reverse_name(value);
1870 
1871 	if (reverse == NULL) {
1872 		return KNOT_EINVAL;
1873 	}
1874 
1875 	// Create reverse query for given address.
1876 	query = query_create(reverse, conf);
1877 
1878 	free(reverse);
1879 
1880 	if (query == NULL) {
1881 		return KNOT_ENOMEM;
1882 	}
1883 
1884 	// Set type for reverse query.
1885 	query->type_num = KNOT_RRTYPE_PTR;
1886 
1887 	// Add new query to the queries.
1888 	add_tail(queries, (node_t *)query);
1889 
1890 	return KNOT_EOK;
1891 }
1892 
parse_server(const char * value,kdig_params_t * params)1893 static int parse_server(const char *value, kdig_params_t *params)
1894 {
1895 	query_t *query;
1896 
1897 	// Set current query (last or config).
1898 	if (list_size(&params->queries) > 0) {
1899 		query = TAIL(params->queries);
1900 	} else {
1901 		query = params->config;
1902 	}
1903 
1904 	if (params_parse_server(value, &query->servers, query->port) != KNOT_EOK) {
1905 		ERR("invalid server @%s\n", value);
1906 		return KNOT_EINVAL;
1907 	}
1908 
1909 	return KNOT_EOK;
1910 }
1911 
parse_tsig(const char * value,query_t * query)1912 static int parse_tsig(const char *value, query_t *query)
1913 {
1914 	knot_tsig_key_deinit(&query->tsig_key);
1915 
1916 	if (knot_tsig_key_init_str(&query->tsig_key, value) != KNOT_EOK) {
1917 		return KNOT_EINVAL;
1918 	}
1919 
1920 	return KNOT_EOK;
1921 }
1922 
parse_type(const char * value,query_t * query)1923 static int parse_type(const char *value, query_t *query)
1924 {
1925 	uint16_t rtype;
1926 	int64_t  serial;
1927 	bool     notify;
1928 
1929 	if (params_parse_type(value, &rtype, &serial, &notify) != KNOT_EOK) {
1930 		return KNOT_EINVAL;
1931 	}
1932 
1933 	query->type_num = rtype;
1934 	query->serial = serial;
1935 	query->notify = notify;
1936 
1937 	// If NOTIFY, reset default RD flag.
1938 	if (query->notify) {
1939 		query->flags.rd_flag = false;
1940 	}
1941 
1942 	return KNOT_EOK;
1943 }
1944 
1945 #if USE_DNSTAP
parse_dnstap_output(const char * value,query_t * query)1946 static int parse_dnstap_output(const char *value, query_t *query)
1947 {
1948 	if (query->dt_writer != NULL) {
1949 		if (query->conf == NULL ||
1950 		    query->conf->dt_writer != query->dt_writer) {
1951 			dt_writer_free(query->dt_writer);
1952 		}
1953 	}
1954 
1955 	query->dt_writer = dt_writer_create(value, "kdig " PACKAGE_VERSION);
1956 	if (query->dt_writer == NULL) {
1957 		return KNOT_EINVAL;
1958 	}
1959 
1960 	return KNOT_EOK;
1961 }
1962 
parse_dnstap_input(const char * value,query_t * query)1963 static int parse_dnstap_input(const char *value, query_t *query)
1964 {
1965 	// Just in case, shouldn't happen.
1966 	if (query->dt_reader != NULL) {
1967 		dt_reader_free(query->dt_reader);
1968 	}
1969 
1970 	query->dt_reader = dt_reader_create(value);
1971 	if (query->dt_reader == NULL) {
1972 		return KNOT_EINVAL;
1973 	}
1974 
1975 	return KNOT_EOK;
1976 }
1977 #endif // USE_DNSTAP
1978 
complete_servers(query_t * query,const query_t * conf)1979 static void complete_servers(query_t *query, const query_t *conf)
1980 {
1981 	node_t *n;
1982 	char *def_port;
1983 
1984 	// Decide which default port use.
1985 	if (strlen(query->port) > 0) {
1986 		def_port = query->port;
1987 	} else if (strlen(conf->port) > 0) {
1988 		def_port = conf->port;
1989 	} else if (query->https.enable) {
1990 		def_port = DEFAULT_DNS_HTTPS_PORT;
1991 	} else if (query->tls.enable) {
1992 		def_port = DEFAULT_DNS_TLS_PORT;
1993 	} else {
1994 		def_port = DEFAULT_DNS_PORT;
1995 	}
1996 
1997 	// Complete specified nameservers if any.
1998 	if (list_size(&query->servers) > 0) {
1999 		WALK_LIST(n, query->servers) {
2000 			srv_info_t *s = (srv_info_t *)n;
2001 
2002 			// If the port isn't specified yet use the default one.
2003 			if (strlen(s->service) == 0) {
2004 				free(s->service);
2005 				s->service = strdup(def_port);
2006 				if (s->service == NULL) {
2007 					WARN("can't set port %s\n", def_port);
2008 					return;
2009 				}
2010 			}
2011 
2012 			// Use server name as hostname for TLS if necessary.
2013 			if (query->tls.enable && query->tls.hostname == NULL &&
2014 			    (query->tls.system_ca || !EMPTY_LIST(query->tls.ca_files))) {
2015 				query->tls.hostname = strdup(s->name);
2016 			}
2017 		}
2018 	// Use servers from config if any.
2019 	} else if (list_size(&conf->servers) > 0) {
2020 		WALK_LIST(n, conf->servers) {
2021 			srv_info_t *s = (srv_info_t *)n;
2022 			char     *port = def_port;
2023 
2024 			// If the port is already specified, use it.
2025 			if (strlen(s->service) > 0) {
2026 				port = s->service;
2027 			}
2028 
2029 			srv_info_t *server = srv_info_create(s->name, port);
2030 			if (server == NULL) {
2031 				WARN("can't set nameserver %s port %s\n",
2032 				     s->name, s->service);
2033 				return;
2034 			}
2035 			add_tail(&query->servers, (node_t *)server);
2036 
2037 			// Use server name as hostname for TLS if necessary.
2038 			if (query->tls.enable && query->tls.hostname == NULL &&
2039 			    (query->tls.system_ca || !EMPTY_LIST(query->tls.ca_files))) {
2040 				query->tls.hostname = strdup(s->name);
2041 			}
2042 		}
2043 	// Use system specific.
2044 	} else {
2045 		get_nameservers(&query->servers, def_port);
2046 	}
2047 }
2048 
compare_servers(list_t * s1,list_t * s2)2049 static bool compare_servers(list_t *s1, list_t *s2)
2050 {
2051 	if (list_size(s1) != list_size(s2)) {
2052 		return false;
2053 	}
2054 
2055 	node_t *n1, *n2 = HEAD(*s2);
2056 	WALK_LIST(n1, *s1) {
2057 		srv_info_t *i1 = (srv_info_t *)n1, *i2 = (srv_info_t *)n2;
2058 		if (strcmp(i1->service, i2->service) != 0 ||
2059 		    strcmp(i1->name, i2->name) != 0)
2060 		{
2061 			return false;
2062 		}
2063 		n2 = n2->next;
2064 	}
2065 	return true;
2066 }
2067 
complete_queries(list_t * queries,const query_t * conf)2068 void complete_queries(list_t *queries, const query_t *conf)
2069 {
2070 	node_t  *n;
2071 
2072 	if (queries == NULL || conf == NULL) {
2073 		DBG_NULL;
2074 		return;
2075 	}
2076 
2077 	// If there is no query, add default query: NS to ".".
2078 	if (list_size(queries) == 0) {
2079 		query_t *q = query_create(".", conf);
2080 		if (q == NULL) {
2081 			WARN("can't create query . NS IN\n");
2082 			return;
2083 		}
2084 		q->class_num = KNOT_CLASS_IN;
2085 		q->type_num = KNOT_RRTYPE_NS;
2086 		add_tail(queries, (node_t *)q);
2087 	}
2088 
2089 	WALK_LIST(n, *queries) {
2090 		query_t *q = (query_t *)n;
2091 		query_t *q_prev = (HEAD(*queries) != n) ? (query_t *)n->prev : NULL;
2092 
2093 		// Fill class number if missing.
2094 		if (q->class_num < 0) {
2095 			if (conf->class_num >= 0) {
2096 				q->class_num = conf->class_num;
2097 			} else {
2098 				q->class_num = KNOT_CLASS_IN;
2099 			}
2100 		}
2101 
2102 		// Fill type number if missing.
2103 		if (q->type_num < 0) {
2104 			if (conf->type_num >= 0) {
2105 				q->type_num = conf->type_num;
2106 				q->serial = conf->serial;
2107 			} else {
2108 				q->type_num = KNOT_RRTYPE_A;
2109 			}
2110 		}
2111 
2112 		// Set zone transfer if any.
2113 		if (q->type_num == KNOT_RRTYPE_AXFR ||
2114 		    q->type_num == KNOT_RRTYPE_IXFR) {
2115 			q->operation = OPERATION_XFR;
2116 		}
2117 
2118 		// No retries for TCP.
2119 		if (q->protocol == PROTO_TCP) {
2120 			q->retries = 0;
2121 		}
2122 
2123 		// Complete nameservers list.
2124 		complete_servers(q, conf);
2125 
2126 		// Check if using previous connection makes sense.
2127 		if (q_prev != NULL && q_prev->keepopen &&
2128 		    (get_socktype(q->protocol, q->type_num) !=
2129 		     get_socktype(q_prev->protocol, q_prev->type_num) ||
2130 		     q->https.enable != q_prev->https.enable ||
2131 		     q->tls.enable != q_prev->tls.enable ||
2132 		     strcmp(q->port, q_prev->port) != 0 ||
2133 		     !compare_servers(&q->servers, &q_prev->servers)))
2134 		{
2135 			WARN("connection parameters mismatch for query (%s), "
2136 			     "ignoring keepopen\n", q->owner);
2137 			q_prev->keepopen = false;
2138 		}
2139 	}
2140 }
2141 
print_help(void)2142 static void print_help(void)
2143 {
2144 	printf("Usage: %s [-4] [-6] [-d] [-b address] [-c class] [-p port]\n"
2145 	       "            [-q name] [-t type] [-x address] [-k keyfile]\n"
2146 	       "            [-y [algo:]keyname:key] [-E tapfile] [-G tapfile]\n"
2147 	       "            name [type] [class] [@server]\n"
2148 	       "\n"
2149 	       "       +[no]multiline             Wrap long records to more lines.\n"
2150 	       "       +[no]short                 Show record data only.\n"
2151 	       "       +[no]generic               Use generic representation format.\n"
2152 	       "       +[no]aaflag                Set AA flag.\n"
2153 	       "       +[no]tcflag                Set TC flag.\n"
2154 	       "       +[no]rdflag                Set RD flag.\n"
2155 	       "       +[no]recurse               Same as +[no]rdflag\n"
2156 	       "       +[no]raflag                Set RA flag.\n"
2157 	       "       +[no]zflag                 Set zero flag bit.\n"
2158 	       "       +[no]adflag                Set AD flag.\n"
2159 	       "       +[no]cdflag                Set CD flag.\n"
2160 	       "       +[no]dnssec                Set DO flag.\n"
2161 	       "       +[no]all                   Show all packet sections.\n"
2162 	       "       +[no]qr                    Show query packet.\n"
2163 	       "       +[no]header                Show packet header.\n"
2164 	       "       +[no]comments              Show commented section names.\n"
2165 	       "       +[no]opt                   Show EDNS pseudosection.\n"
2166 	       "       +[no]opttext               Try to show unknown EDNS options as text.\n"
2167 	       "       +[no]question              Show question section.\n"
2168 	       "       +[no]answer                Show answer section.\n"
2169 	       "       +[no]authority             Show authority section.\n"
2170 	       "       +[no]additional            Show additional section.\n"
2171 	       "       +[no]tsig                  Show TSIG pseudosection.\n"
2172 	       "       +[no]stats                 Show trailing packet statistics.\n"
2173 	       "       +[no]class                 Show DNS class.\n"
2174 	       "       +[no]ttl                   Show TTL value.\n"
2175 	       "       +[no]crypto                Show binary parts of RRSIGs and DNSKEYs.\n"
2176 	       "       +[no]tcp                   Use TCP protocol.\n"
2177 	       "       +[no]fastopen              Use TCP Fast Open.\n"
2178 	       "       +[no]ignore                Don't use TCP automatically if truncated.\n"
2179 	       "       +[no]keepopen              Don't close the TCP connection to be reused.\n"
2180 	       "       +[no]tls                   Use TLS with Opportunistic privacy profile.\n"
2181 	       "       +[no]tls-ca[=FILE]         Use TLS with Out-Of-Band privacy profile.\n"
2182 	       "       +[no]tls-pin=BASE64        Use TLS with pinned certificate.\n"
2183 	       "       +[no]tls-hostname=STR      Use TLS with remote server hostname.\n"
2184 	       "       +[no]tls-sni=STR           Use TLS with Server Name Indication.\n"
2185 	       "       +[no]tls-keyfile=FILE      Use TLS with a client keyfile.\n"
2186 	       "       +[no]tls-certfile=FILE     Use TLS with a client certfile.\n"
2187 	       "       +[no]tls-ocsp-stapling[=H] Use TLS with a valid stapled OCSP response for the\n"
2188 	       "                                  server certificate (%u or specify hours).\n"
2189 #ifdef LIBNGHTTP2
2190 	       "       +[no]https[=URL]           Use HTTPS protocol. It's also possible to specify\n"
2191 	       "                                  URL as [authority][/path] where query will be sent.\n"
2192 	       "       +[no]https-get             Use HTTPS protocol with GET method instead of POST.\n"
2193 #endif
2194 	       "       +[no]nsid                  Request NSID.\n"
2195 	       "       +[no]bufsize=B             Set EDNS buffer size.\n"
2196 	       "       +[no]padding[=N]           Pad with EDNS(0) (default or specify size).\n"
2197 	       "       +[no]alignment[=N]         Pad with EDNS(0) to blocksize (%u or specify size).\n"
2198 	       "       +[no]subnet=SUBN           Set EDNS(0) client subnet addr/prefix.\n"
2199 	       "       +[no]edns[=N]              Use EDNS(=version).\n"
2200 	       "       +[no]timeout=T             Set wait for reply interval in seconds.\n"
2201 	       "       +[no]retry=N               Set number of retries.\n"
2202 	       "       +[no]cookie=HEX            Attach EDNS(0) cookie to the query.\n"
2203 	       "       +[no]badcookie             Repeat a query with the correct cookie.\n"
2204 	       "       +[no]ednsopt=CODE[:HEX]    Set custom EDNS option.\n"
2205 	       "       +noidn                     Disable IDN transformation.\n"
2206 	       "\n"
2207 	       "       -h, --help                 Print the program help.\n"
2208 	       "       -V, --version              Print the program version.\n",
2209 	       PROGRAM_NAME, DEFAULT_TLS_OCSP_STAPLING / 3600, DEFAULT_ALIGNMENT_SIZE);
2210 }
2211 
parse_opt1(const char * opt,const char * value,kdig_params_t * params,int * index)2212 static int parse_opt1(const char *opt, const char *value, kdig_params_t *params,
2213                       int *index)
2214 {
2215 	const char *val = value;
2216 	size_t     len = strlen(opt);
2217 	int        add = 1;
2218 	query_t    *query;
2219 
2220 	// Set current query (last or config).
2221 	if (list_size(&params->queries) > 0) {
2222 		query = TAIL(params->queries);
2223 	} else {
2224 		query = params->config;
2225 	}
2226 
2227 	// If there is no space between option and argument.
2228 	if (len > 1) {
2229 		val = opt + 1;
2230 		add = 0;
2231 	}
2232 
2233 	switch (opt[0]) {
2234 	case '4':
2235 		if (len > 1) {
2236 			ERR("invalid option -%s\n", opt);
2237 			return KNOT_ENOTSUP;
2238 		}
2239 
2240 		query->ip = IP_4;
2241 		break;
2242 	case '6':
2243 		if (len > 1) {
2244 			ERR("invalid option -%s\n", opt);
2245 			return KNOT_ENOTSUP;
2246 		}
2247 
2248 		query->ip = IP_6;
2249 		break;
2250 	case 'b':
2251 		if (val == NULL) {
2252 			ERR("missing address\n");
2253 			return KNOT_EINVAL;
2254 		}
2255 
2256 		if (parse_local(val, query) != KNOT_EOK) {
2257 			ERR("bad address %s\n", val);
2258 			return KNOT_EINVAL;
2259 		}
2260 		*index += add;
2261 		break;
2262 	case 'd':
2263 		msg_enable_debug(1);
2264 		break;
2265 	case 'h':
2266 		if (len > 1) {
2267 			ERR("invalid option -%s\n", opt);
2268 			return KNOT_ENOTSUP;
2269 		}
2270 
2271 		print_help();
2272 		params->stop = true;
2273 		break;
2274 	case 'c':
2275 		if (val == NULL) {
2276 			ERR("missing class\n");
2277 			return KNOT_EINVAL;
2278 		}
2279 
2280 		if (parse_class(val, query) != KNOT_EOK) {
2281 			ERR("bad class %s\n", val);
2282 			return KNOT_EINVAL;
2283 		}
2284 		*index += add;
2285 		break;
2286 	case 'k':
2287 		if (val == NULL) {
2288 			ERR("missing filename\n");
2289 			return KNOT_EINVAL;
2290 		}
2291 
2292 		if (parse_keyfile(val, query) != KNOT_EOK) {
2293 			ERR("bad keyfile %s\n", value);
2294 			return KNOT_EINVAL;
2295 		}
2296 		*index += add;
2297 		break;
2298 	case 'p':
2299 		if (val == NULL) {
2300 			ERR("missing port\n");
2301 			return KNOT_EINVAL;
2302 		}
2303 
2304 		if (parse_port(val, query) != KNOT_EOK) {
2305 			ERR("bad port %s\n", value);
2306 			return KNOT_EINVAL;
2307 		}
2308 		*index += add;
2309 		break;
2310 	case 'q':
2311 		// Allow empty QNAME.
2312 		if (parse_name(val, &params->queries, params->config)
2313 		    != KNOT_EOK) {
2314 			ERR("bad query name %s\n", val);
2315 			return KNOT_EINVAL;
2316 		}
2317 		*index += add;
2318 		break;
2319 	case 't':
2320 		if (val == NULL) {
2321 			ERR("missing type\n");
2322 			return KNOT_EINVAL;
2323 		}
2324 
2325 		if (parse_type(val, query) != KNOT_EOK) {
2326 			ERR("bad type %s\n", val);
2327 			return KNOT_EINVAL;
2328 		}
2329 		*index += add;
2330 		break;
2331 	case 'V':
2332 		if (len > 1) {
2333 			ERR("invalid option -%s\n", opt);
2334 			return KNOT_ENOTSUP;
2335 		}
2336 
2337 		print_version(PROGRAM_NAME);
2338 		params->stop = true;
2339 		break;
2340 	case 'x':
2341 		if (val == NULL) {
2342 			ERR("missing address\n");
2343 			return KNOT_EINVAL;
2344 		}
2345 
2346 		if (parse_reverse(val, &params->queries, params->config)
2347 		    != KNOT_EOK) {
2348 			ERR("bad reverse name %s\n", val);
2349 			return KNOT_EINVAL;
2350 		}
2351 		*index += add;
2352 		break;
2353 	case 'y':
2354 		if (val == NULL) {
2355 			ERR("missing key\n");
2356 			return KNOT_EINVAL;
2357 		}
2358 
2359 		if (parse_tsig(val, query) != KNOT_EOK) {
2360 			ERR("bad key %s\n", value);
2361 			return KNOT_EINVAL;
2362 		}
2363 		*index += add;
2364 		break;
2365 	case 'E':
2366 #if USE_DNSTAP
2367 		if (val == NULL) {
2368 			ERR("missing filename\n");
2369 			return KNOT_EINVAL;
2370 		}
2371 
2372 		if (parse_dnstap_output(val, query) != KNOT_EOK) {
2373 			ERR("unable to open dnstap output file %s\n", val);
2374 			return KNOT_EINVAL;
2375 		}
2376 		*index += add;
2377 #else
2378 		ERR("no dnstap support but -E specified\n");
2379 		return KNOT_EINVAL;
2380 #endif // USE_DNSTAP
2381 		break;
2382 	case 'G':
2383 #if USE_DNSTAP
2384 		if (val == NULL) {
2385 			ERR("missing filename\n");
2386 			return KNOT_EINVAL;
2387 		}
2388 
2389 		query = query_create(NULL, params->config);
2390 		if (query == NULL) {
2391 			return KNOT_ENOMEM;
2392 		}
2393 
2394 		if (parse_dnstap_input(val, query) != KNOT_EOK) {
2395 			ERR("unable to open dnstap input file %s\n", val);
2396 			query_free(query);
2397 			return KNOT_EINVAL;
2398 		}
2399 
2400 		query->operation = OPERATION_LIST_DNSTAP;
2401 		add_tail(&params->queries, (node_t *)query);
2402 
2403 		*index += add;
2404 #else
2405 		ERR("no dnstap support but -G specified\n");
2406 		return KNOT_EINVAL;
2407 #endif // USE_DNSTAP
2408 		break;
2409 	case '-':
2410 		if (strcmp(opt, "-help") == 0) {
2411 			print_help();
2412 			params->stop = true;
2413 		} else if (strcmp(opt, "-version") == 0) {
2414 			print_version(PROGRAM_NAME);
2415 			params->stop = true;
2416 		} else {
2417 			ERR("invalid option: -%s\n", opt);
2418 			return KNOT_ENOTSUP;
2419 		}
2420 		break;
2421 	default:
2422 		ERR("invalid option: -%s\n", opt);
2423 		return KNOT_ENOTSUP;
2424 	}
2425 
2426 	return KNOT_EOK;
2427 }
2428 
parse_opt2(const char * value,kdig_params_t * params)2429 static int parse_opt2(const char *value, kdig_params_t *params)
2430 {
2431 	query_t *query;
2432 
2433 	// Set current query (last or config).
2434 	if (list_size(&params->queries) > 0) {
2435 		query = TAIL(params->queries);
2436 	} else {
2437 		query = params->config;
2438 	}
2439 
2440 	// Get option name.
2441 	const char *arg_sep = "=";
2442 	size_t opt_len = strcspn(value, arg_sep);
2443 	if (opt_len < 1) {
2444 		ERR("invalid option: +%s\n", value);
2445 		return KNOT_ENOTSUP;
2446 	}
2447 
2448 	// Get option argument if any.
2449 	const char *arg = NULL;
2450 	const char *rest = value + opt_len;
2451 	if (strlen(rest) > 0) {
2452 		arg = rest + strspn(rest, arg_sep);
2453 	}
2454 
2455 	// Check if the given option is supported.
2456 	bool unique;
2457 	int ret = best_param(value, opt_len, kdig_opts2, &unique);
2458 	if (ret < 0) {
2459 		ERR("invalid option: +%s\n", value);
2460 		return KNOT_ENOTSUP;
2461 	} else if (!unique) {
2462 		ERR("ambiguous option: +%s\n", value);
2463 		return KNOT_ENOTSUP;
2464 	}
2465 
2466 	// Check argument presence.
2467 	switch (kdig_opts2[ret].arg) {
2468 	case ARG_NONE:
2469 		if (arg != NULL && *arg != '\0') {
2470 			WARN("superfluous option argument: +%s\n", value);
2471 		}
2472 		break;
2473 	case ARG_REQUIRED:
2474 		if (arg == NULL) {
2475 			ERR("missing argument: +%s\n", value);
2476 			return KNOT_EFEWDATA;
2477 		}
2478 		// FALLTHROUGH
2479 	case ARG_OPTIONAL:
2480 		if (arg != NULL && *arg == '\0') {
2481 			ERR("empty argument: +%s\n", value);
2482 			return KNOT_EFEWDATA;
2483 		}
2484 		break;
2485 	}
2486 
2487 	// Call option handler.
2488 	return kdig_opts2[ret].handler(arg, query);
2489 }
2490 
parse_token(const char * value,kdig_params_t * params)2491 static int parse_token(const char *value, kdig_params_t *params)
2492 {
2493 	query_t *query;
2494 
2495 	// Set current query (last or config).
2496 	if (list_size(&params->queries) > 0) {
2497 		query = TAIL(params->queries);
2498 	} else {
2499 		query = params->config;
2500 	}
2501 
2502 	// Try to guess the meaning of the token.
2503 	if (strlen(value) == 0) {
2504 		ERR("invalid empty parameter\n");
2505 	} else if (parse_type(value, query) == KNOT_EOK) {
2506 		return KNOT_EOK;
2507 	} else if (parse_class(value, query) == KNOT_EOK) {
2508 		return KNOT_EOK;
2509 	} else if (parse_name(value, &params->queries, params->config) == KNOT_EOK) {
2510 		return KNOT_EOK;
2511 	} else {
2512 		ERR("invalid parameter: %s\n", value);
2513 	}
2514 
2515 	return KNOT_EINVAL;
2516 }
2517 
kdig_parse(kdig_params_t * params,int argc,char * argv[])2518 int kdig_parse(kdig_params_t *params, int argc, char *argv[])
2519 {
2520 	if (params == NULL || argv == NULL) {
2521 		DBG_NULL;
2522 		return KNOT_EINVAL;
2523 	}
2524 
2525 	// Initialize parameters.
2526 	if (kdig_init(params) != KNOT_EOK) {
2527 		return KNOT_ERROR;
2528 	}
2529 
2530 #ifdef LIBIDN
2531 	// Set up localization.
2532 	if (setlocale(LC_CTYPE, "") == NULL) {
2533 		WARN("can't setlocale, disabling IDN\n");
2534 		params->config->idn = false;
2535 		params->config->style.style.ascii_to_idn = NULL;
2536 	}
2537 #endif
2538 
2539 	// Command line parameters processing.
2540 	for (int i = 1; i < argc; i++) {
2541 		int ret = KNOT_ERROR;
2542 
2543 		// Process parameter.
2544 		switch (argv[i][0]) {
2545 		case '@':
2546 			ret = parse_server(argv[i] + 1, params);
2547 			break;
2548 		case '-':
2549 			ret = parse_opt1(argv[i] + 1, argv[i + 1], params, &i);
2550 			break;
2551 		case '+':
2552 			ret = parse_opt2(argv[i] + 1, params);
2553 			break;
2554 		default:
2555 			ret = parse_token(argv[i], params);
2556 			break;
2557 		}
2558 
2559 		// Check return.
2560 		switch (ret) {
2561 		case KNOT_EOK:
2562 			if (params->stop) {
2563 				return KNOT_EOK;
2564 			}
2565 			break;
2566 		case KNOT_ENOTSUP:
2567 			print_help();
2568 		default: // Fall through.
2569 			return ret;
2570 		}
2571 	}
2572 
2573 	// Complete missing data in queries based on defaults.
2574 	complete_queries(&params->queries, params->config);
2575 
2576 	return KNOT_EOK;
2577 }
2578