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>
42 #include "inet_ntop.h"
45 #undef WIN32 /* Redefined in MingW headers */
49 #define INADDR_NONE 0xffffffff
52 /* Mac OS X portability check */
54 #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 },
121 static const int ntypes = sizeof(types) / sizeof(types[0]);
123 static const char *opcodes[] = {
124 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
125 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
126 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
127 "ZONEINIT", "ZONEREF"
130 static const char *rcodes[] = {
131 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
132 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
133 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
136 static void callback(void *arg, int status, unsigned char *abuf, int alen);
137 static const unsigned char *display_question(const unsigned char *aptr,
138 const unsigned char *abuf,
140 static const unsigned char *display_rr(const unsigned char *aptr,
141 const unsigned char *abuf, int alen);
142 static const char *type_name(int type);
143 static const char *class_name(int dnsclass);
144 static void usage(void);
146 int main(int argc, char **argv)
148 ares_channel channel;
149 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
150 int status, nfds, count;
151 struct ares_options options;
152 struct hostent *hostent;
153 fd_set read_fds, write_fds;
154 struct timeval *tvp, tv;
157 WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
159 WSAStartup(wVersionRequested, &wsaData);
162 options.flags = ARES_FLAG_NOCHECKRESP;
163 options.servers = NULL;
164 options.nservers = 0;
165 while ((c = getopt(argc, argv, "f:s:c:t:T:U:")) != -1)
171 for (i = 0; i < nflags; i++)
173 if (strcmp(flags[i].name, optarg) == 0)
178 options.flags |= flags[i].value;
182 /* Add a server, and specify servers in the option mask. */
183 hostent = gethostbyname(optarg);
184 if (!hostent || hostent->h_addrtype != AF_INET)
186 fprintf(stderr, "adig: server %s not found.\n", optarg);
189 options.servers = realloc(options.servers, (options.nservers + 1)
190 * sizeof(struct in_addr));
191 if (!options.servers)
193 fprintf(stderr, "Out of memory!\n");
196 memcpy(&options.servers[options.nservers], hostent->h_addr,
197 sizeof(struct in_addr));
199 optmask |= ARES_OPT_SERVERS;
203 /* Set the query class. */
204 for (i = 0; i < nclasses; i++)
206 if (strcasecmp(classes[i].name, optarg) == 0)
211 dnsclass = classes[i].value;
215 /* Set the query type. */
216 for (i = 0; i < ntypes; i++)
218 if (strcasecmp(types[i].name, optarg) == 0)
223 type = types[i].value;
227 /* Set the TCP port number. */
228 if (!ISDIGIT(*optarg))
230 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
231 optmask |= ARES_OPT_TCP_PORT;
235 /* Set the UDP port number. */
236 if (!ISDIGIT(*optarg))
238 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
239 optmask |= ARES_OPT_UDP_PORT;
248 status = ares_init_options(&channel, &options, optmask);
250 if (status != ARES_SUCCESS)
252 fprintf(stderr, "ares_init_options: %s\n",
253 ares_strerror(status));
257 /* Initiate the queries, one per command-line argument. If there is
258 * only one query to do, supply NULL as the callback argument;
259 * otherwise, supply the query name as an argument so we can
260 * distinguish responses for the user when printing them out.
263 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
266 for (; *argv; argv++)
267 ares_query(channel, *argv, dnsclass, type, callback, *argv);
270 /* Wait for all queries to complete. */
275 nfds = ares_fds(channel, &read_fds, &write_fds);
278 tvp = ares_timeout(channel, NULL, &tv);
279 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
280 if (count < 0 && errno != EINVAL)
285 ares_process(channel, &read_fds, &write_fds);
288 ares_destroy(channel);
292 static void callback(void *arg, int status, unsigned char *abuf, int alen)
294 char *name = (char *) arg;
295 int id, qr, opcode, aa, tc, rd, ra, rcode;
296 unsigned int qdcount, ancount, nscount, arcount, i;
297 const unsigned char *aptr;
299 /* Display the query name if given. */
301 printf("Answer for query %s:\n", name);
303 /* Display an error message if there was an error, but only stop if
304 * we actually didn't get an answer buffer.
306 if (status != ARES_SUCCESS)
308 printf("%s\n", ares_strerror(status));
313 /* Won't happen, but check anyway, for safety. */
317 /* Parse the answer header. */
318 id = DNS_HEADER_QID(abuf);
319 qr = DNS_HEADER_QR(abuf);
320 opcode = DNS_HEADER_OPCODE(abuf);
321 aa = DNS_HEADER_AA(abuf);
322 tc = DNS_HEADER_TC(abuf);
323 rd = DNS_HEADER_RD(abuf);
324 ra = DNS_HEADER_RA(abuf);
325 rcode = DNS_HEADER_RCODE(abuf);
326 qdcount = DNS_HEADER_QDCOUNT(abuf);
327 ancount = DNS_HEADER_ANCOUNT(abuf);
328 nscount = DNS_HEADER_NSCOUNT(abuf);
329 arcount = DNS_HEADER_ARCOUNT(abuf);
331 /* Display the answer header. */
332 printf("id: %d\n", id);
333 printf("flags: %s%s%s%s%s\n",
339 printf("opcode: %s\n", opcodes[opcode]);
340 printf("rcode: %s\n", rcodes[rcode]);
342 /* Display the questions. */
343 printf("Questions:\n");
344 aptr = abuf + HFIXEDSZ;
345 for (i = 0; i < qdcount; i++)
347 aptr = display_question(aptr, abuf, alen);
352 /* Display the answers. */
353 printf("Answers:\n");
354 for (i = 0; i < ancount; i++)
356 aptr = display_rr(aptr, abuf, alen);
361 /* Display the NS records. */
362 printf("NS records:\n");
363 for (i = 0; i < nscount; i++)
365 aptr = display_rr(aptr, abuf, alen);
370 /* Display the additional records. */
371 printf("Additional records:\n");
372 for (i = 0; i < arcount; i++)
374 aptr = display_rr(aptr, abuf, alen);
380 static const unsigned char *display_question(const unsigned char *aptr,
381 const unsigned char *abuf,
385 int type, dnsclass, status;
388 /* Parse the question name. */
389 status = ares_expand_name(aptr, abuf, alen, &name, &len);
390 if (status != ARES_SUCCESS)
394 /* Make sure there's enough data after the name for the fixed part
397 if (aptr + QFIXEDSZ > abuf + alen)
399 ares_free_string(name);
403 /* Parse the question type and class. */
404 type = DNS_QUESTION_TYPE(aptr);
405 dnsclass = DNS_QUESTION_CLASS(aptr);
408 /* Display the question, in a format sort of similar to how we will
411 printf("\t%-15s.\t", name);
412 if (dnsclass != C_IN)
413 printf("\t%s", class_name(dnsclass));
414 printf("\t%s\n", type_name(type));
415 ares_free_string(name);
419 static const unsigned char *display_rr(const unsigned char *aptr,
420 const unsigned char *abuf, int alen)
422 const unsigned char *p;
424 int type, dnsclass, ttl, dlen, status;
428 /* Parse the RR name. */
429 status = ares_expand_name(aptr, abuf, alen, &name, &len);
430 if (status != ARES_SUCCESS)
434 /* Make sure there is enough data after the RR name for the fixed
437 if (aptr + RRFIXEDSZ > abuf + alen)
439 ares_free_string(name);
443 /* Parse the fixed part of the RR, and advance to the RR data
445 type = DNS_RR_TYPE(aptr);
446 dnsclass = DNS_RR_CLASS(aptr);
447 ttl = DNS_RR_TTL(aptr);
448 dlen = DNS_RR_LEN(aptr);
450 if (aptr + dlen > abuf + alen)
452 ares_free_string(name);
456 /* Display the RR name, class, and type. */
457 printf("\t%-15s.\t%d", name, ttl);
458 if (dnsclass != C_IN)
459 printf("\t%s", class_name(dnsclass));
460 printf("\t%s", type_name(type));
461 ares_free_string(name);
463 /* Display the RR data. Don't touch aptr. */
474 /* For these types, the RR data is just a domain name. */
475 status = ares_expand_name(aptr, abuf, alen, &name, &len);
476 if (status != ARES_SUCCESS)
478 printf("\t%s.", name);
479 ares_free_string(name);
483 /* The RR data is two length-counted character strings. */
486 if (p + len + 1 > aptr + dlen)
488 printf("\t%.*s", (int)len, p + 1);
491 if (p + len + 1 > aptr + dlen)
493 printf("\t%.*s", (int)len, p + 1);
497 /* The RR data is two domain names. */
499 status = ares_expand_name(p, abuf, alen, &name, &len);
500 if (status != ARES_SUCCESS)
502 printf("\t%s.", name);
503 ares_free_string(name);
505 status = ares_expand_name(p, abuf, alen, &name, &len);
506 if (status != ARES_SUCCESS)
508 printf("\t%s.", name);
509 ares_free_string(name);
513 /* The RR data is two bytes giving a preference ordering, and
514 * then a domain name.
518 printf("\t%d", DNS__16BIT(aptr));
519 status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
520 if (status != ARES_SUCCESS)
522 printf("\t%s.", name);
523 ares_free_string(name);
527 /* The RR data is two domain names and then five four-byte
528 * numbers giving the serial number and some timeouts.
531 status = ares_expand_name(p, abuf, alen, &name, &len);
532 if (status != ARES_SUCCESS)
534 printf("\t%s.\n", name);
535 ares_free_string(name);
537 status = ares_expand_name(p, abuf, alen, &name, &len);
538 if (status != ARES_SUCCESS)
540 printf("\t\t\t\t\t\t%s.\n", name);
541 ares_free_string(name);
543 if (p + 20 > aptr + dlen)
545 printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
546 DNS__32BIT(p), DNS__32BIT(p+4), DNS__32BIT(p+8),
547 DNS__32BIT(p+12), DNS__32BIT(p+16));
551 /* The RR data is one or more length-counted character
554 while (p < aptr + dlen)
557 if (p + len + 1 > aptr + dlen)
559 printf("\t%.*s", (int)len, p + 1);
565 /* The RR data is a four-byte Internet address. */
568 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
572 /* The RR data is a 16-byte IPv6 address. */
575 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
579 /* Not implemented yet */
583 /* The RR data is three two-byte numbers representing the
584 * priority, weight, and port, followed by a domain name.
587 printf("\t%d", DNS__16BIT(aptr));
588 printf(" %d", DNS__16BIT(aptr + 2));
589 printf(" %d", DNS__16BIT(aptr + 4));
591 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
592 if (status != ARES_SUCCESS)
594 printf("\t%s.", name);
595 ares_free_string(name);
599 printf("\t[Unknown RR; cannot parse]");
607 static const char *type_name(int type)
611 for (i = 0; i < ntypes; i++)
613 if (types[i].value == type)
614 return types[i].name;
619 static const char *class_name(int dnsclass)
623 for (i = 0; i < nclasses; i++)
625 if (classes[i].value == dnsclass)
626 return classes[i].name;
631 static void usage(void)
633 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
634 "[-t type] [-p port] name ...\n");