1 /* Copyright 1998 by the Massachusetts Institute of Technology.
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.
20 #if defined(WIN32) && !defined(WATT32)
23 #ifdef HAVE_SYS_TIME_H
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>
50 #include "inet_ntop.h"
51 #include "ares_getopt.h"
54 #undef WIN32 /* Redefined in MingW headers */
57 /* Mac OS X portability check */
59 #define T_SRV 33 /* server selection */
67 static const struct nv flags[] = {
68 { "usevc", ARES_FLAG_USEVC },
69 { "primary", ARES_FLAG_PRIMARY },
70 { "igntc", ARES_FLAG_IGNTC },
71 { "norecurse", ARES_FLAG_NORECURSE },
72 { "stayopen", ARES_FLAG_STAYOPEN },
73 { "noaliases", ARES_FLAG_NOALIASES }
75 static const int nflags = sizeof(flags) / sizeof(flags[0]);
77 static const struct nv classes[] = {
83 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
85 static const struct nv types[] = {
103 { "AFSDB", T_AFSDB },
108 { "NSAP_PTR", T_NSAP_PTR },
117 { "MAILB", T_MAILB },
118 { "MAILA", T_MAILA },
119 { "NAPTR", T_NAPTR },
122 static const int ntypes = sizeof(types) / sizeof(types[0]);
124 static const char *opcodes[] = {
125 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
126 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
127 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
128 "ZONEINIT", "ZONEREF"
131 static const char *rcodes[] = {
132 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
133 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
134 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
137 static void callback(void *arg, int status, int timeouts,
138 unsigned char *abuf, int alen);
139 static const unsigned char *display_question(const unsigned char *aptr,
140 const unsigned char *abuf,
142 static const unsigned char *display_rr(const unsigned char *aptr,
143 const unsigned char *abuf, int alen);
144 static const char *type_name(int type);
145 static const char *class_name(int dnsclass);
146 static void usage(void);
148 int main(int argc, char **argv)
150 ares_channel channel;
151 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
152 int status, nfds, count;
153 struct ares_options options;
154 struct hostent *hostent;
155 fd_set read_fds, write_fds;
156 struct timeval *tvp, tv;
159 WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
161 WSAStartup(wVersionRequested, &wsaData);
164 options.flags = ARES_FLAG_NOCHECKRESP;
165 options.servers = NULL;
166 options.nservers = 0;
167 while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1)
179 for (i = 0; i < nflags; i++)
181 if (strcmp(flags[i].name, optarg) == 0)
186 options.flags |= flags[i].value;
190 /* Add a server, and specify servers in the option mask. */
191 hostent = gethostbyname(optarg);
192 if (!hostent || hostent->h_addrtype != AF_INET)
194 fprintf(stderr, "adig: server %s not found.\n", optarg);
197 options.servers = realloc(options.servers, (options.nservers + 1)
198 * sizeof(struct in_addr));
199 if (!options.servers)
201 fprintf(stderr, "Out of memory!\n");
204 memcpy(&options.servers[options.nservers], hostent->h_addr,
205 sizeof(struct in_addr));
207 optmask |= ARES_OPT_SERVERS;
211 /* Set the query class. */
212 for (i = 0; i < nclasses; i++)
214 if (strcasecmp(classes[i].name, optarg) == 0)
219 dnsclass = classes[i].value;
223 /* Set the query type. */
224 for (i = 0; i < ntypes; i++)
226 if (strcasecmp(types[i].name, optarg) == 0)
231 type = types[i].value;
235 /* Set the TCP port number. */
236 if (!ISDIGIT(*optarg))
238 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
239 optmask |= ARES_OPT_TCP_PORT;
243 /* Set the UDP port number. */
244 if (!ISDIGIT(*optarg))
246 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
247 optmask |= ARES_OPT_UDP_PORT;
256 status = ares_init_options(&channel, &options, optmask);
258 if (status != ARES_SUCCESS)
260 fprintf(stderr, "ares_init_options: %s\n",
261 ares_strerror(status));
265 /* Initiate the queries, one per command-line argument. If there is
266 * only one query to do, supply NULL as the callback argument;
267 * otherwise, supply the query name as an argument so we can
268 * distinguish responses for the user when printing them out.
271 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
274 for (; *argv; argv++)
275 ares_query(channel, *argv, dnsclass, type, callback, *argv);
278 /* Wait for all queries to complete. */
283 nfds = ares_fds(channel, &read_fds, &write_fds);
286 tvp = ares_timeout(channel, NULL, &tv);
287 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
288 if (count < 0 && SOCKERRNO != EINVAL)
293 ares_process(channel, &read_fds, &write_fds);
296 ares_destroy(channel);
305 static void callback(void *arg, int status, int timeouts,
306 unsigned char *abuf, int alen)
308 char *name = (char *) arg;
309 int id, qr, opcode, aa, tc, rd, ra, rcode;
310 unsigned int qdcount, ancount, nscount, arcount, i;
311 const unsigned char *aptr;
315 /* Display the query name if given. */
317 printf("Answer for query %s:\n", name);
319 /* Display an error message if there was an error, but only stop if
320 * we actually didn't get an answer buffer.
322 if (status != ARES_SUCCESS)
324 printf("%s\n", ares_strerror(status));
329 /* Won't happen, but check anyway, for safety. */
333 /* Parse the answer header. */
334 id = DNS_HEADER_QID(abuf);
335 qr = DNS_HEADER_QR(abuf);
336 opcode = DNS_HEADER_OPCODE(abuf);
337 aa = DNS_HEADER_AA(abuf);
338 tc = DNS_HEADER_TC(abuf);
339 rd = DNS_HEADER_RD(abuf);
340 ra = DNS_HEADER_RA(abuf);
341 rcode = DNS_HEADER_RCODE(abuf);
342 qdcount = DNS_HEADER_QDCOUNT(abuf);
343 ancount = DNS_HEADER_ANCOUNT(abuf);
344 nscount = DNS_HEADER_NSCOUNT(abuf);
345 arcount = DNS_HEADER_ARCOUNT(abuf);
347 /* Display the answer header. */
348 printf("id: %d\n", id);
349 printf("flags: %s%s%s%s%s\n",
355 printf("opcode: %s\n", opcodes[opcode]);
356 printf("rcode: %s\n", rcodes[rcode]);
358 /* Display the questions. */
359 printf("Questions:\n");
360 aptr = abuf + HFIXEDSZ;
361 for (i = 0; i < qdcount; i++)
363 aptr = display_question(aptr, abuf, alen);
368 /* Display the answers. */
369 printf("Answers:\n");
370 for (i = 0; i < ancount; i++)
372 aptr = display_rr(aptr, abuf, alen);
377 /* Display the NS records. */
378 printf("NS records:\n");
379 for (i = 0; i < nscount; i++)
381 aptr = display_rr(aptr, abuf, alen);
386 /* Display the additional records. */
387 printf("Additional records:\n");
388 for (i = 0; i < arcount; i++)
390 aptr = display_rr(aptr, abuf, alen);
396 static const unsigned char *display_question(const unsigned char *aptr,
397 const unsigned char *abuf,
401 int type, dnsclass, status;
404 /* Parse the question name. */
405 status = ares_expand_name(aptr, abuf, alen, &name, &len);
406 if (status != ARES_SUCCESS)
410 /* Make sure there's enough data after the name for the fixed part
413 if (aptr + QFIXEDSZ > abuf + alen)
415 ares_free_string(name);
419 /* Parse the question type and class. */
420 type = DNS_QUESTION_TYPE(aptr);
421 dnsclass = DNS_QUESTION_CLASS(aptr);
424 /* Display the question, in a format sort of similar to how we will
427 printf("\t%-15s.\t", name);
428 if (dnsclass != C_IN)
429 printf("\t%s", class_name(dnsclass));
430 printf("\t%s\n", type_name(type));
431 ares_free_string(name);
435 static const unsigned char *display_rr(const unsigned char *aptr,
436 const unsigned char *abuf, int alen)
438 const unsigned char *p;
440 int type, dnsclass, ttl, dlen, status;
444 /* Parse the RR name. */
445 status = ares_expand_name(aptr, abuf, alen, &name, &len);
446 if (status != ARES_SUCCESS)
450 /* Make sure there is enough data after the RR name for the fixed
453 if (aptr + RRFIXEDSZ > abuf + alen)
455 ares_free_string(name);
459 /* Parse the fixed part of the RR, and advance to the RR data
461 type = DNS_RR_TYPE(aptr);
462 dnsclass = DNS_RR_CLASS(aptr);
463 ttl = DNS_RR_TTL(aptr);
464 dlen = DNS_RR_LEN(aptr);
466 if (aptr + dlen > abuf + alen)
468 ares_free_string(name);
472 /* Display the RR name, class, and type. */
473 printf("\t%-15s.\t%d", name, ttl);
474 if (dnsclass != C_IN)
475 printf("\t%s", class_name(dnsclass));
476 printf("\t%s", type_name(type));
477 ares_free_string(name);
479 /* Display the RR data. Don't touch aptr. */
490 /* For these types, the RR data is just a domain name. */
491 status = ares_expand_name(aptr, abuf, alen, &name, &len);
492 if (status != ARES_SUCCESS)
494 printf("\t%s.", name);
495 ares_free_string(name);
499 /* The RR data is two length-counted character strings. */
502 if (p + len + 1 > aptr + dlen)
504 printf("\t%.*s", (int)len, p + 1);
507 if (p + len + 1 > aptr + dlen)
509 printf("\t%.*s", (int)len, p + 1);
513 /* The RR data is two domain names. */
515 status = ares_expand_name(p, abuf, alen, &name, &len);
516 if (status != ARES_SUCCESS)
518 printf("\t%s.", name);
519 ares_free_string(name);
521 status = ares_expand_name(p, abuf, alen, &name, &len);
522 if (status != ARES_SUCCESS)
524 printf("\t%s.", name);
525 ares_free_string(name);
529 /* The RR data is two bytes giving a preference ordering, and
530 * then a domain name.
534 printf("\t%d", DNS__16BIT(aptr));
535 status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
536 if (status != ARES_SUCCESS)
538 printf("\t%s.", name);
539 ares_free_string(name);
543 /* The RR data is two domain names and then five four-byte
544 * numbers giving the serial number and some timeouts.
547 status = ares_expand_name(p, abuf, alen, &name, &len);
548 if (status != ARES_SUCCESS)
550 printf("\t%s.\n", name);
551 ares_free_string(name);
553 status = ares_expand_name(p, abuf, alen, &name, &len);
554 if (status != ARES_SUCCESS)
556 printf("\t\t\t\t\t\t%s.\n", name);
557 ares_free_string(name);
559 if (p + 20 > aptr + dlen)
561 printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
562 (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
563 (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
564 (unsigned long)DNS__32BIT(p+16));
568 /* The RR data is one or more length-counted character
571 while (p < aptr + dlen)
574 if (p + len + 1 > aptr + dlen)
576 printf("\t%.*s", (int)len, p + 1);
582 /* The RR data is a four-byte Internet address. */
585 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
589 /* The RR data is a 16-byte IPv6 address. */
592 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
596 /* Not implemented yet */
600 /* The RR data is three two-byte numbers representing the
601 * priority, weight, and port, followed by a domain name.
604 printf("\t%d", DNS__16BIT(aptr));
605 printf(" %d", DNS__16BIT(aptr + 2));
606 printf(" %d", DNS__16BIT(aptr + 4));
608 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
609 if (status != ARES_SUCCESS)
611 printf("\t%s.", name);
612 ares_free_string(name);
617 printf("\t%d", DNS__16BIT(aptr)); /* order */
618 printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */
621 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
622 if (status != ARES_SUCCESS)
624 printf("\t\t\t\t\t\t%s\n", name);
625 ares_free_string(name);
628 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
629 if (status != ARES_SUCCESS)
631 printf("\t\t\t\t\t\t%s\n", name);
632 ares_free_string(name);
635 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
636 if (status != ARES_SUCCESS)
638 printf("\t\t\t\t\t\t%s\n", name);
639 ares_free_string(name);
642 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
643 if (status != ARES_SUCCESS)
645 printf("\t\t\t\t\t\t%s", name);
646 ares_free_string(name);
651 printf("\t[Unknown RR; cannot parse]");
659 static const char *type_name(int type)
663 for (i = 0; i < ntypes; i++)
665 if (types[i].value == type)
666 return types[i].name;
671 static const char *class_name(int dnsclass)
675 for (i = 0; i < nclasses; i++)
677 if (classes[i].value == dnsclass)
678 return classes[i].name;
683 static void usage(void)
685 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
686 "[-t type] [-p port] name ...\n");