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