Make the query callbacks return the number of timeouts that happened during the execu...
[platform/upstream/c-ares.git] / adig.c
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2  *
3  * $Id$
4  *
5  * Permission to use, copy, modify, and distribute this
6  * software and its documentation for any purpose and without
7  * fee is hereby granted, provided that the above copyright
8  * notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting
10  * documentation, and that the name of M.I.T. not be used in
11  * advertising or publicity pertaining to distribution of the
12  * software without specific, written prior permission.
13  * M.I.T. makes no representations about the suitability of
14  * this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  */
17
18 #include "setup.h"
19
20 #if defined(WIN32) && !defined(WATT32)
21 #include "nameser.h"
22 #else
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <arpa/nameser.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <netdb.h>
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41
42 #include "ares.h"
43 #include "ares_dns.h"
44 #include "inet_ntop.h"
45 #include "ares_getopt.h"
46
47 #ifdef WATT32
48 #undef WIN32  /* Redefined in MingW headers */
49 #endif
50
51 /* Mac OS X portability check */
52 #ifndef T_SRV
53 #define T_SRV 33 /* server selection */
54 #endif
55
56 struct nv {
57   const char *name;
58   int value;
59 };
60
61 static const struct nv flags[] = {
62   { "usevc",            ARES_FLAG_USEVC },
63   { "primary",          ARES_FLAG_PRIMARY },
64   { "igntc",            ARES_FLAG_IGNTC },
65   { "norecurse",        ARES_FLAG_NORECURSE },
66   { "stayopen",         ARES_FLAG_STAYOPEN },
67   { "noaliases",        ARES_FLAG_NOALIASES }
68 };
69 static const int nflags = sizeof(flags) / sizeof(flags[0]);
70
71 static const struct nv classes[] = {
72   { "IN",       C_IN },
73   { "CHAOS",    C_CHAOS },
74   { "HS",       C_HS },
75   { "ANY",      C_ANY }
76 };
77 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
78
79 static const struct nv types[] = {
80   { "A",        T_A },
81   { "NS",       T_NS },
82   { "MD",       T_MD },
83   { "MF",       T_MF },
84   { "CNAME",    T_CNAME },
85   { "SOA",      T_SOA },
86   { "MB",       T_MB },
87   { "MG",       T_MG },
88   { "MR",       T_MR },
89   { "NULL",     T_NULL },
90   { "WKS",      T_WKS },
91   { "PTR",      T_PTR },
92   { "HINFO",    T_HINFO },
93   { "MINFO",    T_MINFO },
94   { "MX",       T_MX },
95   { "TXT",      T_TXT },
96   { "RP",       T_RP },
97   { "AFSDB",    T_AFSDB },
98   { "X25",      T_X25 },
99   { "ISDN",     T_ISDN },
100   { "RT",       T_RT },
101   { "NSAP",     T_NSAP },
102   { "NSAP_PTR", T_NSAP_PTR },
103   { "SIG",      T_SIG },
104   { "KEY",      T_KEY },
105   { "PX",       T_PX },
106   { "GPOS",     T_GPOS },
107   { "AAAA",     T_AAAA },
108   { "LOC",      T_LOC },
109   { "SRV",      T_SRV },
110   { "AXFR",     T_AXFR },
111   { "MAILB",    T_MAILB },
112   { "MAILA",    T_MAILA },
113   { "ANY",      T_ANY }
114 };
115 static const int ntypes = sizeof(types) / sizeof(types[0]);
116
117 static const char *opcodes[] = {
118   "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
119   "(unknown)", "(unknown)", "(unknown)", "(unknown)",
120   "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
121   "ZONEINIT", "ZONEREF"
122 };
123
124 static const char *rcodes[] = {
125   "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
126   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
127   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
128 };
129
130 static void callback(void *arg, int status, int timeouts,
131                      unsigned char *abuf, int alen);
132 static const unsigned char *display_question(const unsigned char *aptr,
133                                              const unsigned char *abuf,
134                                              int alen);
135 static const unsigned char *display_rr(const unsigned char *aptr,
136                                        const unsigned char *abuf, int alen);
137 static const char *type_name(int type);
138 static const char *class_name(int dnsclass);
139 static void usage(void);
140
141 int main(int argc, char **argv)
142 {
143   ares_channel channel;
144   int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
145   int status, nfds, count;
146   struct ares_options options;
147   struct hostent *hostent;
148   fd_set read_fds, write_fds;
149   struct timeval *tvp, tv;
150
151 #ifdef USE_WINSOCK
152   WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
153   WSADATA wsaData;
154   WSAStartup(wVersionRequested, &wsaData);
155 #endif
156
157   options.flags = ARES_FLAG_NOCHECKRESP;
158   options.servers = NULL;
159   options.nservers = 0;
160   while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1)
161     {
162       switch (c)
163         {
164         case 'd':
165 #ifdef WATT32
166           dbug_init();
167 #endif
168           break;
169
170         case 'f':
171           /* Add a flag. */
172           for (i = 0; i < nflags; i++)
173             {
174               if (strcmp(flags[i].name, optarg) == 0)
175                 break;
176             }
177           if (i == nflags)
178             usage();
179           options.flags |= flags[i].value;
180           break;
181
182         case 's':
183           /* Add a server, and specify servers in the option mask. */
184           hostent = gethostbyname(optarg);
185           if (!hostent || hostent->h_addrtype != AF_INET)
186             {
187               fprintf(stderr, "adig: server %s not found.\n", optarg);
188               return 1;
189             }
190           options.servers = realloc(options.servers, (options.nservers + 1)
191                                     * sizeof(struct in_addr));
192           if (!options.servers)
193             {
194               fprintf(stderr, "Out of memory!\n");
195               return 1;
196             }
197           memcpy(&options.servers[options.nservers], hostent->h_addr,
198                  sizeof(struct in_addr));
199           options.nservers++;
200           optmask |= ARES_OPT_SERVERS;
201           break;
202
203         case 'c':
204           /* Set the query class. */
205           for (i = 0; i < nclasses; i++)
206             {
207               if (strcasecmp(classes[i].name, optarg) == 0)
208                 break;
209             }
210           if (i == nclasses)
211             usage();
212           dnsclass = classes[i].value;
213           break;
214
215         case 't':
216           /* Set the query type. */
217           for (i = 0; i < ntypes; i++)
218             {
219               if (strcasecmp(types[i].name, optarg) == 0)
220                 break;
221             }
222           if (i == ntypes)
223             usage();
224           type = types[i].value;
225           break;
226
227         case 'T':
228           /* Set the TCP port number. */
229           if (!ISDIGIT(*optarg))
230             usage();
231           options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
232           optmask |= ARES_OPT_TCP_PORT;
233           break;
234
235         case 'U':
236           /* Set the UDP port number. */
237           if (!ISDIGIT(*optarg))
238             usage();
239           options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
240           optmask |= ARES_OPT_UDP_PORT;
241           break;
242         }
243     }
244   argc -= optind;
245   argv += optind;
246   if (argc == 0)
247     usage();
248
249   status = ares_init_options(&channel, &options, optmask);
250
251   if (status != ARES_SUCCESS)
252     {
253       fprintf(stderr, "ares_init_options: %s\n",
254               ares_strerror(status));
255       return 1;
256     }
257
258   /* Initiate the queries, one per command-line argument.  If there is
259    * only one query to do, supply NULL as the callback argument;
260    * otherwise, supply the query name as an argument so we can
261    * distinguish responses for the user when printing them out.
262    */
263   if (argc == 1)
264     ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
265   else
266     {
267       for (; *argv; argv++)
268         ares_query(channel, *argv, dnsclass, type, callback, *argv);
269     }
270
271   /* Wait for all queries to complete. */
272   while (1)
273     {
274       FD_ZERO(&read_fds);
275       FD_ZERO(&write_fds);
276       nfds = ares_fds(channel, &read_fds, &write_fds);
277       if (nfds == 0)
278         break;
279       tvp = ares_timeout(channel, NULL, &tv);
280       count = select(nfds, &read_fds, &write_fds, NULL, tvp);
281       if (count < 0 && SOCKERRNO != EINVAL)
282         {
283           perror("select");
284           return 1;
285         }
286       ares_process(channel, &read_fds, &write_fds);
287     }
288
289   ares_destroy(channel);
290
291 #ifdef USE_WINSOCK
292   WSACleanup();
293 #endif
294
295   return 0;
296 }
297
298 static void callback(void *arg, int status, int timeouts,
299                      unsigned char *abuf, int alen)
300 {
301   char *name = (char *) arg;
302   int id, qr, opcode, aa, tc, rd, ra, rcode;
303   unsigned int qdcount, ancount, nscount, arcount, i;
304   const unsigned char *aptr;
305
306   /* Display the query name if given. */
307   if (name)
308     printf("Answer for query %s:\n", name);
309
310   /* Display an error message if there was an error, but only stop if
311    * we actually didn't get an answer buffer.
312    */
313   if (status != ARES_SUCCESS)
314     {
315       printf("%s\n", ares_strerror(status));
316       if (!abuf)
317         return;
318     }
319
320   /* Won't happen, but check anyway, for safety. */
321   if (alen < HFIXEDSZ)
322     return;
323
324   /* Parse the answer header. */
325   id = DNS_HEADER_QID(abuf);
326   qr = DNS_HEADER_QR(abuf);
327   opcode = DNS_HEADER_OPCODE(abuf);
328   aa = DNS_HEADER_AA(abuf);
329   tc = DNS_HEADER_TC(abuf);
330   rd = DNS_HEADER_RD(abuf);
331   ra = DNS_HEADER_RA(abuf);
332   rcode = DNS_HEADER_RCODE(abuf);
333   qdcount = DNS_HEADER_QDCOUNT(abuf);
334   ancount = DNS_HEADER_ANCOUNT(abuf);
335   nscount = DNS_HEADER_NSCOUNT(abuf);
336   arcount = DNS_HEADER_ARCOUNT(abuf);
337
338   /* Display the answer header. */
339   printf("id: %d\n", id);
340   printf("flags: %s%s%s%s%s\n",
341          qr ? "qr " : "",
342          aa ? "aa " : "",
343          tc ? "tc " : "",
344          rd ? "rd " : "",
345          ra ? "ra " : "");
346   printf("opcode: %s\n", opcodes[opcode]);
347   printf("rcode: %s\n", rcodes[rcode]);
348
349   /* Display the questions. */
350   printf("Questions:\n");
351   aptr = abuf + HFIXEDSZ;
352   for (i = 0; i < qdcount; i++)
353     {
354       aptr = display_question(aptr, abuf, alen);
355       if (aptr == NULL)
356         return;
357     }
358
359   /* Display the answers. */
360   printf("Answers:\n");
361   for (i = 0; i < ancount; i++)
362     {
363       aptr = display_rr(aptr, abuf, alen);
364       if (aptr == NULL)
365         return;
366     }
367
368   /* Display the NS records. */
369   printf("NS records:\n");
370   for (i = 0; i < nscount; i++)
371     {
372       aptr = display_rr(aptr, abuf, alen);
373       if (aptr == NULL)
374         return;
375     }
376
377   /* Display the additional records. */
378   printf("Additional records:\n");
379   for (i = 0; i < arcount; i++)
380     {
381       aptr = display_rr(aptr, abuf, alen);
382       if (aptr == NULL)
383         return;
384     }
385 }
386
387 static const unsigned char *display_question(const unsigned char *aptr,
388                                              const unsigned char *abuf,
389                                              int alen)
390 {
391   char *name;
392   int type, dnsclass, status;
393   long len;
394
395   /* Parse the question name. */
396   status = ares_expand_name(aptr, abuf, alen, &name, &len);
397   if (status != ARES_SUCCESS)
398     return NULL;
399   aptr += len;
400
401   /* Make sure there's enough data after the name for the fixed part
402    * of the question.
403    */
404   if (aptr + QFIXEDSZ > abuf + alen)
405     {
406       ares_free_string(name);
407       return NULL;
408     }
409
410   /* Parse the question type and class. */
411   type = DNS_QUESTION_TYPE(aptr);
412   dnsclass = DNS_QUESTION_CLASS(aptr);
413   aptr += QFIXEDSZ;
414
415   /* Display the question, in a format sort of similar to how we will
416    * display RRs.
417    */
418   printf("\t%-15s.\t", name);
419   if (dnsclass != C_IN)
420     printf("\t%s", class_name(dnsclass));
421   printf("\t%s\n", type_name(type));
422   ares_free_string(name);
423   return aptr;
424 }
425
426 static const unsigned char *display_rr(const unsigned char *aptr,
427                                        const unsigned char *abuf, int alen)
428 {
429   const unsigned char *p;
430   char *name;
431   int type, dnsclass, ttl, dlen, status;
432   long len;
433   char addr[46];
434
435   /* Parse the RR name. */
436   status = ares_expand_name(aptr, abuf, alen, &name, &len);
437   if (status != ARES_SUCCESS)
438     return NULL;
439   aptr += len;
440
441   /* Make sure there is enough data after the RR name for the fixed
442    * part of the RR.
443    */
444   if (aptr + RRFIXEDSZ > abuf + alen)
445     {
446       ares_free_string(name);
447       return NULL;
448     }
449
450   /* Parse the fixed part of the RR, and advance to the RR data
451    * field. */
452   type = DNS_RR_TYPE(aptr);
453   dnsclass = DNS_RR_CLASS(aptr);
454   ttl = DNS_RR_TTL(aptr);
455   dlen = DNS_RR_LEN(aptr);
456   aptr += RRFIXEDSZ;
457   if (aptr + dlen > abuf + alen)
458     {
459       ares_free_string(name);
460       return NULL;
461     }
462
463   /* Display the RR name, class, and type. */
464   printf("\t%-15s.\t%d", name, ttl);
465   if (dnsclass != C_IN)
466     printf("\t%s", class_name(dnsclass));
467   printf("\t%s", type_name(type));
468   ares_free_string(name);
469
470   /* Display the RR data.  Don't touch aptr. */
471   switch (type)
472     {
473     case T_CNAME:
474     case T_MB:
475     case T_MD:
476     case T_MF:
477     case T_MG:
478     case T_MR:
479     case T_NS:
480     case T_PTR:
481       /* For these types, the RR data is just a domain name. */
482       status = ares_expand_name(aptr, abuf, alen, &name, &len);
483       if (status != ARES_SUCCESS)
484         return NULL;
485       printf("\t%s.", name);
486       ares_free_string(name);
487       break;
488
489     case T_HINFO:
490       /* The RR data is two length-counted character strings. */
491       p = aptr;
492       len = *p;
493       if (p + len + 1 > aptr + dlen)
494         return NULL;
495       printf("\t%.*s", (int)len, p + 1);
496       p += len + 1;
497       len = *p;
498       if (p + len + 1 > aptr + dlen)
499         return NULL;
500       printf("\t%.*s", (int)len, p + 1);
501       break;
502
503     case T_MINFO:
504       /* The RR data is two domain names. */
505       p = aptr;
506       status = ares_expand_name(p, abuf, alen, &name, &len);
507       if (status != ARES_SUCCESS)
508         return NULL;
509       printf("\t%s.", name);
510       ares_free_string(name);
511       p += len;
512       status = ares_expand_name(p, abuf, alen, &name, &len);
513       if (status != ARES_SUCCESS)
514         return NULL;
515       printf("\t%s.", name);
516       ares_free_string(name);
517       break;
518
519     case T_MX:
520       /* The RR data is two bytes giving a preference ordering, and
521        * then a domain name.
522        */
523       if (dlen < 2)
524         return NULL;
525       printf("\t%d", DNS__16BIT(aptr));
526       status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
527       if (status != ARES_SUCCESS)
528         return NULL;
529       printf("\t%s.", name);
530       ares_free_string(name);
531       break;
532
533     case T_SOA:
534       /* The RR data is two domain names and then five four-byte
535        * numbers giving the serial number and some timeouts.
536        */
537       p = aptr;
538       status = ares_expand_name(p, abuf, alen, &name, &len);
539       if (status != ARES_SUCCESS)
540         return NULL;
541       printf("\t%s.\n", name);
542       ares_free_string(name);
543       p += len;
544       status = ares_expand_name(p, abuf, alen, &name, &len);
545       if (status != ARES_SUCCESS)
546         return NULL;
547       printf("\t\t\t\t\t\t%s.\n", name);
548       ares_free_string(name);
549       p += len;
550       if (p + 20 > aptr + dlen)
551         return NULL;
552       printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
553              (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
554              (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
555              (unsigned long)DNS__32BIT(p+16));
556       break;
557
558     case T_TXT:
559       /* The RR data is one or more length-counted character
560        * strings. */
561       p = aptr;
562       while (p < aptr + dlen)
563         {
564           len = *p;
565           if (p + len + 1 > aptr + dlen)
566             return NULL;
567           printf("\t%.*s", (int)len, p + 1);
568           p += len + 1;
569         }
570       break;
571
572     case T_A:
573       /* The RR data is a four-byte Internet address. */
574       if (dlen != 4)
575         return NULL;
576       printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
577       break;
578
579     case T_AAAA:
580       /* The RR data is a 16-byte IPv6 address. */
581       if (dlen != 16)
582         return NULL;
583       printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
584       break;
585
586     case T_WKS:
587       /* Not implemented yet */
588       break;
589
590     case T_SRV:
591       /* The RR data is three two-byte numbers representing the
592        * priority, weight, and port, followed by a domain name.
593        */
594
595       printf("\t%d", DNS__16BIT(aptr));
596       printf(" %d", DNS__16BIT(aptr + 2));
597       printf(" %d", DNS__16BIT(aptr + 4));
598
599       status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
600       if (status != ARES_SUCCESS)
601         return NULL;
602       printf("\t%s.", name);
603       ares_free_string(name);
604       break;
605
606     default:
607       printf("\t[Unknown RR; cannot parse]");
608       break;
609     }
610   printf("\n");
611
612   return aptr + dlen;
613 }
614
615 static const char *type_name(int type)
616 {
617   int i;
618
619   for (i = 0; i < ntypes; i++)
620     {
621       if (types[i].value == type)
622         return types[i].name;
623     }
624   return "(unknown)";
625 }
626
627 static const char *class_name(int dnsclass)
628 {
629   int i;
630
631   for (i = 0; i < nclasses; i++)
632     {
633       if (classes[i].value == dnsclass)
634         return classes[i].name;
635     }
636   return "(unknown)";
637 }
638
639 static void usage(void)
640 {
641   fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
642           "[-t type] [-p port] name ...\n");
643   exit(1);
644 }