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