/[resiprocate]/main/contrib/ares/adig.c
ViewVC logotype

Contents of /main/contrib/ares/adig.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5295 - (show annotations) (download)
Mon Aug 22 00:30:05 2005 UTC (14 years, 2 months ago) by jason
File MIME type: text/plain
File size: 18967 byte(s)
merged 5270:HEAD from b-directory-reorg
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
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.
14 */
15
16 #include <sys/types.h>
17
18 #ifdef WIN32
19 #include <winsock2.h>
20 #include <stdlib.h>
21 #include <io.h>
22 #else
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <arpa/nameser.h>
28 #include <unistd.h>
29 #include <netdb.h>
30 #endif
31
32 #include <assert.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include <errno.h>
39
40 #include "ares.h"
41 #include "ares_dns.h"
42 #include "ares_compat.h"
43
44 #if defined(WIN32) || defined(__QNX__)
45 #define strcasecmp(a,b) stricmp(a,b)
46 #define strncasecmp(a,b,c) strnicmp(a,b,c)
47 #endif
48
49
50 #ifndef INADDR_NONE
51 #define INADDR_NONE 0xffffffff
52 #endif
53
54 extern int optind;
55 extern char *optarg;
56
57 struct nv {
58 const char *name;
59 int value;
60 };
61
62 static const struct nv flags[] = {
63 { "usevc", ARES_FLAG_USEVC },
64 { "primary", ARES_FLAG_PRIMARY },
65 { "igntc", ARES_FLAG_IGNTC },
66 { "norecurse", ARES_FLAG_NORECURSE },
67 { "stayopen", ARES_FLAG_STAYOPEN },
68 { "noaliases", ARES_FLAG_NOALIASES }
69 };
70 static const int nflags = sizeof(flags) / sizeof(flags[0]);
71
72 static const struct nv classes[] = {
73 { "IN", C_IN },
74 { "CHAOS", C_CHAOS },
75 { "HS", C_HS },
76 { "ANY", C_ANY }
77 };
78 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
79
80 static const struct nv types[] = {
81 { "A", T_A },
82 { "NS", T_NS },
83 { "MD", T_MD },
84 { "MF", T_MF },
85 { "CNAME", T_CNAME },
86 { "SOA", T_SOA },
87 { "MB", T_MB },
88 { "MG", T_MG },
89 { "MR", T_MR },
90 { "NULL", T_NULL },
91 { "WKS", T_WKS },
92 { "PTR", T_PTR },
93 { "HINFO", T_HINFO },
94 { "MINFO", T_MINFO },
95 { "MX", T_MX },
96 { "TXT", T_TXT },
97 { "RP", T_RP },
98 { "AFSDB", T_AFSDB },
99 { "X25", T_X25 },
100 { "ISDN", T_ISDN },
101 { "RT", T_RT },
102 { "NSAP", T_NSAP },
103 { "NSAP_PTR", T_NSAP_PTR },
104 { "SIG", T_SIG },
105 { "KEY", T_KEY },
106 { "PX", T_PX },
107 { "GPOS", T_GPOS },
108 { "AAAA", T_AAAA },
109 { "LOC", T_LOC },
110 { "SRV", T_SRV },
111 { "AXFR", T_AXFR },
112 { "MAILB", T_MAILB },
113 { "MAILA", T_MAILA },
114 { "NAPTR", T_NAPTR },
115 { "ANY", T_ANY }
116 };
117 static const int ntypes = sizeof(types) / sizeof(types[0]);
118
119 static const char *opcodes[] = {
120 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
121 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
122 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
123 "ZONEINIT", "ZONEREF"
124 };
125
126 static const char *rcodes[] = {
127 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
128 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
129 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
130 };
131
132 static void callback(void *arg, int status, unsigned char *abuf, int alen);
133 static const unsigned char *display_question(const unsigned char *aptr,
134 const unsigned char *abuf,
135 int alen);
136 static const unsigned char *display_rr(const unsigned char *aptr,
137 const unsigned char *abuf, int alen);
138 static const char *type_name(int type);
139 static const char *class_name(int dnsclass);
140 static void usage(void);
141
142 #ifdef WIN32
143 struct option
144 {
145 const char *name;
146 int has_arg;
147 int *flag;
148 int val;
149 };
150
151 char *optarg = 0;
152 int optind = 0;
153
154 /**
155 * This is a very hacked version for WIN32 that will support only what
156 * we need. This is NOT a generic getopt_long()
157 */
158 int getopt(int argc,
159 char * argv[],
160 char *optstring )
161 {
162 static int carg = 0;
163 //static int nextchar = 0;
164 char * p;
165
166 carg++;
167 if ( carg >= argc ) return -1;
168
169 p = argv[carg];
170 //register int al = strlen(argv[carg]);
171
172 if (*p == '-' && isalnum(*(p+1)))
173 {
174 char o = *(p+1);
175 int i,l;
176
177 l = (int)strlen(optstring);
178
179 for( i = 0 ; i < l; i++)
180 {
181
182 if (optstring[i] == ':') continue;
183
184 if ( optstring[i] == o ) // match option char
185 {
186
187 if ( optstring[i+1] == ':' ) // arg option
188 {
189 optind = ++carg;
190 optarg = argv[optind];
191
192 }
193 else
194 {
195 optind = 0;
196 optarg = 0;
197 }
198 return (int)o;
199 }
200
201 }
202
203 return (int)'?';
204 }
205 return (int)'?';
206 }
207 #endif
208
209 int main(int argc, char **argv)
210 {
211 ares_channel channel;
212 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
213 int status, nfds, count;
214 struct ares_options options;
215 struct hostent *hostent;
216 fd_set read_fds, write_fds;
217 struct timeval *tvp, tv;
218 char *errmem;
219
220 #ifdef WIN32
221 WORD wVersionRequested = MAKEWORD( 2, 2 );
222 WSADATA wsaData;
223 int err;
224
225 err = WSAStartup( wVersionRequested, &wsaData );
226 if ( err != 0 )
227 {
228 // could not find a usable WinSock DLL
229 //cerr << "Could not load winsock" << endl;
230 assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
231 exit(1);
232 }
233
234 /* Confirm that the WinSock DLL supports 2.2.*/
235 /* Note that if the DLL supports versions greater */
236 /* than 2.2 in addition to 2.2, it will still return */
237 /* 2.2 in wVersion since that is the version we */
238 /* requested. */
239
240 if ( LOBYTE( wsaData.wVersion ) != 2 ||
241 HIBYTE( wsaData.wVersion ) != 2 )
242 {
243 /* Tell the user that we could not find a usable */
244 /* WinSock DLL. */
245 WSACleanup( );
246 //cerr << "Bad winsock verion" << endl;
247 assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
248 exit(1);
249 }
250 #endif
251
252 options.flags = ARES_FLAG_NOCHECKRESP;
253 options.servers = NULL;
254 options.nservers = 0;
255
256 while ((c = getopt(argc, argv, "f:s:c:t:T:U:")) != -1)
257 {
258 switch (c)
259 {
260 case 'f':
261 /* Add a flag. */
262 for (i = 0; i < nflags; i++)
263 {
264 if (strcmp(flags[i].name, optarg) == 0)
265 break;
266 }
267 if (i == nflags)
268 usage();
269 options.flags |= flags[i].value;
270 break;
271
272 case 's':
273 /* Add a server, and specify servers in the option mask. */
274 hostent = gethostbyname(optarg);
275 if (!hostent || hostent->h_addrtype != AF_INET)
276 {
277 fprintf(stderr, "adig: server %s not found.\n", optarg);
278 return 1;
279 }
280 options.servers = realloc(options.servers, (options.nservers + 1)
281 * sizeof(struct in_addr));
282 if (!options.servers)
283 {
284 fprintf(stderr, "Out of memory!\n");
285 return 1;
286 }
287 memcpy(&options.servers[options.nservers], hostent->h_addr,
288 sizeof(struct in_addr));
289 options.nservers++;
290 optmask |= ARES_OPT_SERVERS;
291 break;
292
293 case 'c':
294 /* Set the query class. */
295 for (i = 0; i < nclasses; i++)
296 {
297 if (strcasecmp(classes[i].name, optarg) == 0)
298 break;
299 }
300 if (i == nclasses)
301 usage();
302 dnsclass = classes[i].value;
303 break;
304
305 case 't':
306 /* Set the query type. */
307 for (i = 0; i < ntypes; i++)
308 {
309 if (strcasecmp(types[i].name, optarg) == 0)
310 break;
311 }
312 if (i == ntypes)
313 usage();
314 type = types[i].value;
315 break;
316
317 case 'T':
318 /* Set the TCP port number. */
319 if (!isdigit((unsigned char)*optarg))
320 usage();
321 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
322 optmask |= ARES_OPT_TCP_PORT;
323 break;
324
325 case 'U':
326 /* Set the UDP port number. */
327 if (!isdigit((unsigned char)*optarg))
328 usage();
329 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
330 optmask |= ARES_OPT_UDP_PORT;
331 break;
332 }
333 }
334 argc -= optind;
335 argv += optind;
336 if (argc == 0)
337 usage();
338
339 status = ares_init_options(&channel, &options, optmask);
340 if (status != ARES_SUCCESS)
341 {
342 fprintf(stderr, "ares_init_options: %s\n",
343 ares_strerror(status)); //, &errmem));
344 ares_free_errmem(errmem);
345 return 1;
346 }
347
348 /* Initiate the queries, one per command-line argument. If there is
349 * only one query to do, supply NULL as the callback argument;
350 * otherwise, supply the query name as an argument so we can
351 * distinguish responses for the user when printing them out.
352 */
353 if (argc == 1)
354 ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
355 else
356 {
357 for (; *argv; argv++)
358 ares_query(channel, *argv, dnsclass, type, callback, *argv);
359 }
360
361 /* Wait for all queries to complete. */
362 while (1)
363 {
364 FD_ZERO(&read_fds);
365 FD_ZERO(&write_fds);
366 nfds = ares_fds(channel, &read_fds, &write_fds);
367 if (nfds == 0)
368 break;
369 tvp = ares_timeout(channel, NULL, &tv);
370 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
371 if (count < 0 && errno != EINVAL)
372 {
373 perror("select");
374 return 1;
375 }
376 ares_process(channel, &read_fds, &write_fds);
377 }
378
379 ares_destroy(channel);
380 return 0;
381 }
382
383 static void callback(void *arg, int status, unsigned char *abuf, int alen)
384 {
385 char *name = (char *) arg, *errmem;
386 int id, qr, opcode, aa, tc, rd, ra, rcode, i;
387 unsigned int qdcount, ancount, nscount, arcount;
388 const unsigned char *aptr;
389
390 /* Display the query name if given. */
391 if (name)
392 printf("Answer for query %s:\n", name);
393
394 /* Display an error message if there was an error, but only stop if
395 * we actually didn't get an answer buffer.
396 */
397 if (status != ARES_SUCCESS)
398 {
399 printf("%s\n", ares_strerror(status));//, &errmem));
400 ares_free_errmem(errmem);
401 if (!abuf)
402 return;
403 }
404
405 /* Won't happen, but check anyway, for safety. */
406 if (alen < HFIXEDSZ)
407 return;
408
409 /* Parse the answer header. */
410 id = DNS_HEADER_QID(abuf); /* query identification number */
411 qr = DNS_HEADER_QR(abuf); /* query response */
412 opcode = DNS_HEADER_OPCODE(abuf); /* opcode */
413 aa = DNS_HEADER_AA(abuf); /* authoritative answer */
414 tc = DNS_HEADER_TC(abuf); /* truncation */
415 rd = DNS_HEADER_RD(abuf); /* recursion desired */
416 ra = DNS_HEADER_RA(abuf); /* recursion available */
417 rcode = DNS_HEADER_RCODE(abuf); /* response code */
418 qdcount = DNS_HEADER_QDCOUNT(abuf); /* question count */
419 ancount = DNS_HEADER_ANCOUNT(abuf); /* answer record count */
420 nscount = DNS_HEADER_NSCOUNT(abuf); /* name server record count */
421 arcount = DNS_HEADER_ARCOUNT(abuf); /* additional record count */
422
423 /* Display the answer header. */
424 printf("id: %d\n", id);
425 printf("flags: %s%s%s%s%s\n",
426 qr ? "qr " : "",
427 aa ? "aa " : "",
428 tc ? "tc " : "",
429 rd ? "rd " : "",
430 ra ? "ra " : "");
431 printf("opcode: %s\n", opcodes[opcode]);
432 printf("rcode: %s\n", rcodes[rcode]);
433
434 /* Display the questions. */
435 printf("Questions:\n");
436 aptr = abuf + HFIXEDSZ;
437 for (i = 0; i < (int)qdcount; i++)
438 {
439 aptr = display_question(aptr, abuf, alen);
440 if (aptr == NULL)
441 return;
442 }
443
444 /* Display the answers. */
445 printf("Answers:\n");
446 for (i = 0; i < (int)ancount; i++)
447 {
448 aptr = display_rr(aptr, abuf, alen);
449 if (aptr == NULL)
450 return;
451 }
452
453 /* Display the NS records. */
454 printf("NS records:\n");
455 for (i = 0; i < (int)nscount; i++)
456 {
457 aptr = display_rr(aptr, abuf, alen);
458 if (aptr == NULL)
459 return;
460 }
461
462 /* Display the additional records. */
463 printf("Additional records:\n");
464 for (i = 0; i < (int)arcount; i++)
465 {
466 aptr = display_rr(aptr, abuf, alen);
467 if (aptr == NULL)
468 return;
469 }
470 }
471
472 static const unsigned char *display_question(const unsigned char *aptr,
473 const unsigned char *abuf,
474 int alen)
475 {
476 char *name;
477 int type, dnsclass, status, len;
478
479 /* Parse the question name. */
480 status = ares_expand_name(aptr, abuf, alen, &name, &len);
481 if (status != ARES_SUCCESS)
482 return NULL;
483 aptr += len;
484
485 /* Make sure there's enough data after the name for the fixed part
486 * of the question.
487 */
488 if (aptr + QFIXEDSZ > abuf + alen)
489 {
490 free(name);
491 return NULL;
492 }
493
494 /* Parse the question type and class. */
495 type = DNS_QUESTION_TYPE(aptr);
496 dnsclass = DNS_QUESTION_CLASS(aptr);
497 aptr += QFIXEDSZ;
498
499 /* Display the question, in a format sort of similar to how we will
500 * display RRs.
501 */
502 printf("\t%-15s.\t", name);
503 if (dnsclass != C_IN)
504 printf("\t%s", class_name(dnsclass));
505 printf("\t%s\n", type_name(type));
506 free(name);
507 return aptr;
508 }
509
510 static const unsigned char *display_rr(const unsigned char *aptr,
511 const unsigned char *abuf, int alen)
512 {
513 const unsigned char *p;
514 char *name;
515 int type, dnsclass, ttl, dlen, status, len;
516 struct in_addr addr;
517
518 /* Parse the RR name. */
519 status = ares_expand_name(aptr, abuf, alen, &name, &len);
520 if (status != ARES_SUCCESS)
521 return NULL;
522 aptr += len;
523
524 /* Make sure there is enough data after the RR name for the fixed
525 * part of the RR.
526 */
527 if (aptr + RRFIXEDSZ > abuf + alen)
528 {
529 free(name);
530 return NULL;
531 }
532
533 /* Parse the fixed part of the RR, and advance to the RR data
534 * field. */
535 type = DNS_RR_TYPE(aptr);
536 dnsclass = DNS_RR_CLASS(aptr);
537 ttl = DNS_RR_TTL(aptr);
538 dlen = DNS_RR_LEN(aptr);
539 aptr += RRFIXEDSZ;
540 if (aptr + dlen > abuf + alen)
541 {
542 free(name);
543 return NULL;
544 }
545
546 /* Display the RR name, class, and type. */
547 printf("\t%-15s.\t%d", name, ttl);
548 if (dnsclass != C_IN)
549 printf("\t%s", class_name(dnsclass));
550 printf("\t%s", type_name(type));
551 free(name);
552
553 /* Display the RR data. Don't touch aptr. */
554 switch (type)
555 {
556 case T_CNAME:
557 case T_MB:
558 case T_MD:
559 case T_MF:
560 case T_MG:
561 case T_MR:
562 case T_NS:
563 case T_PTR:
564 /* For these types, the RR data is just a domain name. */
565 status = ares_expand_name(aptr, abuf, alen, &name, &len);
566 if (status != ARES_SUCCESS)
567 return NULL;
568 printf("\t%s.", name);
569 free(name);
570 break;
571
572 case T_HINFO:
573 /* The RR data is two length-counted character strings. */
574 p = aptr;
575 len = *p;
576 if (p + len + 1 > aptr + dlen)
577 return NULL;
578 printf("\t%.*s", len, p + 1);
579 p += len + 1;
580 len = *p;
581 if (p + len + 1 > aptr + dlen)
582 return NULL;
583 printf("\t%.*s", len, p + 1);
584 break;
585
586 case T_MINFO:
587 /* The RR data is two domain names. */
588 p = aptr;
589 status = ares_expand_name(p, abuf, alen, &name, &len);
590 if (status != ARES_SUCCESS)
591 return NULL;
592 printf("\t%s.", name);
593 free(name);
594 p += len;
595 status = ares_expand_name(p, abuf, alen, &name, &len);
596 if (status != ARES_SUCCESS)
597 return NULL;
598 printf("\t%s.", name);
599 free(name);
600 break;
601
602 case T_MX:
603 /* The RR data is two bytes giving a preference ordering, and
604 * then a domain name.
605 */
606 if (dlen < 2)
607 return NULL;
608 printf("\t%d", (aptr[0] << 8) | aptr[1]);
609 status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
610 if (status != ARES_SUCCESS)
611 return NULL;
612 printf("\t%s.", name);
613 free(name);
614 break;
615
616 case T_SOA:
617 /* The RR data is two domain names and then five four-byte
618 * numbers giving the serial number and some timeouts.
619 */
620 p = aptr;
621 status = ares_expand_name(p, abuf, alen, &name, &len);
622 if (status != ARES_SUCCESS)
623 return NULL;
624 printf("\t%s.\n", name);
625 free(name);
626 p += len;
627 status = ares_expand_name(p, abuf, alen, &name, &len);
628 if (status != ARES_SUCCESS)
629 return NULL;
630 printf("\t\t\t\t\t\t%s.\n", name);
631 free(name);
632 p += len;
633 if (p + 20 > aptr + dlen)
634 return NULL;
635 printf("\t\t\t\t\t\t( %d %d %d %d %d )",
636 (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3],
637 (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7],
638 (p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11],
639 (p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15],
640 (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]);
641 break;
642
643 case T_TXT:
644 /* The RR data is one or more length-counted character
645 * strings. */
646 p = aptr;
647 while (p < aptr + dlen)
648 {
649 len = *p;
650 if (p + len + 1 > aptr + dlen)
651 return NULL;
652 printf("\t%.*s", len, p + 1);
653 p += len + 1;
654 }
655 break;
656
657 case T_A:
658 /* The RR data is a four-byte Internet address. */
659 if (dlen != 4)
660 return NULL;
661 memcpy(&addr, aptr, sizeof(struct in_addr));
662 printf("\t%s", inet_ntoa(addr));
663 break;
664
665 case T_WKS:
666 /* Not implemented yet */
667 break;
668
669 case T_SRV:
670 /* The RR data is three two-byte numbers representing the
671 * priority, weight, and port, followed by a domain name.
672 */
673
674 printf("\t%d", DNS__16BIT(aptr));
675 printf(" %d", DNS__16BIT(aptr + 2));
676 printf(" %d", DNS__16BIT(aptr + 4));
677
678 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
679 if (status != ARES_SUCCESS)
680 return NULL;
681 printf("\t%s.", name);
682 free(name);
683 break;
684
685 case T_NAPTR:
686 /* The RR data is two two-byte numbers representing the
687 * order and preference, followed by three character strings
688 * representing flags, services, a regex, and a domain name.
689 */
690
691 printf("\t%d", DNS__16BIT(aptr));
692 printf(" %d", DNS__16BIT(aptr + 2));
693
694 p = aptr + 4;
695 len = *p;
696 if (p + len + 1 > aptr + dlen)
697 return NULL;
698 printf(" %.*s", len, p + 1);
699 p += len + 1;
700 len = *p;
701 if (p + len + 1 > aptr + dlen)
702 return NULL;
703 printf(" %.*s", len, p + 1);
704 p += len + 1;
705 len = *p;
706 if (p + len + 1 > aptr + dlen)
707 return NULL;
708 printf(" %.*s", len, p + 1);
709 p += len + 1;
710 status = ares_expand_name(p, abuf, alen, &name, &len);
711 if (status != ARES_SUCCESS)
712 return NULL;
713 printf("\t%s.", name);
714 free(name);
715 break;
716
717 default:
718 printf("\t[Unknown RR; cannot parse]");
719 }
720 printf("\n");
721
722 return aptr + dlen;
723 }
724
725 static const char *type_name(int type)
726 {
727 int i;
728
729 for (i = 0; i < ntypes; i++)
730 {
731 if (types[i].value == type)
732 return types[i].name;
733 }
734 return "(unknown)";
735 }
736
737 static const char *class_name(int dnsclass)
738 {
739 int i;
740
741 for (i = 0; i < nclasses; i++)
742 {
743 if (classes[i].value == dnsclass)
744 return classes[i].name;
745 }
746 return "(unknown)";
747 }
748
749 static void usage(void)
750 {
751 fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
752 "[-t type] [-p port] name ...\n");
753 exit(1);
754 }

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27