1 /* Copyright 1998 by the Massachusetts Institute of Technology.
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.
17 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <arpa/nameser.h>
40 #define INADDR_NONE 0xffffffff
43 /* Mac OS X portability check */
45 #define T_SRV 33 /* server selection */
56 static const struct nv flags[] = {
57 { "usevc", ARES_FLAG_USEVC },
58 { "primary", ARES_FLAG_PRIMARY },
59 { "igntc", ARES_FLAG_IGNTC },
60 { "norecurse", ARES_FLAG_NORECURSE },
61 { "stayopen", ARES_FLAG_STAYOPEN },
62 { "noaliases", ARES_FLAG_NOALIASES }
64 static const int nflags = sizeof(flags) / sizeof(flags[0]);
66 static const struct nv classes[] = {
72 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
74 static const struct nv types[] = {
97 { "NSAP_PTR", T_NSAP_PTR },
106 { "MAILB", T_MAILB },
107 { "MAILA", T_MAILA },
110 static const int ntypes = sizeof(types) / sizeof(types[0]);
112 static const char *opcodes[] = {
113 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
114 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
115 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
116 "ZONEINIT", "ZONEREF"
119 static const char *rcodes[] = {
120 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
121 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
122 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
125 static void callback(void *arg, int status, unsigned char *abuf, int alen);
126 static const unsigned char *display_question(const unsigned char *aptr,
127 const unsigned char *abuf,
129 static const unsigned char *display_rr(const unsigned char *aptr,
130 const unsigned char *abuf, int alen);
131 static const char *type_name(int type);
132 static const char *class_name(int dnsclass);
133 static void usage(void);
135 int main(int argc, char **argv)
137 ares_channel channel;
138 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
139 int status, nfds, count;
140 struct ares_options options;
141 struct hostent *hostent;
142 fd_set read_fds, write_fds;
143 struct timeval *tvp, tv;
146 WORD wVersionRequested = MAKEWORD(1,1);
148 WSAStartup(wVersionRequested, &wsaData);
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)
160 for (i = 0; i < nflags; i++)
162 if (strcmp(flags[i].name, optarg) == 0)
167 options.flags |= flags[i].value;
171 /* Add a server, and specify servers in the option mask. */
172 hostent = gethostbyname(optarg);
173 if (!hostent || hostent->h_addrtype != AF_INET)
175 fprintf(stderr, "adig: server %s not found.\n", optarg);
178 options.servers = realloc(options.servers, (options.nservers + 1)
179 * sizeof(struct in_addr));
180 if (!options.servers)
182 fprintf(stderr, "Out of memory!\n");
185 memcpy(&options.servers[options.nservers], hostent->h_addr,
186 sizeof(struct in_addr));
188 optmask |= ARES_OPT_SERVERS;
192 /* Set the query class. */
193 for (i = 0; i < nclasses; i++)
195 if (strcasecmp(classes[i].name, optarg) == 0)
200 dnsclass = classes[i].value;
204 /* Set the query type. */
205 for (i = 0; i < ntypes; i++)
207 if (strcasecmp(types[i].name, optarg) == 0)
212 type = types[i].value;
216 /* Set the TCP port number. */
217 if (!isdigit((unsigned char)*optarg))
219 options.tcp_port = strtol(optarg, NULL, 0);
220 optmask |= ARES_OPT_TCP_PORT;
224 /* Set the UDP port number. */
225 if (!isdigit((unsigned char)*optarg))
227 options.udp_port = strtol(optarg, NULL, 0);
228 optmask |= ARES_OPT_UDP_PORT;
237 status = ares_init_options(&channel, &options, optmask);
239 if (status != ARES_SUCCESS)
241 fprintf(stderr, "ares_init_options: %s\n",
242 ares_strerror(status));
246 /* Initiate the queries, one per command-line argument. If there is
247 * only one query to do, supply NULL as the callback argument;
248 * otherwise, supply the query name as an argument so we can
249 * distinguish responses for the user when printing them out.
252 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
255 for (; *argv; argv++)
256 ares_query(channel, *argv, dnsclass, type, callback, *argv);
259 /* Wait for all queries to complete. */
264 nfds = ares_fds(channel, &read_fds, &write_fds);
267 tvp = ares_timeout(channel, NULL, &tv);
268 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
269 if (count < 0 && errno != EINVAL)
274 ares_process(channel, &read_fds, &write_fds);
277 ares_destroy(channel);
281 static void callback(void *arg, int status, unsigned char *abuf, int alen)
283 char *name = (char *) arg;
284 int id, qr, opcode, aa, tc, rd, ra, rcode;
285 unsigned int qdcount, ancount, nscount, arcount, i;
286 const unsigned char *aptr;
288 /* Display the query name if given. */
290 printf("Answer for query %s:\n", name);
292 /* Display an error message if there was an error, but only stop if
293 * we actually didn't get an answer buffer.
295 if (status != ARES_SUCCESS)
297 printf("%s\n", ares_strerror(status));
302 /* Won't happen, but check anyway, for safety. */
306 /* Parse the answer header. */
307 id = DNS_HEADER_QID(abuf);
308 qr = DNS_HEADER_QR(abuf);
309 opcode = DNS_HEADER_OPCODE(abuf);
310 aa = DNS_HEADER_AA(abuf);
311 tc = DNS_HEADER_TC(abuf);
312 rd = DNS_HEADER_RD(abuf);
313 ra = DNS_HEADER_RA(abuf);
314 rcode = DNS_HEADER_RCODE(abuf);
315 qdcount = DNS_HEADER_QDCOUNT(abuf);
316 ancount = DNS_HEADER_ANCOUNT(abuf);
317 nscount = DNS_HEADER_NSCOUNT(abuf);
318 arcount = DNS_HEADER_ARCOUNT(abuf);
320 /* Display the answer header. */
321 printf("id: %d\n", id);
322 printf("flags: %s%s%s%s%s\n",
328 printf("opcode: %s\n", opcodes[opcode]);
329 printf("rcode: %s\n", rcodes[rcode]);
331 /* Display the questions. */
332 printf("Questions:\n");
333 aptr = abuf + HFIXEDSZ;
334 for (i = 0; i < qdcount; i++)
336 aptr = display_question(aptr, abuf, alen);
341 /* Display the answers. */
342 printf("Answers:\n");
343 for (i = 0; i < ancount; i++)
345 aptr = display_rr(aptr, abuf, alen);
350 /* Display the NS records. */
351 printf("NS records:\n");
352 for (i = 0; i < nscount; i++)
354 aptr = display_rr(aptr, abuf, alen);
359 /* Display the additional records. */
360 printf("Additional records:\n");
361 for (i = 0; i < arcount; i++)
363 aptr = display_rr(aptr, abuf, alen);
369 static const unsigned char *display_question(const unsigned char *aptr,
370 const unsigned char *abuf,
374 int type, dnsclass, status;
377 /* Parse the question name. */
378 status = ares_expand_name(aptr, abuf, alen, &name, &len);
379 if (status != ARES_SUCCESS)
383 /* Make sure there's enough data after the name for the fixed part
386 if (aptr + QFIXEDSZ > abuf + alen)
392 /* Parse the question type and class. */
393 type = DNS_QUESTION_TYPE(aptr);
394 dnsclass = DNS_QUESTION_CLASS(aptr);
397 /* Display the question, in a format sort of similar to how we will
400 printf("\t%-15s.\t", name);
401 if (dnsclass != C_IN)
402 printf("\t%s", class_name(dnsclass));
403 printf("\t%s\n", type_name(type));
408 static const unsigned char *display_rr(const unsigned char *aptr,
409 const unsigned char *abuf, int alen)
411 const unsigned char *p;
413 int type, dnsclass, ttl, dlen, status;
417 /* Parse the RR name. */
418 status = ares_expand_name(aptr, abuf, alen, &name, &len);
419 if (status != ARES_SUCCESS)
423 /* Make sure there is enough data after the RR name for the fixed
426 if (aptr + RRFIXEDSZ > abuf + alen)
432 /* Parse the fixed part of the RR, and advance to the RR data
434 type = DNS_RR_TYPE(aptr);
435 dnsclass = DNS_RR_CLASS(aptr);
436 ttl = DNS_RR_TTL(aptr);
437 dlen = DNS_RR_LEN(aptr);
439 if (aptr + dlen > abuf + alen)
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));
452 /* Display the RR data. Don't touch aptr. */
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)
467 printf("\t%s.", name);
472 /* The RR data is two length-counted character strings. */
475 if (p + len + 1 > aptr + dlen)
477 printf("\t%.*s", len, p + 1);
480 if (p + len + 1 > aptr + dlen)
482 printf("\t%.*s", len, p + 1);
486 /* The RR data is two domain names. */
488 status = ares_expand_name(p, abuf, alen, &name, &len);
489 if (status != ARES_SUCCESS)
491 printf("\t%s.", name);
494 status = ares_expand_name(p, abuf, alen, &name, &len);
495 if (status != ARES_SUCCESS)
497 printf("\t%s.", name);
502 /* The RR data is two bytes giving a preference ordering, and
503 * then a domain name.
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)
511 printf("\t%s.", name);
516 /* The RR data is two domain names and then five four-byte
517 * numbers giving the serial number and some timeouts.
520 status = ares_expand_name(p, abuf, alen, &name, &len);
521 if (status != ARES_SUCCESS)
523 printf("\t%s.\n", name);
526 status = ares_expand_name(p, abuf, alen, &name, &len);
527 if (status != ARES_SUCCESS)
529 printf("\t\t\t\t\t\t%s.\n", name);
532 if (p + 20 > aptr + dlen)
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]);
543 /* The RR data is one or more length-counted character
546 while (p < aptr + dlen)
549 if (p + len + 1 > aptr + dlen)
551 printf("\t%.*s", len, p + 1);
557 /* The RR data is a four-byte Internet address. */
560 memcpy(&addr, aptr, sizeof(struct in_addr));
561 printf("\t%s", inet_ntoa(addr));
565 /* Not implemented yet */
569 /* The RR data is three two-byte numbers representing the
570 * priority, weight, and port, followed by a domain name.
573 printf("\t%d", DNS__16BIT(aptr));
574 printf(" %d", DNS__16BIT(aptr + 2));
575 printf(" %d", DNS__16BIT(aptr + 4));
577 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
578 if (status != ARES_SUCCESS)
580 printf("\t%s.", name);
585 printf("\t[Unknown RR; cannot parse]");
592 static const char *type_name(int type)
596 for (i = 0; i < ntypes; i++)
598 if (types[i].value == type)
599 return types[i].name;
604 static const char *class_name(int dnsclass)
608 for (i = 0; i < nclasses; i++)
610 if (classes[i].value == dnsclass)
611 return classes[i].name;
616 static void usage(void)
618 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
619 "[-t type] [-p port] name ...\n");