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.
16 static const char rcsid[] = "$Id: adig.c,v 1.6 1999/10/23 19:28:12 danw Exp $";
18 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <arpa/nameser.h>
35 #define INADDR_NONE 0xffffffff
46 static const struct nv flags[] = {
47 { "usevc", ARES_FLAG_USEVC },
48 { "primary", ARES_FLAG_PRIMARY },
49 { "igntc", ARES_FLAG_IGNTC },
50 { "norecurse", ARES_FLAG_NORECURSE },
51 { "stayopen", ARES_FLAG_STAYOPEN },
52 { "noaliases", ARES_FLAG_NOALIASES }
54 static const int nflags = sizeof(flags) / sizeof(flags[0]);
56 static const struct nv classes[] = {
62 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
64 static const struct nv types[] = {
87 { "NSAP_PTR", T_NSAP_PTR },
99 static const int ntypes = sizeof(types) / sizeof(types[0]);
101 static const char *opcodes[] = {
102 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
103 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
104 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
105 "ZONEINIT", "ZONEREF"
108 static const char *rcodes[] = {
109 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
110 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
111 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
114 static void callback(void *arg, int status, unsigned char *abuf, int alen);
115 static const unsigned char *display_question(const unsigned char *aptr,
116 const unsigned char *abuf,
118 static const unsigned char *display_rr(const unsigned char *aptr,
119 const unsigned char *abuf, int alen);
120 static const char *type_name(int type);
121 static const char *class_name(int class);
122 static void usage(void);
124 int main(int argc, char **argv)
126 ares_channel channel;
127 int c, i, optmask = ARES_OPT_FLAGS, class = C_IN, type = T_A;
128 int status, nfds, count;
129 struct ares_options options;
130 struct hostent *hostent;
131 fd_set read_fds, write_fds;
132 struct timeval *tvp, tv;
135 options.flags = ARES_FLAG_NOCHECKRESP;
136 options.servers = NULL;
137 options.nservers = 0;
138 while ((c = getopt(argc, argv, "f:s:c:t:T:U:")) != -1)
144 for (i = 0; i < nflags; i++)
146 if (strcmp(flags[i].name, optarg) == 0)
151 options.flags |= flags[i].value;
155 /* Add a server, and specify servers in the option mask. */
156 hostent = gethostbyname(optarg);
157 if (!hostent || hostent->h_addrtype != AF_INET)
159 fprintf(stderr, "adig: server %s not found.\n", optarg);
162 options.servers = realloc(options.servers, (options.nservers + 1)
163 * sizeof(struct in_addr));
164 if (!options.servers)
166 fprintf(stderr, "Out of memory!\n");
169 memcpy(&options.servers[options.nservers], hostent->h_addr,
170 sizeof(struct in_addr));
172 optmask |= ARES_OPT_SERVERS;
176 /* Set the query class. */
177 for (i = 0; i < nclasses; i++)
179 if (strcasecmp(classes[i].name, optarg) == 0)
184 class = classes[i].value;
188 /* Set the query type. */
189 for (i = 0; i < ntypes; i++)
191 if (strcasecmp(types[i].name, optarg) == 0)
196 type = types[i].value;
200 /* Set the TCP port number. */
201 if (!isdigit((unsigned char)*optarg))
203 options.tcp_port = strtol(optarg, NULL, 0);
204 optmask |= ARES_OPT_TCP_PORT;
208 /* Set the UDP port number. */
209 if (!isdigit((unsigned char)*optarg))
211 options.udp_port = strtol(optarg, NULL, 0);
212 optmask |= ARES_OPT_UDP_PORT;
221 status = ares_init_options(&channel, &options, optmask);
222 if (status != ARES_SUCCESS)
224 fprintf(stderr, "ares_init_options: %s\n",
225 ares_strerror(status, &errmem));
226 ares_free_errmem(errmem);
230 /* Initiate the queries, one per command-line argument. If there is
231 * only one query to do, supply NULL as the callback argument;
232 * otherwise, supply the query name as an argument so we can
233 * distinguish responses for the user when printing them out.
236 ares_query(channel, *argv, class, type, callback, (char *) NULL);
239 for (; *argv; argv++)
240 ares_query(channel, *argv, class, type, callback, *argv);
243 /* Wait for all queries to complete. */
248 nfds = ares_fds(channel, &read_fds, &write_fds);
251 tvp = ares_timeout(channel, NULL, &tv);
252 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
253 if (count < 0 && errno != EINVAL)
258 ares_process(channel, &read_fds, &write_fds);
261 ares_destroy(channel);
265 static void callback(void *arg, int status, unsigned char *abuf, int alen)
267 char *name = (char *) arg, *errmem;
268 int id, qr, opcode, aa, tc, rd, ra, rcode, i;
269 unsigned int qdcount, ancount, nscount, arcount;
270 const unsigned char *aptr;
272 /* Display the query name if given. */
274 printf("Answer for query %s:\n", name);
276 /* Display an error message if there was an error, but only stop if
277 * we actually didn't get an answer buffer.
279 if (status != ARES_SUCCESS)
281 printf("%s\n", ares_strerror(status, &errmem));
282 ares_free_errmem(errmem);
287 /* Won't happen, but check anyway, for safety. */
291 /* Parse the answer header. */
292 id = DNS_HEADER_QID(abuf);
293 qr = DNS_HEADER_QR(abuf);
294 opcode = DNS_HEADER_OPCODE(abuf);
295 aa = DNS_HEADER_AA(abuf);
296 tc = DNS_HEADER_TC(abuf);
297 rd = DNS_HEADER_RD(abuf);
298 ra = DNS_HEADER_RA(abuf);
299 rcode = DNS_HEADER_RCODE(abuf);
300 qdcount = DNS_HEADER_QDCOUNT(abuf);
301 ancount = DNS_HEADER_ANCOUNT(abuf);
302 nscount = DNS_HEADER_NSCOUNT(abuf);
303 arcount = DNS_HEADER_ARCOUNT(abuf);
305 /* Display the answer header. */
306 printf("id: %d\n", id);
307 printf("flags: %s%s%s%s%s\n",
313 printf("opcode: %s\n", opcodes[opcode]);
314 printf("rcode: %s\n", rcodes[rcode]);
316 /* Display the questions. */
317 printf("Questions:\n");
318 aptr = abuf + HFIXEDSZ;
319 for (i = 0; i < qdcount; i++)
321 aptr = display_question(aptr, abuf, alen);
326 /* Display the answers. */
327 printf("Answers:\n");
328 for (i = 0; i < ancount; i++)
330 aptr = display_rr(aptr, abuf, alen);
335 /* Display the NS records. */
336 printf("NS records:\n");
337 for (i = 0; i < nscount; i++)
339 aptr = display_rr(aptr, abuf, alen);
344 /* Display the additional records. */
345 printf("Additional records:\n");
346 for (i = 0; i < arcount; i++)
348 aptr = display_rr(aptr, abuf, alen);
354 static const unsigned char *display_question(const unsigned char *aptr,
355 const unsigned char *abuf,
359 int type, class, status, len;
361 /* Parse the question name. */
362 status = ares_expand_name(aptr, abuf, alen, &name, &len);
363 if (status != ARES_SUCCESS)
367 /* Make sure there's enough data after the name for the fixed part
370 if (aptr + QFIXEDSZ > abuf + alen)
376 /* Parse the question type and class. */
377 type = DNS_QUESTION_TYPE(aptr);
378 class = DNS_QUESTION_CLASS(aptr);
381 /* Display the question, in a format sort of similar to how we will
384 printf("\t%-15s.\t", name);
386 printf("\t%s", class_name(class));
387 printf("\t%s\n", type_name(type));
392 static const unsigned char *display_rr(const unsigned char *aptr,
393 const unsigned char *abuf, int alen)
395 const unsigned char *p;
397 int type, class, ttl, dlen, status, len;
400 /* Parse the RR name. */
401 status = ares_expand_name(aptr, abuf, alen, &name, &len);
402 if (status != ARES_SUCCESS)
406 /* Make sure there is enough data after the RR name for the fixed
409 if (aptr + RRFIXEDSZ > abuf + alen)
415 /* Parse the fixed part of the RR, and advance to the RR data
417 type = DNS_RR_TYPE(aptr);
418 class = DNS_RR_CLASS(aptr);
419 ttl = DNS_RR_TTL(aptr);
420 dlen = DNS_RR_LEN(aptr);
422 if (aptr + dlen > abuf + alen)
428 /* Display the RR name, class, and type. */
429 printf("\t%-15s.\t%d", name, ttl);
431 printf("\t%s", class_name(class));
432 printf("\t%s", type_name(type));
435 /* Display the RR data. Don't touch aptr. */
446 /* For these types, the RR data is just a domain name. */
447 status = ares_expand_name(aptr, abuf, alen, &name, &len);
448 if (status != ARES_SUCCESS)
450 printf("\t%s.", name);
455 /* The RR data is two length-counted character strings. */
458 if (p + len + 1 > aptr + dlen)
460 printf("\t%.*s", len, p + 1);
463 if (p + len + 1 > aptr + dlen)
465 printf("\t%.*s", len, p + 1);
469 /* The RR data is two domain names. */
471 status = ares_expand_name(p, abuf, alen, &name, &len);
472 if (status != ARES_SUCCESS)
474 printf("\t%s.", name);
477 status = ares_expand_name(p, abuf, alen, &name, &len);
478 if (status != ARES_SUCCESS)
480 printf("\t%s.", name);
485 /* The RR data is two bytes giving a preference ordering, and
486 * then a domain name.
490 printf("\t%d", (aptr[0] << 8) | aptr[1]);
491 status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
492 if (status != ARES_SUCCESS)
494 printf("\t%s.", name);
499 /* The RR data is two domain names and then five four-byte
500 * numbers giving the serial number and some timeouts.
503 status = ares_expand_name(p, abuf, alen, &name, &len);
504 if (status != ARES_SUCCESS)
506 printf("\t%s.\n", name);
509 status = ares_expand_name(p, abuf, alen, &name, &len);
510 if (status != ARES_SUCCESS)
512 printf("\t\t\t\t\t\t%s.\n", name);
515 if (p + 20 > aptr + dlen)
517 printf("\t\t\t\t\t\t( %d %d %d %d %d )",
518 (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3],
519 (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7],
520 (p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11],
521 (p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15],
522 (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]);
526 /* The RR data is one or more length-counted character
529 while (p < aptr + dlen)
532 if (p + len + 1 > aptr + dlen)
534 printf("\t%.*s", len, p + 1);
540 /* The RR data is a four-byte Internet address. */
543 memcpy(&addr, aptr, sizeof(struct in_addr));
544 printf("\t%s", inet_ntoa(addr));
548 /* Not implemented yet */
556 static const char *type_name(int type)
560 for (i = 0; i < ntypes; i++)
562 if (types[i].value == type)
563 return types[i].name;
568 static const char *class_name(int class)
572 for (i = 0; i < nclasses; i++)
574 if (classes[i].value == class)
575 return classes[i].name;
580 static void usage(void)
582 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
583 "[-t type] [-p port] name ...\n");