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(¶ms->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(¶ms->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, ¬ify) != 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(¶ms->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, ¶ms->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, ¶ms->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(¶ms->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(¶ms->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(¶ms->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, ¶ms->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(¶ms->queries, params->config);
2575
2576 return KNOT_EOK;
2577 }
2578