1 /* Copyright 1998 by the Massachusetts Institute of Technology.
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of M.I.T. not be used in
10 * advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.
12 * M.I.T. makes no representations about the suitability of
13 * this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
17 #include "ares_setup.h"
19 #ifdef HAVE_SYS_SOCKET_H
20 # include <sys/socket.h>
22 #ifdef HAVE_NETINET_IN_H
23 # include <netinet/in.h>
25 #ifdef HAVE_ARPA_INET_H
26 # include <arpa/inet.h>
31 #ifdef HAVE_ARPA_NAMESER_H
32 # include <arpa/nameser.h>
36 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
37 # include <arpa/nameser_compat.h>
49 #include "inet_ntop.h"
50 #include "inet_net_pton.h"
51 #include "ares_getopt.h"
52 #include "ares_nowarn.h"
55 # include "ares_strdup.h"
56 # define strdup(ptr) ares_strdup(ptr)
59 #ifndef HAVE_STRCASECMP
60 # include "ares_strcasecmp.h"
61 # define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
64 #ifndef HAVE_STRNCASECMP
65 # include "ares_strcasecmp.h"
66 # define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
70 #undef WIN32 /* Redefined in MingW headers */
74 # define T_SRV 33 /* Server selection */
77 # define T_NAPTR 35 /* Naming authority pointer */
80 # define T_DS 43 /* Delegation Signer (RFC4034) */
83 # define T_SSHFP 44 /* SSH Key Fingerprint (RFC4255) */
86 # define T_RRSIG 46 /* Resource Record Signature (RFC4034) */
89 # define T_NSEC 47 /* Next Secure (RFC4034) */
92 # define T_DNSKEY 48 /* DNS Public Key (RFC4034) */
100 static const struct nv flags[] = {
101 { "usevc", ARES_FLAG_USEVC },
102 { "primary", ARES_FLAG_PRIMARY },
103 { "igntc", ARES_FLAG_IGNTC },
104 { "norecurse", ARES_FLAG_NORECURSE },
105 { "stayopen", ARES_FLAG_STAYOPEN },
106 { "noaliases", ARES_FLAG_NOALIASES }
108 static const int nflags = sizeof(flags) / sizeof(flags[0]);
110 static const struct nv classes[] = {
112 { "CHAOS", C_CHAOS },
116 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
118 static const struct nv types[] = {
123 { "CNAME", T_CNAME },
131 { "HINFO", T_HINFO },
132 { "MINFO", T_MINFO },
136 { "AFSDB", T_AFSDB },
141 { "NSAP_PTR", T_NSAP_PTR },
150 { "MAILB", T_MAILB },
151 { "MAILA", T_MAILA },
152 { "NAPTR", T_NAPTR },
154 { "SSHFP", T_SSHFP },
155 { "RRSIG", T_RRSIG },
157 { "DNSKEY", T_DNSKEY },
160 static const int ntypes = sizeof(types) / sizeof(types[0]);
162 static const char *opcodes[] = {
163 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
164 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
165 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
166 "ZONEINIT", "ZONEREF"
169 static const char *rcodes[] = {
170 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
171 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
172 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
175 static void callback(void *arg, int status, int timeouts,
176 unsigned char *abuf, int alen);
177 static const unsigned char *display_question(const unsigned char *aptr,
178 const unsigned char *abuf,
180 static const unsigned char *display_rr(const unsigned char *aptr,
181 const unsigned char *abuf, int alen);
182 static const char *type_name(int type);
183 static const char *class_name(int dnsclass);
184 static void usage(void);
185 static void destroy_addr_list(struct ares_addr_node *head);
186 static void append_addr_list(struct ares_addr_node **head,
187 struct ares_addr_node *node);
189 int main(int argc, char **argv)
191 ares_channel channel;
192 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
193 int status, nfds, count;
194 struct ares_options options;
195 struct hostent *hostent;
196 fd_set read_fds, write_fds;
197 struct timeval *tvp, tv;
198 struct ares_addr_node *srvr, *servers = NULL;
201 WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
203 WSAStartup(wVersionRequested, &wsaData);
206 status = ares_library_init(ARES_LIB_INIT_ALL);
207 if (status != ARES_SUCCESS)
209 fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status));
213 options.flags = ARES_FLAG_NOCHECKRESP;
214 options.servers = NULL;
215 options.nservers = 0;
216 while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1)
228 for (i = 0; i < nflags; i++)
230 if (strcmp(flags[i].name, optarg) == 0)
234 options.flags |= flags[i].value;
240 /* User-specified name servers override default ones. */
241 srvr = malloc(sizeof(struct ares_addr_node));
244 fprintf(stderr, "Out of memory!\n");
245 destroy_addr_list(servers);
248 append_addr_list(&servers, srvr);
249 if (ares_inet_pton(AF_INET, optarg, &srvr->addr.addr4) > 0)
250 srvr->family = AF_INET;
251 else if (ares_inet_pton(AF_INET6, optarg, &srvr->addr.addr6) > 0)
252 srvr->family = AF_INET6;
255 hostent = gethostbyname(optarg);
258 fprintf(stderr, "adig: server %s not found.\n", optarg);
259 destroy_addr_list(servers);
262 switch (hostent->h_addrtype)
265 srvr->family = AF_INET;
266 memcpy(&srvr->addr.addr4, hostent->h_addr,
267 sizeof(srvr->addr.addr4));
270 srvr->family = AF_INET6;
271 memcpy(&srvr->addr.addr6, hostent->h_addr,
272 sizeof(srvr->addr.addr6));
276 "adig: server %s unsupported address family.\n", optarg);
277 destroy_addr_list(servers);
281 /* Notice that calling ares_init_options() without servers in the
282 * options struct and with ARES_OPT_SERVERS set simultaneously in
283 * the options mask, results in an initialization with no servers.
284 * When alternative name servers have been specified these are set
285 * later calling ares_set_servers() overriding any existing server
286 * configuration. To prevent initial configuration with default
287 * servers that will be discarded later, ARES_OPT_SERVERS is set.
288 * If this flag is not set here the result shall be the same but
289 * ares_init_options() will do needless work. */
290 optmask |= ARES_OPT_SERVERS;
294 /* Set the query class. */
295 for (i = 0; i < nclasses; i++)
297 if (strcasecmp(classes[i].name, optarg) == 0)
301 dnsclass = classes[i].value;
307 /* Set the query type. */
308 for (i = 0; i < ntypes; i++)
310 if (strcasecmp(types[i].name, optarg) == 0)
314 type = types[i].value;
320 /* Set the TCP port number. */
321 if (!ISDIGIT(*optarg))
323 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
324 optmask |= ARES_OPT_TCP_PORT;
328 /* Set the UDP port number. */
329 if (!ISDIGIT(*optarg))
331 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
332 optmask |= ARES_OPT_UDP_PORT;
341 status = ares_init_options(&channel, &options, optmask);
343 if (status != ARES_SUCCESS)
345 fprintf(stderr, "ares_init_options: %s\n",
346 ares_strerror(status));
352 status = ares_set_servers(channel, servers);
353 destroy_addr_list(servers);
354 if (status != ARES_SUCCESS)
356 fprintf(stderr, "ares_init_options: %s\n",
357 ares_strerror(status));
362 /* Initiate the queries, one per command-line argument. If there is
363 * only one query to do, supply NULL as the callback argument;
364 * otherwise, supply the query name as an argument so we can
365 * distinguish responses for the user when printing them out.
368 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
371 for (; *argv; argv++)
372 ares_query(channel, *argv, dnsclass, type, callback, *argv);
375 /* Wait for all queries to complete. */
380 nfds = ares_fds(channel, &read_fds, &write_fds);
383 tvp = ares_timeout(channel, NULL, &tv);
384 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
385 if (count < 0 && (status = SOCKERRNO) != EINVAL)
387 printf("select fail: %d", status);
390 ares_process(channel, &read_fds, &write_fds);
393 ares_destroy(channel);
395 ares_library_cleanup();
404 static void callback(void *arg, int status, int timeouts,
405 unsigned char *abuf, int alen)
407 char *name = (char *) arg;
408 int id, qr, opcode, aa, tc, rd, ra, rcode;
409 unsigned int qdcount, ancount, nscount, arcount, i;
410 const unsigned char *aptr;
414 /* Display the query name if given. */
416 printf("Answer for query %s:\n", name);
418 /* Display an error message if there was an error, but only stop if
419 * we actually didn't get an answer buffer.
421 if (status != ARES_SUCCESS)
423 printf("%s\n", ares_strerror(status));
428 /* Won't happen, but check anyway, for safety. */
432 /* Parse the answer header. */
433 id = DNS_HEADER_QID(abuf);
434 qr = DNS_HEADER_QR(abuf);
435 opcode = DNS_HEADER_OPCODE(abuf);
436 aa = DNS_HEADER_AA(abuf);
437 tc = DNS_HEADER_TC(abuf);
438 rd = DNS_HEADER_RD(abuf);
439 ra = DNS_HEADER_RA(abuf);
440 rcode = DNS_HEADER_RCODE(abuf);
441 qdcount = DNS_HEADER_QDCOUNT(abuf);
442 ancount = DNS_HEADER_ANCOUNT(abuf);
443 nscount = DNS_HEADER_NSCOUNT(abuf);
444 arcount = DNS_HEADER_ARCOUNT(abuf);
446 /* Display the answer header. */
447 printf("id: %d\n", id);
448 printf("flags: %s%s%s%s%s\n",
454 printf("opcode: %s\n", opcodes[opcode]);
455 printf("rcode: %s\n", rcodes[rcode]);
457 /* Display the questions. */
458 printf("Questions:\n");
459 aptr = abuf + HFIXEDSZ;
460 for (i = 0; i < qdcount; i++)
462 aptr = display_question(aptr, abuf, alen);
467 /* Display the answers. */
468 printf("Answers:\n");
469 for (i = 0; i < ancount; i++)
471 aptr = display_rr(aptr, abuf, alen);
476 /* Display the NS records. */
477 printf("NS records:\n");
478 for (i = 0; i < nscount; i++)
480 aptr = display_rr(aptr, abuf, alen);
485 /* Display the additional records. */
486 printf("Additional records:\n");
487 for (i = 0; i < arcount; i++)
489 aptr = display_rr(aptr, abuf, alen);
495 static const unsigned char *display_question(const unsigned char *aptr,
496 const unsigned char *abuf,
500 int type, dnsclass, status;
503 /* Parse the question name. */
504 status = ares_expand_name(aptr, abuf, alen, &name, &len);
505 if (status != ARES_SUCCESS)
509 /* Make sure there's enough data after the name for the fixed part
512 if (aptr + QFIXEDSZ > abuf + alen)
514 ares_free_string(name);
518 /* Parse the question type and class. */
519 type = DNS_QUESTION_TYPE(aptr);
520 dnsclass = DNS_QUESTION_CLASS(aptr);
523 /* Display the question, in a format sort of similar to how we will
526 printf("\t%-15s.\t", name);
527 if (dnsclass != C_IN)
528 printf("\t%s", class_name(dnsclass));
529 printf("\t%s\n", type_name(type));
530 ares_free_string(name);
534 static const unsigned char *display_rr(const unsigned char *aptr,
535 const unsigned char *abuf, int alen)
537 const unsigned char *p;
538 int type, dnsclass, ttl, dlen, status;
542 unsigned char * as_uchar;
546 /* Parse the RR name. */
547 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
548 if (status != ARES_SUCCESS)
552 /* Make sure there is enough data after the RR name for the fixed
555 if (aptr + RRFIXEDSZ > abuf + alen)
557 ares_free_string(name.as_char);
561 /* Parse the fixed part of the RR, and advance to the RR data
563 type = DNS_RR_TYPE(aptr);
564 dnsclass = DNS_RR_CLASS(aptr);
565 ttl = DNS_RR_TTL(aptr);
566 dlen = DNS_RR_LEN(aptr);
568 if (aptr + dlen > abuf + alen)
570 ares_free_string(name.as_char);
574 /* Display the RR name, class, and type. */
575 printf("\t%-15s.\t%d", name.as_char, ttl);
576 if (dnsclass != C_IN)
577 printf("\t%s", class_name(dnsclass));
578 printf("\t%s", type_name(type));
579 ares_free_string(name.as_char);
581 /* Display the RR data. Don't touch aptr. */
592 /* For these types, the RR data is just a domain name. */
593 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
594 if (status != ARES_SUCCESS)
596 printf("\t%s.", name.as_char);
597 ares_free_string(name.as_char);
601 /* The RR data is two length-counted character strings. */
604 if (p + len + 1 > aptr + dlen)
606 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
607 if (status != ARES_SUCCESS)
609 printf("\t%s", name.as_char);
610 ares_free_string(name.as_char);
613 if (p + len + 1 > aptr + dlen)
615 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
616 if (status != ARES_SUCCESS)
618 printf("\t%s", name.as_char);
619 ares_free_string(name.as_char);
623 /* The RR data is two domain names. */
625 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
626 if (status != ARES_SUCCESS)
628 printf("\t%s.", name.as_char);
629 ares_free_string(name.as_char);
631 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
632 if (status != ARES_SUCCESS)
634 printf("\t%s.", name.as_char);
635 ares_free_string(name.as_char);
639 /* The RR data is two bytes giving a preference ordering, and
640 * then a domain name.
644 printf("\t%d", (int)DNS__16BIT(aptr));
645 status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
646 if (status != ARES_SUCCESS)
648 printf("\t%s.", name.as_char);
649 ares_free_string(name.as_char);
653 /* The RR data is two domain names and then five four-byte
654 * numbers giving the serial number and some timeouts.
657 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
658 if (status != ARES_SUCCESS)
660 printf("\t%s.\n", name.as_char);
661 ares_free_string(name.as_char);
663 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
664 if (status != ARES_SUCCESS)
666 printf("\t\t\t\t\t\t%s.\n", name.as_char);
667 ares_free_string(name.as_char);
669 if (p + 20 > aptr + dlen)
671 printf("\t\t\t\t\t\t( %u %u %u %u %u )",
672 DNS__32BIT(p), DNS__32BIT(p+4),
673 DNS__32BIT(p+8), DNS__32BIT(p+12),
678 /* The RR data is one or more length-counted character
681 while (p < aptr + dlen)
684 if (p + len + 1 > aptr + dlen)
686 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
687 if (status != ARES_SUCCESS)
689 printf("\t%s", name.as_char);
690 ares_free_string(name.as_char);
696 /* The RR data is a four-byte Internet address. */
699 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
703 /* The RR data is a 16-byte IPv6 address. */
706 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
710 /* Not implemented yet */
714 /* The RR data is three two-byte numbers representing the
715 * priority, weight, and port, followed by a domain name.
718 printf("\t%d", (int)DNS__16BIT(aptr));
719 printf(" %d", (int)DNS__16BIT(aptr + 2));
720 printf(" %d", (int)DNS__16BIT(aptr + 4));
722 status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
723 if (status != ARES_SUCCESS)
725 printf("\t%s.", name.as_char);
726 ares_free_string(name.as_char);
731 printf("\t%d", (int)DNS__16BIT(aptr)); /* order */
732 printf(" %d\n", (int)DNS__16BIT(aptr + 2)); /* preference */
735 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
736 if (status != ARES_SUCCESS)
738 printf("\t\t\t\t\t\t%s\n", name.as_char);
739 ares_free_string(name.as_char);
742 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
743 if (status != ARES_SUCCESS)
745 printf("\t\t\t\t\t\t%s\n", name.as_char);
746 ares_free_string(name.as_char);
749 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
750 if (status != ARES_SUCCESS)
752 printf("\t\t\t\t\t\t%s\n", name.as_char);
753 ares_free_string(name.as_char);
756 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
757 if (status != ARES_SUCCESS)
759 printf("\t\t\t\t\t\t%s", name.as_char);
760 ares_free_string(name.as_char);
768 printf("\t[RR type parsing unavailable]");
772 printf("\t[Unknown RR; cannot parse]");
780 static const char *type_name(int type)
784 for (i = 0; i < ntypes; i++)
786 if (types[i].value == type)
787 return types[i].name;
792 static const char *class_name(int dnsclass)
796 for (i = 0; i < nclasses; i++)
798 if (classes[i].value == dnsclass)
799 return classes[i].name;
804 static void usage(void)
806 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
807 "[-t type] [-p port] name ...\n");
811 static void destroy_addr_list(struct ares_addr_node *head)
815 struct ares_addr_node *detached = head;
821 static void append_addr_list(struct ares_addr_node **head,
822 struct ares_addr_node *node)
824 struct ares_addr_node *last;