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 # include "ares_strdup.h"
55 # define strdup(ptr) ares_strdup(ptr)
58 #ifndef HAVE_STRCASECMP
59 # include "ares_strcasecmp.h"
60 # define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
63 #ifndef HAVE_STRNCASECMP
64 # include "ares_strcasecmp.h"
65 # define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
69 #undef WIN32 /* Redefined in MingW headers */
72 /* Mac OS X portability check */
74 #define T_SRV 33 /* server selection */
82 static const struct nv flags[] = {
83 { "usevc", ARES_FLAG_USEVC },
84 { "primary", ARES_FLAG_PRIMARY },
85 { "igntc", ARES_FLAG_IGNTC },
86 { "norecurse", ARES_FLAG_NORECURSE },
87 { "stayopen", ARES_FLAG_STAYOPEN },
88 { "noaliases", ARES_FLAG_NOALIASES }
90 static const int nflags = sizeof(flags) / sizeof(flags[0]);
92 static const struct nv classes[] = {
98 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
100 static const struct nv types[] = {
105 { "CNAME", T_CNAME },
113 { "HINFO", T_HINFO },
114 { "MINFO", T_MINFO },
118 { "AFSDB", T_AFSDB },
123 { "NSAP_PTR", T_NSAP_PTR },
132 { "MAILB", T_MAILB },
133 { "MAILA", T_MAILA },
134 { "NAPTR", T_NAPTR },
137 static const int ntypes = sizeof(types) / sizeof(types[0]);
139 static const char *opcodes[] = {
140 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
141 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
142 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
143 "ZONEINIT", "ZONEREF"
146 static const char *rcodes[] = {
147 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
148 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
149 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
152 static void callback(void *arg, int status, int timeouts,
153 unsigned char *abuf, int alen);
154 static const unsigned char *display_question(const unsigned char *aptr,
155 const unsigned char *abuf,
157 static const unsigned char *display_rr(const unsigned char *aptr,
158 const unsigned char *abuf, int alen);
159 static const char *type_name(int type);
160 static const char *class_name(int dnsclass);
161 static void usage(void);
163 int main(int argc, char **argv)
165 ares_channel channel;
166 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
167 int status, nfds, count;
168 struct ares_options options;
169 struct hostent *hostent;
170 fd_set read_fds, write_fds;
171 struct timeval *tvp, tv;
174 WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
176 WSAStartup(wVersionRequested, &wsaData);
179 options.flags = ARES_FLAG_NOCHECKRESP;
180 options.servers = NULL;
181 options.nservers = 0;
182 while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1)
194 for (i = 0; i < nflags; i++)
196 if (strcmp(flags[i].name, optarg) == 0)
201 options.flags |= flags[i].value;
205 /* Add a server, and specify servers in the option mask. */
206 hostent = gethostbyname(optarg);
207 if (!hostent || hostent->h_addrtype != AF_INET)
209 fprintf(stderr, "adig: server %s not found.\n", optarg);
212 options.servers = realloc(options.servers, (options.nservers + 1)
213 * sizeof(struct in_addr));
214 if (!options.servers)
216 fprintf(stderr, "Out of memory!\n");
219 memcpy(&options.servers[options.nservers], hostent->h_addr,
220 sizeof(struct in_addr));
222 optmask |= ARES_OPT_SERVERS;
226 /* Set the query class. */
227 for (i = 0; i < nclasses; i++)
229 if (strcasecmp(classes[i].name, optarg) == 0)
234 dnsclass = classes[i].value;
238 /* Set the query type. */
239 for (i = 0; i < ntypes; i++)
241 if (strcasecmp(types[i].name, optarg) == 0)
246 type = types[i].value;
250 /* Set the TCP port number. */
251 if (!ISDIGIT(*optarg))
253 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
254 optmask |= ARES_OPT_TCP_PORT;
258 /* Set the UDP port number. */
259 if (!ISDIGIT(*optarg))
261 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
262 optmask |= ARES_OPT_UDP_PORT;
271 status = ares_init_options(&channel, &options, optmask);
273 if (status != ARES_SUCCESS)
275 fprintf(stderr, "ares_init_options: %s\n",
276 ares_strerror(status));
280 /* Initiate the queries, one per command-line argument. If there is
281 * only one query to do, supply NULL as the callback argument;
282 * otherwise, supply the query name as an argument so we can
283 * distinguish responses for the user when printing them out.
286 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
289 for (; *argv; argv++)
290 ares_query(channel, *argv, dnsclass, type, callback, *argv);
293 /* Wait for all queries to complete. */
298 nfds = ares_fds(channel, &read_fds, &write_fds);
301 tvp = ares_timeout(channel, NULL, &tv);
302 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
303 if (count < 0 && SOCKERRNO != EINVAL)
308 ares_process(channel, &read_fds, &write_fds);
311 ares_destroy(channel);
320 static void callback(void *arg, int status, int timeouts,
321 unsigned char *abuf, int alen)
323 char *name = (char *) arg;
324 int id, qr, opcode, aa, tc, rd, ra, rcode;
325 unsigned int qdcount, ancount, nscount, arcount, i;
326 const unsigned char *aptr;
330 /* Display the query name if given. */
332 printf("Answer for query %s:\n", name);
334 /* Display an error message if there was an error, but only stop if
335 * we actually didn't get an answer buffer.
337 if (status != ARES_SUCCESS)
339 printf("%s\n", ares_strerror(status));
344 /* Won't happen, but check anyway, for safety. */
348 /* Parse the answer header. */
349 id = DNS_HEADER_QID(abuf);
350 qr = DNS_HEADER_QR(abuf);
351 opcode = DNS_HEADER_OPCODE(abuf);
352 aa = DNS_HEADER_AA(abuf);
353 tc = DNS_HEADER_TC(abuf);
354 rd = DNS_HEADER_RD(abuf);
355 ra = DNS_HEADER_RA(abuf);
356 rcode = DNS_HEADER_RCODE(abuf);
357 qdcount = DNS_HEADER_QDCOUNT(abuf);
358 ancount = DNS_HEADER_ANCOUNT(abuf);
359 nscount = DNS_HEADER_NSCOUNT(abuf);
360 arcount = DNS_HEADER_ARCOUNT(abuf);
362 /* Display the answer header. */
363 printf("id: %d\n", id);
364 printf("flags: %s%s%s%s%s\n",
370 printf("opcode: %s\n", opcodes[opcode]);
371 printf("rcode: %s\n", rcodes[rcode]);
373 /* Display the questions. */
374 printf("Questions:\n");
375 aptr = abuf + HFIXEDSZ;
376 for (i = 0; i < qdcount; i++)
378 aptr = display_question(aptr, abuf, alen);
383 /* Display the answers. */
384 printf("Answers:\n");
385 for (i = 0; i < ancount; i++)
387 aptr = display_rr(aptr, abuf, alen);
392 /* Display the NS records. */
393 printf("NS records:\n");
394 for (i = 0; i < nscount; i++)
396 aptr = display_rr(aptr, abuf, alen);
401 /* Display the additional records. */
402 printf("Additional records:\n");
403 for (i = 0; i < arcount; i++)
405 aptr = display_rr(aptr, abuf, alen);
411 static const unsigned char *display_question(const unsigned char *aptr,
412 const unsigned char *abuf,
416 int type, dnsclass, status;
419 /* Parse the question name. */
420 status = ares_expand_name(aptr, abuf, alen, &name, &len);
421 if (status != ARES_SUCCESS)
425 /* Make sure there's enough data after the name for the fixed part
428 if (aptr + QFIXEDSZ > abuf + alen)
430 ares_free_string(name);
434 /* Parse the question type and class. */
435 type = DNS_QUESTION_TYPE(aptr);
436 dnsclass = DNS_QUESTION_CLASS(aptr);
439 /* Display the question, in a format sort of similar to how we will
442 printf("\t%-15s.\t", name);
443 if (dnsclass != C_IN)
444 printf("\t%s", class_name(dnsclass));
445 printf("\t%s\n", type_name(type));
446 ares_free_string(name);
450 static const unsigned char *display_rr(const unsigned char *aptr,
451 const unsigned char *abuf, int alen)
453 const unsigned char *p;
455 int type, dnsclass, ttl, dlen, status;
459 /* Parse the RR name. */
460 status = ares_expand_name(aptr, abuf, alen, &name, &len);
461 if (status != ARES_SUCCESS)
465 /* Make sure there is enough data after the RR name for the fixed
468 if (aptr + RRFIXEDSZ > abuf + alen)
470 ares_free_string(name);
474 /* Parse the fixed part of the RR, and advance to the RR data
476 type = DNS_RR_TYPE(aptr);
477 dnsclass = DNS_RR_CLASS(aptr);
478 ttl = DNS_RR_TTL(aptr);
479 dlen = DNS_RR_LEN(aptr);
481 if (aptr + dlen > abuf + alen)
483 ares_free_string(name);
487 /* Display the RR name, class, and type. */
488 printf("\t%-15s.\t%d", name, ttl);
489 if (dnsclass != C_IN)
490 printf("\t%s", class_name(dnsclass));
491 printf("\t%s", type_name(type));
492 ares_free_string(name);
494 /* Display the RR data. Don't touch aptr. */
505 /* For these types, the RR data is just a domain name. */
506 status = ares_expand_name(aptr, abuf, alen, &name, &len);
507 if (status != ARES_SUCCESS)
509 printf("\t%s.", name);
510 ares_free_string(name);
514 /* The RR data is two length-counted character strings. */
517 if (p + len + 1 > aptr + dlen)
519 printf("\t%.*s", (int)len, p + 1);
522 if (p + len + 1 > aptr + dlen)
524 printf("\t%.*s", (int)len, p + 1);
528 /* The RR data is two domain names. */
530 status = ares_expand_name(p, abuf, alen, &name, &len);
531 if (status != ARES_SUCCESS)
533 printf("\t%s.", name);
534 ares_free_string(name);
536 status = ares_expand_name(p, abuf, alen, &name, &len);
537 if (status != ARES_SUCCESS)
539 printf("\t%s.", name);
540 ares_free_string(name);
544 /* The RR data is two bytes giving a preference ordering, and
545 * then a domain name.
549 printf("\t%d", DNS__16BIT(aptr));
550 status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
551 if (status != ARES_SUCCESS)
553 printf("\t%s.", name);
554 ares_free_string(name);
558 /* The RR data is two domain names and then five four-byte
559 * numbers giving the serial number and some timeouts.
562 status = ares_expand_name(p, abuf, alen, &name, &len);
563 if (status != ARES_SUCCESS)
565 printf("\t%s.\n", name);
566 ares_free_string(name);
568 status = ares_expand_name(p, abuf, alen, &name, &len);
569 if (status != ARES_SUCCESS)
571 printf("\t\t\t\t\t\t%s.\n", name);
572 ares_free_string(name);
574 if (p + 20 > aptr + dlen)
576 printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
577 (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
578 (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
579 (unsigned long)DNS__32BIT(p+16));
583 /* The RR data is one or more length-counted character
586 while (p < aptr + dlen)
589 if (p + len + 1 > aptr + dlen)
591 printf("\t%.*s", (int)len, p + 1);
597 /* The RR data is a four-byte Internet address. */
600 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
604 /* The RR data is a 16-byte IPv6 address. */
607 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
611 /* Not implemented yet */
615 /* The RR data is three two-byte numbers representing the
616 * priority, weight, and port, followed by a domain name.
619 printf("\t%d", DNS__16BIT(aptr));
620 printf(" %d", DNS__16BIT(aptr + 2));
621 printf(" %d", DNS__16BIT(aptr + 4));
623 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
624 if (status != ARES_SUCCESS)
626 printf("\t%s.", name);
627 ares_free_string(name);
632 printf("\t%d", DNS__16BIT(aptr)); /* order */
633 printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */
636 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
637 if (status != ARES_SUCCESS)
639 printf("\t\t\t\t\t\t%s\n", name);
640 ares_free_string(name);
643 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
644 if (status != ARES_SUCCESS)
646 printf("\t\t\t\t\t\t%s\n", name);
647 ares_free_string(name);
650 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
651 if (status != ARES_SUCCESS)
653 printf("\t\t\t\t\t\t%s\n", name);
654 ares_free_string(name);
657 status = ares_expand_string(p, abuf, alen, (unsigned char **)&name, &len);
658 if (status != ARES_SUCCESS)
660 printf("\t\t\t\t\t\t%s", name);
661 ares_free_string(name);
666 printf("\t[Unknown RR; cannot parse]");
674 static const char *type_name(int type)
678 for (i = 0; i < ntypes; i++)
680 if (types[i].value == type)
681 return types[i].name;
686 static const char *class_name(int dnsclass)
690 for (i = 0; i < nclasses; i++)
692 if (classes[i].value == dnsclass)
693 return classes[i].name;
698 static void usage(void)
700 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
701 "[-t type] [-p port] name ...\n");