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