• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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