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