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