source: trunk/athena/lib/ares/adig.c @ 12098

Revision 12098, 14.2 KB checked in by ghudson, 26 years ago (diff)
Fix a tiny typo in the types table.
Line 
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
16static const char rcsid[] = "$Id: adig.c,v 1.5 1998-11-02 19:37:47 ghudson 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
38extern int optind;
39extern char *optarg;
40
41struct nv {
42  const char *name;
43  int value;
44};
45
46static 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};
54static const int nflags = sizeof(flags) / sizeof(flags[0]);
55
56static const struct nv classes[] = {
57  { "IN",       C_IN },
58  { "CHAOS",    C_CHAOS },
59  { "HS",       C_HS },
60  { "ANY",      C_ANY }
61};
62static const int nclasses = sizeof(classes) / sizeof(classes[0]);
63
64static 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};
103static const int ntypes = sizeof(types) / sizeof(types[0]);
104
105static 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
112static const char *rcodes[] = {
113  "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
114  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
115  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
116};
117
118static void callback(void *arg, int status, unsigned char *abuf, int alen);
119static const unsigned char *display_question(const unsigned char *aptr,
120                                             const unsigned char *abuf,
121                                             int alen);
122static const unsigned char *display_rr(const unsigned char *aptr,
123                                       const unsigned char *abuf, int alen);
124static const char *type_name(int type);
125static const char *class_name(int class);
126static void usage(void);
127
128int 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(*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(*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
269static 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
358static 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
396static 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
560static 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
572static 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
584static 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}
Note: See TracBrowser for help on using the repository browser.