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