1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) The c-ares project and its contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27 #include "ares_setup.h"
28
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
31 #endif
32 #ifdef HAVE_ARPA_INET_H
33 # include <arpa/inet.h>
34 #endif
35 #ifdef HAVE_NETDB_H
36 # include <netdb.h>
37 #endif
38
39 #include "ares_nameser.h"
40
41 #ifdef HAVE_STRINGS_H
42 # include <strings.h>
43 #endif
44
45 #include "ares.h"
46 #include "ares_dns.h"
47
48 #ifndef HAVE_STRDUP
49 # include "ares_str.h"
50 # define strdup(ptr) ares_strdup(ptr)
51 #endif
52
53 #ifndef HAVE_STRCASECMP
54 # include "ares_strcasecmp.h"
55 # define strcasecmp(p1, p2) ares_strcasecmp(p1, p2)
56 #endif
57
58 #ifndef HAVE_STRNCASECMP
59 # include "ares_strcasecmp.h"
60 # define strncasecmp(p1, p2, n) ares_strncasecmp(p1, p2, n)
61 #endif
62
63 #include "ares_getopt.h"
64
65 #ifdef WATT32
66 # undef WIN32 /* Redefined in MingW headers */
67 #endif
68
69
70 typedef struct {
71 ares_bool_t is_help;
72 struct ares_options options;
73 int optmask;
74 ares_dns_class_t qclass;
75 ares_dns_rec_type_t qtype;
76 int args_processed;
77 char *servers;
78 char error[256];
79 } adig_config_t;
80
81 typedef struct {
82 const char *name;
83 int value;
84 } nv_t;
85
86 static const nv_t configflags[] = {
87 {"usevc", ARES_FLAG_USEVC },
88 { "primary", ARES_FLAG_PRIMARY },
89 { "igntc", ARES_FLAG_IGNTC },
90 { "norecurse", ARES_FLAG_NORECURSE},
91 { "stayopen", ARES_FLAG_STAYOPEN },
92 { "noaliases", ARES_FLAG_NOALIASES}
93 };
94 static const size_t nconfigflags = sizeof(configflags) / sizeof(*configflags);
95
lookup_flag(const nv_t * nv,size_t num_nv,const char * name)96 static int lookup_flag(const nv_t *nv, size_t num_nv, const char *name)
97 {
98 size_t i;
99
100 if (name == NULL) {
101 return 0;
102 }
103
104 for (i = 0; i < num_nv; i++) {
105 if (strcasecmp(nv[i].name, name) == 0) {
106 return nv[i].value;
107 }
108 }
109
110 return 0;
111 }
112
free_config(adig_config_t * config)113 static void free_config(adig_config_t *config)
114 {
115 free(config->servers);
116 memset(config, 0, sizeof(*config));
117 }
118
print_help(void)119 static void print_help(void)
120 {
121 printf("adig version %s\n\n", ares_version(NULL));
122 printf(
123 "usage: adig [-h] [-d] [-f flag] [[-s server] ...] [-T|U port] [-c class]\n"
124 " [-t type] name ...\n\n"
125 " -h : Display this help and exit.\n"
126 " -d : Print some extra debugging output.\n"
127 " -f flag : Add a behavior control flag. Possible values are\n"
128 " igntc - do not retry a truncated query as TCP, just\n"
129 " return the truncated answer\n"
130 " noaliases - don't honor the HOSTALIASES environment\n"
131 " variable\n"
132 " norecurse - don't query upstream servers recursively\n"
133 " primary - use the first server\n"
134 " stayopen - don't close the communication sockets\n"
135 " usevc - use TCP only\n"
136 " -s server : Connect to the specified DNS server, instead of the\n"
137 " system's default one(s). Servers are tried in round-robin,\n"
138 " if the previous one failed.\n"
139 " -T port : Connect to the specified TCP port of DNS server.\n"
140 " -U port : Connect to the specified UDP port of DNS server.\n"
141 " -c class : Set the query class. Possible values for class are:\n"
142 " ANY, CHAOS, HS and IN (default)\n"
143 " -t type : Query records of the specified type. Possible values for\n"
144 " type are:\n"
145 " A (default), AAAA, ANY, CNAME, HINFO, MX, NAPTR, NS, PTR,\n"
146 " SOA, SRV, TXT, TLSA, URI, CAA, SVCB, HTTPS\n\n");
147 }
148
read_cmdline(int argc,const char ** argv,adig_config_t * config)149 static ares_bool_t read_cmdline(int argc, const char **argv,
150 adig_config_t *config)
151 {
152 ares_getopt_state_t state;
153 int c;
154
155 ares_getopt_init(&state, argc, argv);
156 state.opterr = 0;
157
158 while ((c = ares_getopt(&state, "dh?f:s:c:t:T:U:")) != -1) {
159 int f;
160
161 switch (c) {
162 case 'd':
163 #ifdef WATT32
164 dbug_init();
165 #endif
166 break;
167
168 case 'h':
169 config->is_help = ARES_TRUE;
170 return ARES_TRUE;
171
172 case 'f':
173 f = lookup_flag(configflags, nconfigflags, state.optarg);
174 if (f == 0) {
175 snprintf(config->error, sizeof(config->error), "flag %s unknown",
176 state.optarg);
177 }
178
179 config->options.flags |= f;
180 config->optmask |= ARES_OPT_FLAGS;
181 break;
182
183 case 's':
184 if (state.optarg == NULL) {
185 snprintf(config->error, sizeof(config->error), "%s",
186 "missing servers");
187 return ARES_FALSE;
188 }
189 if (config->servers) {
190 free(config->servers);
191 }
192 config->servers = strdup(state.optarg);
193 break;
194
195 case 'c':
196 if (!ares_dns_class_fromstr(&config->qclass, state.optarg)) {
197 snprintf(config->error, sizeof(config->error),
198 "unrecognized class %s", state.optarg);
199 return ARES_FALSE;
200 }
201 break;
202
203 case 't':
204 if (!ares_dns_rec_type_fromstr(&config->qtype, state.optarg)) {
205 snprintf(config->error, sizeof(config->error), "unrecognized type %s",
206 state.optarg);
207 return ARES_FALSE;
208 }
209 break;
210
211 case 'T':
212 /* Set the TCP port number. */
213 if (!isdigit(*state.optarg)) {
214 snprintf(config->error, sizeof(config->error), "invalid port number");
215 return ARES_FALSE;
216 }
217 config->options.tcp_port =
218 (unsigned short)strtol(state.optarg, NULL, 0);
219 config->options.flags |= ARES_FLAG_USEVC;
220 config->optmask |= ARES_OPT_TCP_PORT;
221 break;
222
223 case 'U':
224 /* Set the UDP port number. */
225 if (!isdigit(*state.optarg)) {
226 snprintf(config->error, sizeof(config->error), "invalid port number");
227 return ARES_FALSE;
228 }
229 config->options.udp_port =
230 (unsigned short)strtol(state.optarg, NULL, 0);
231 config->optmask |= ARES_OPT_UDP_PORT;
232 break;
233
234 case ':':
235 snprintf(config->error, sizeof(config->error),
236 "%c requires an argument", state.optopt);
237 return ARES_FALSE;
238
239 default:
240 snprintf(config->error, sizeof(config->error),
241 "unrecognized option: %c", state.optopt);
242 return ARES_FALSE;
243 }
244 }
245
246 config->args_processed = state.optind;
247 if (config->args_processed >= argc) {
248 snprintf(config->error, sizeof(config->error), "missing query name");
249 return ARES_FALSE;
250 }
251 return ARES_TRUE;
252 }
253
print_flags(ares_dns_flags_t flags)254 static void print_flags(ares_dns_flags_t flags)
255 {
256 if (flags & ARES_FLAG_QR) {
257 printf(" qr");
258 }
259 if (flags & ARES_FLAG_AA) {
260 printf(" aa");
261 }
262 if (flags & ARES_FLAG_TC) {
263 printf(" tc");
264 }
265 if (flags & ARES_FLAG_RD) {
266 printf(" rd");
267 }
268 if (flags & ARES_FLAG_RA) {
269 printf(" ra");
270 }
271 if (flags & ARES_FLAG_AD) {
272 printf(" ad");
273 }
274 if (flags & ARES_FLAG_CD) {
275 printf(" cd");
276 }
277 }
278
print_header(const ares_dns_record_t * dnsrec)279 static void print_header(const ares_dns_record_t *dnsrec)
280 {
281 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
282 ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec)),
283 ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec)),
284 ares_dns_record_get_id(dnsrec));
285 printf(";; flags:");
286 print_flags(ares_dns_record_get_flags(dnsrec));
287 printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n\n",
288 (unsigned int)ares_dns_record_query_cnt(dnsrec),
289 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER),
290 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY),
291 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
292 }
293
print_question(const ares_dns_record_t * dnsrec)294 static void print_question(const ares_dns_record_t *dnsrec)
295 {
296 size_t i;
297 printf(";; QUESTION SECTION:\n");
298 for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) {
299 const char *name;
300 ares_dns_rec_type_t qtype;
301 ares_dns_class_t qclass;
302 size_t len;
303 if (ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass) !=
304 ARES_SUCCESS) {
305 return;
306 }
307 if (name == NULL) {
308 return;
309 }
310 len = strlen(name);
311 printf(";%s.\t", name);
312 if (len + 1 < 24) {
313 printf("\t");
314 }
315 if (len + 1 < 16) {
316 printf("\t");
317 }
318 printf("%s\t%s\n", ares_dns_class_tostr(qclass),
319 ares_dns_rec_type_tostr(qtype));
320 }
321 printf("\n");
322 }
323
print_opt_none(const unsigned char * val,size_t val_len)324 static void print_opt_none(const unsigned char *val, size_t val_len)
325 {
326 (void)val;
327 if (val_len != 0) {
328 printf("INVALID!");
329 }
330 }
331
print_opt_addr_list(const unsigned char * val,size_t val_len)332 static void print_opt_addr_list(const unsigned char *val, size_t val_len)
333 {
334 size_t i;
335 if (val_len % 4 != 0) {
336 printf("INVALID!");
337 return;
338 }
339 for (i = 0; i < val_len; i += 4) {
340 char buf[256] = "";
341 ares_inet_ntop(AF_INET, val + i, buf, sizeof(buf));
342 if (i != 0) {
343 printf(",");
344 }
345 printf("%s", buf);
346 }
347 }
348
print_opt_addr6_list(const unsigned char * val,size_t val_len)349 static void print_opt_addr6_list(const unsigned char *val, size_t val_len)
350 {
351 size_t i;
352 if (val_len % 16 != 0) {
353 printf("INVALID!");
354 return;
355 }
356 for (i = 0; i < val_len; i += 16) {
357 char buf[256] = "";
358
359 ares_inet_ntop(AF_INET6, val + i, buf, sizeof(buf));
360 if (i != 0) {
361 printf(",");
362 }
363 printf("%s", buf);
364 }
365 }
366
print_opt_u8_list(const unsigned char * val,size_t val_len)367 static void print_opt_u8_list(const unsigned char *val, size_t val_len)
368 {
369 size_t i;
370
371 for (i = 0; i < val_len; i++) {
372 if (i != 0) {
373 printf(",");
374 }
375 printf("%u", (unsigned int)val[i]);
376 }
377 }
378
print_opt_u16_list(const unsigned char * val,size_t val_len)379 static void print_opt_u16_list(const unsigned char *val, size_t val_len)
380 {
381 size_t i;
382 if (val_len < 2 || val_len % 2 != 0) {
383 printf("INVALID!");
384 return;
385 }
386 for (i = 0; i < val_len; i += 2) {
387 unsigned short u16 = 0;
388 unsigned short c;
389 /* Jumping over backwards to try to avoid odd compiler warnings */
390 c = (unsigned short)val[i];
391 u16 |= (unsigned short)((c << 8) & 0xFFFF);
392 c = (unsigned short)val[i + 1];
393 u16 |= c;
394 if (i != 0) {
395 printf(",");
396 }
397 printf("%u", (unsigned int)u16);
398 }
399 }
400
print_opt_u32_list(const unsigned char * val,size_t val_len)401 static void print_opt_u32_list(const unsigned char *val, size_t val_len)
402 {
403 size_t i;
404 if (val_len < 4 || val_len % 4 != 0) {
405 printf("INVALID!");
406 return;
407 }
408 for (i = 0; i < val_len; i += 4) {
409 unsigned int u32 = 0;
410
411 u32 |= (unsigned int)(val[i] << 24);
412 u32 |= (unsigned int)(val[i + 1] << 16);
413 u32 |= (unsigned int)(val[i + 2] << 8);
414 u32 |= (unsigned int)(val[i + 3]);
415 if (i != 0) {
416 printf(",");
417 }
418 printf("%u", u32);
419 }
420 }
421
print_opt_str_list(const unsigned char * val,size_t val_len)422 static void print_opt_str_list(const unsigned char *val, size_t val_len)
423 {
424 size_t cnt = 0;
425
426 printf("\"");
427 while (val_len) {
428 long read_len = 0;
429 unsigned char *str = NULL;
430 ares_status_t status;
431
432 if (cnt) {
433 printf(",");
434 }
435
436 status = (ares_status_t)ares_expand_string(val, val, (int)val_len, &str,
437 &read_len);
438 if (status != ARES_SUCCESS) {
439 printf("INVALID");
440 break;
441 }
442 printf("%s", str);
443 ares_free_string(str);
444 val_len -= (size_t)read_len;
445 val += read_len;
446 cnt++;
447 }
448 printf("\"");
449 }
450
print_opt_name(const unsigned char * val,size_t val_len)451 static void print_opt_name(const unsigned char *val, size_t val_len)
452 {
453 char *str = NULL;
454 long read_len = 0;
455
456 if (ares_expand_name(val, val, (int)val_len, &str, &read_len) !=
457 ARES_SUCCESS) {
458 printf("INVALID!");
459 return;
460 }
461
462 printf("%s.", str);
463 ares_free_string(str);
464 }
465
print_opt_bin(const unsigned char * val,size_t val_len)466 static void print_opt_bin(const unsigned char *val, size_t val_len)
467 {
468 size_t i;
469
470 for (i = 0; i < val_len; i++) {
471 printf("%02x", (unsigned int)val[i]);
472 }
473 }
474
adig_isprint(int ch)475 static ares_bool_t adig_isprint(int ch)
476 {
477 if (ch >= 0x20 && ch <= 0x7E) {
478 return ARES_TRUE;
479 }
480 return ARES_FALSE;
481 }
482
print_opt_binp(const unsigned char * val,size_t val_len)483 static void print_opt_binp(const unsigned char *val, size_t val_len)
484 {
485 size_t i;
486 printf("\"");
487 for (i = 0; i < val_len; i++) {
488 if (adig_isprint(val[i])) {
489 printf("%c", val[i]);
490 } else {
491 printf("\\%03d", val[i]);
492 }
493 }
494 printf("\"");
495 }
496
print_opts(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)497 static void print_opts(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
498 {
499 size_t i;
500
501 for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, key); i++) {
502 size_t val_len = 0;
503 const unsigned char *val = NULL;
504 unsigned short opt;
505 const char *name;
506
507 if (i != 0) {
508 printf(" ");
509 }
510
511 opt = ares_dns_rr_get_opt(rr, key, i, &val, &val_len);
512 name = ares_dns_opt_get_name(key, opt);
513 if (name == NULL) {
514 printf("key%u", (unsigned int)opt);
515 } else {
516 printf("%s", name);
517 }
518 if (val_len == 0) {
519 return;
520 }
521
522 printf("=");
523
524 switch (ares_dns_opt_get_datatype(key, opt)) {
525 case ARES_OPT_DATATYPE_NONE:
526 print_opt_none(val, val_len);
527 break;
528 case ARES_OPT_DATATYPE_U8_LIST:
529 print_opt_u8_list(val, val_len);
530 break;
531 case ARES_OPT_DATATYPE_INADDR4_LIST:
532 print_opt_addr_list(val, val_len);
533 break;
534 case ARES_OPT_DATATYPE_INADDR6_LIST:
535 print_opt_addr6_list(val, val_len);
536 break;
537 case ARES_OPT_DATATYPE_U16:
538 case ARES_OPT_DATATYPE_U16_LIST:
539 print_opt_u16_list(val, val_len);
540 break;
541 case ARES_OPT_DATATYPE_U32:
542 case ARES_OPT_DATATYPE_U32_LIST:
543 print_opt_u32_list(val, val_len);
544 break;
545 case ARES_OPT_DATATYPE_STR_LIST:
546 print_opt_str_list(val, val_len);
547 break;
548 case ARES_OPT_DATATYPE_BIN:
549 print_opt_bin(val, val_len);
550 break;
551 case ARES_OPT_DATATYPE_NAME:
552 print_opt_name(val, val_len);
553 break;
554 }
555 }
556 }
557
print_addr(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)558 static void print_addr(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
559 {
560 const struct in_addr *addr = ares_dns_rr_get_addr(rr, key);
561 char buf[256] = "";
562
563 ares_inet_ntop(AF_INET, addr, buf, sizeof(buf));
564 printf("%s", buf);
565 }
566
print_addr6(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)567 static void print_addr6(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
568 {
569 const struct ares_in6_addr *addr = ares_dns_rr_get_addr6(rr, key);
570 char buf[256] = "";
571
572 ares_inet_ntop(AF_INET6, addr, buf, sizeof(buf));
573 printf("%s", buf);
574 }
575
print_u8(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)576 static void print_u8(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
577 {
578 unsigned char u8 = ares_dns_rr_get_u8(rr, key);
579 printf("%u", (unsigned int)u8);
580 }
581
print_u16(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)582 static void print_u16(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
583 {
584 unsigned short u16 = ares_dns_rr_get_u16(rr, key);
585 printf("%u", (unsigned int)u16);
586 }
587
print_u32(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)588 static void print_u32(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
589 {
590 unsigned int u32 = ares_dns_rr_get_u32(rr, key);
591 printf("%u", u32);
592 }
593
print_name(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)594 static void print_name(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
595 {
596 const char *str = ares_dns_rr_get_str(rr, key);
597 printf("%s.", str);
598 }
599
print_str(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)600 static void print_str(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
601 {
602 const char *str = ares_dns_rr_get_str(rr, key);
603 printf("\"%s\"", str);
604 }
605
print_bin(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)606 static void print_bin(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
607 {
608 size_t len = 0;
609 const unsigned char *binp = ares_dns_rr_get_bin(rr, key, &len);
610 print_opt_bin(binp, len);
611 }
612
print_binp(const ares_dns_rr_t * rr,ares_dns_rr_key_t key)613 static void print_binp(const ares_dns_rr_t *rr, ares_dns_rr_key_t key)
614 {
615 size_t len;
616 const unsigned char *binp = ares_dns_rr_get_bin(rr, key, &len);
617
618 print_opt_binp(binp, len);
619 }
620
print_rr(const ares_dns_rr_t * rr)621 static void print_rr(const ares_dns_rr_t *rr)
622 {
623 const char *name = ares_dns_rr_get_name(rr);
624 size_t len = 0;
625 size_t keys_cnt = 0;
626 ares_dns_rec_type_t rtype = ares_dns_rr_get_type(rr);
627 const ares_dns_rr_key_t *keys = ares_dns_rr_get_keys(rtype, &keys_cnt);
628 size_t i;
629
630 if (name == NULL) {
631 return;
632 }
633
634 len = strlen(name);
635
636 printf("%s.\t", name);
637 if (len < 24) {
638 printf("\t");
639 }
640
641 printf("%u\t%s\t%s\t", ares_dns_rr_get_ttl(rr),
642 ares_dns_class_tostr(ares_dns_rr_get_class(rr)),
643 ares_dns_rec_type_tostr(rtype));
644
645 /* Output params here */
646 for (i = 0; i < keys_cnt; i++) {
647 ares_dns_datatype_t datatype = ares_dns_rr_key_datatype(keys[i]);
648 if (i != 0) {
649 printf(" ");
650 }
651
652 switch (datatype) {
653 case ARES_DATATYPE_INADDR:
654 print_addr(rr, keys[i]);
655 break;
656 case ARES_DATATYPE_INADDR6:
657 print_addr6(rr, keys[i]);
658 break;
659 case ARES_DATATYPE_U8:
660 print_u8(rr, keys[i]);
661 break;
662 case ARES_DATATYPE_U16:
663 print_u16(rr, keys[i]);
664 break;
665 case ARES_DATATYPE_U32:
666 print_u32(rr, keys[i]);
667 break;
668 case ARES_DATATYPE_NAME:
669 print_name(rr, keys[i]);
670 break;
671 case ARES_DATATYPE_STR:
672 print_str(rr, keys[i]);
673 break;
674 case ARES_DATATYPE_BIN:
675 print_bin(rr, keys[i]);
676 break;
677 case ARES_DATATYPE_BINP:
678 print_binp(rr, keys[i]);
679 break;
680 case ARES_DATATYPE_OPT:
681 print_opts(rr, keys[i]);
682 break;
683 }
684 }
685
686 printf("\n");
687 }
688
has_opt(ares_dns_record_t * dnsrec,ares_dns_section_t section)689 static const ares_dns_rr_t *has_opt(ares_dns_record_t *dnsrec,
690 ares_dns_section_t section)
691 {
692 size_t i;
693 for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) {
694 const ares_dns_rr_t *rr = ares_dns_record_rr_get(dnsrec, section, i);
695 if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) {
696 return rr;
697 }
698 }
699 return NULL;
700 }
701
print_section(ares_dns_record_t * dnsrec,ares_dns_section_t section)702 static void print_section(ares_dns_record_t *dnsrec, ares_dns_section_t section)
703 {
704 size_t i;
705
706 if (ares_dns_record_rr_cnt(dnsrec, section) == 0 ||
707 (ares_dns_record_rr_cnt(dnsrec, section) == 1 &&
708 has_opt(dnsrec, section) != NULL)) {
709 return;
710 }
711
712 printf(";; %s SECTION:\n", ares_dns_section_tostr(section));
713 for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) {
714 const ares_dns_rr_t *rr = ares_dns_record_rr_get(dnsrec, section, i);
715 if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) {
716 continue;
717 }
718 print_rr(rr);
719 }
720 printf("\n");
721 }
722
print_opt_psuedosection(ares_dns_record_t * dnsrec)723 static void print_opt_psuedosection(ares_dns_record_t *dnsrec)
724 {
725 const ares_dns_rr_t *rr = has_opt(dnsrec, ARES_SECTION_ADDITIONAL);
726 if (rr == NULL) {
727 return;
728 }
729
730 printf(";; OPT PSEUDOSECTION:\n");
731 printf("; EDNS: version: %u, flags: %u; udp: %u\t",
732 (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_VERSION),
733 (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_FLAGS),
734 (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_UDP_SIZE));
735
736 printf("\n");
737 }
738
callback(void * arg,int status,int timeouts,unsigned char * abuf,int alen)739 static void callback(void *arg, int status, int timeouts, unsigned char *abuf,
740 int alen)
741 {
742 ares_dns_record_t *dnsrec = NULL;
743 (void)arg;
744 (void)timeouts;
745
746 /* We got a "Server status" */
747 if (status >= ARES_SUCCESS && status <= ARES_EREFUSED) {
748 printf(";; Got answer:");
749 } else {
750 printf(";;");
751 }
752
753 if (status != ARES_SUCCESS) {
754 printf(" %s", ares_strerror(status));
755 }
756 printf("\n");
757
758 if (abuf == NULL || alen == 0) {
759 return;
760 }
761
762 status = (int)ares_dns_parse(abuf, (size_t)alen, 0, &dnsrec);
763 if (status != ARES_SUCCESS) {
764 fprintf(stderr, ";; FAILED TO PARSE DNS PACKET: %s\n",
765 ares_strerror(status));
766 return;
767 }
768
769 print_header(dnsrec);
770 print_opt_psuedosection(dnsrec);
771 print_question(dnsrec);
772 print_section(dnsrec, ARES_SECTION_ANSWER);
773 print_section(dnsrec, ARES_SECTION_ADDITIONAL);
774 print_section(dnsrec, ARES_SECTION_AUTHORITY);
775
776 printf(";; MSG SIZE rcvd: %d\n\n", alen);
777 ares_dns_record_destroy(dnsrec);
778 }
779
enqueue_query(ares_channel_t * channel,const adig_config_t * config,const char * name)780 static ares_status_t enqueue_query(ares_channel_t *channel,
781 const adig_config_t *config,
782 const char *name)
783 {
784 ares_dns_record_t *dnsrec = NULL;
785 ares_dns_rr_t *rr = NULL;
786 ares_status_t status;
787 unsigned char *buf = NULL;
788 size_t buf_len = 0;
789 unsigned short flags = 0;
790 char *nametemp = NULL;
791
792 if (!(config->options.flags & ARES_FLAG_NORECURSE)) {
793 flags |= ARES_FLAG_RD;
794 }
795
796 status = ares_dns_record_create(&dnsrec, 0, flags, ARES_OPCODE_QUERY,
797 ARES_RCODE_NOERROR);
798 if (status != ARES_SUCCESS) {
799 goto done;
800 }
801
802 /* If it is a PTR record, convert from ip address into in-arpa form
803 * automatically */
804 if (config->qtype == ARES_REC_TYPE_PTR) {
805 struct ares_addr addr;
806 size_t len;
807 addr.family = AF_UNSPEC;
808
809 if (ares_dns_pton(name, &addr, &len) != NULL) {
810 nametemp = ares_dns_addr_to_ptr(&addr);
811 name = nametemp;
812 }
813 }
814
815 status =
816 ares_dns_record_query_add(dnsrec, name, config->qtype, config->qclass);
817 if (status != ARES_SUCCESS) {
818 goto done;
819 }
820
821 status = ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "",
822 ARES_REC_TYPE_OPT, ARES_CLASS_IN, 0);
823 if (status != ARES_SUCCESS) {
824 goto done;
825 }
826 ares_dns_rr_set_u16(rr, ARES_RR_OPT_UDP_SIZE, 1280);
827 ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0);
828
829 status = ares_dns_write(dnsrec, &buf, &buf_len);
830 if (status != ARES_SUCCESS) {
831 goto done;
832 }
833
834 ares_send(channel, buf, (int)buf_len, callback, NULL);
835 ares_free_string(buf);
836
837 done:
838 ares_free_string(nametemp);
839 ares_dns_record_destroy(dnsrec);
840 return status;
841 }
842
event_loop(ares_channel_t * channel)843 static int event_loop(ares_channel_t *channel)
844 {
845 while (1) {
846 fd_set read_fds;
847 fd_set write_fds;
848 int nfds;
849 struct timeval tv;
850 struct timeval *tvp;
851 int count;
852
853 FD_ZERO(&read_fds);
854 FD_ZERO(&write_fds);
855 memset(&tv, 0, sizeof(tv));
856
857 nfds = ares_fds(channel, &read_fds, &write_fds);
858 if (nfds == 0) {
859 break;
860 }
861 tvp = ares_timeout(channel, NULL, &tv);
862 if (tvp == NULL) {
863 break;
864 }
865 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
866 if (count < 0) {
867 #ifdef USE_WINSOCK
868 int err = WSAGetLastError();
869 #else
870 int err = errno;
871 #endif
872 if (err != EAGAIN && err != EINTR) {
873 fprintf(stderr, "select fail: %d", err);
874 return 1;
875 }
876 }
877 ares_process(channel, &read_fds, &write_fds);
878 }
879 return 0;
880 }
881
main(int argc,char ** argv)882 int main(int argc, char **argv)
883 {
884 ares_channel_t *channel = NULL;
885 ares_status_t status;
886 adig_config_t config;
887 int i;
888 int rv = 0;
889
890 #ifdef USE_WINSOCK
891 WORD wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
892 WSADATA wsaData;
893 WSAStartup(wVersionRequested, &wsaData);
894 #endif
895
896 status = (ares_status_t)ares_library_init(ARES_LIB_INIT_ALL);
897 if (status != ARES_SUCCESS) {
898 fprintf(stderr, "ares_library_init: %s\n", ares_strerror((int)status));
899 return 1;
900 }
901
902 memset(&config, 0, sizeof(config));
903 config.qclass = ARES_CLASS_IN;
904 config.qtype = ARES_REC_TYPE_A;
905 if (!read_cmdline(argc, (const char **)argv, &config)) {
906 printf("\n** ERROR: %s\n\n", config.error);
907 print_help();
908 rv = 1;
909 goto done;
910 }
911
912 if (config.is_help) {
913 print_help();
914 goto done;
915 }
916
917 status =
918 (ares_status_t)ares_init_options(&channel, &config.options, config.optmask);
919 if (status != ARES_SUCCESS) {
920 fprintf(stderr, "ares_init_options: %s\n", ares_strerror((int)status));
921 rv = 1;
922 goto done;
923 }
924
925 if (config.servers) {
926 status = (ares_status_t)ares_set_servers_ports_csv(channel, config.servers);
927 if (status != ARES_SUCCESS) {
928 fprintf(stderr, "ares_set_servers_ports_csv: %s\n",
929 ares_strerror((int)status));
930 rv = 1;
931 goto done;
932 }
933 }
934
935 /* Enqueue a query for each separate name */
936 for (i = config.args_processed; i < argc; i++) {
937 status = enqueue_query(channel, &config, argv[i]);
938 if (status != ARES_SUCCESS) {
939 fprintf(stderr, "Failed to create query for %s: %s\n", argv[i],
940 ares_strerror((int)status));
941 rv = 1;
942 goto done;
943 }
944 }
945
946 /* Debug */
947 printf("\n; <<>> c-ares DiG %s <<>>", ares_version(NULL));
948 for (i = config.args_processed; i < argc; i++) {
949 printf(" %s", argv[i]);
950 }
951 printf("\n");
952
953 /* Process events */
954 rv = event_loop(channel);
955
956 done:
957 free_config(&config);
958 ares_destroy(channel);
959 ares_library_cleanup();
960
961 #ifdef USE_WINSOCK
962 WSACleanup();
963 #endif
964 return rv;
965 }
966