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