BSD 4_4_Lite1 release
[unix-history] / usr / src / contrib / bind-4.9.2 / tools / host.c
CommitLineData
ad787160
C
1/*
2 * ++Copyright++ 1986
3 * -
ed554bc5
C
4 * Copyright (c) 1986
5 * The Regents of the University of California. All rights reserved.
ad787160
C
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 * -
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 * -
53 * --Copyright--
54 */
55
56#ifndef lint
57char copyright[] =
58"@(#) Copyright (c) 1986 Regents of the University of California.\n\
59 portions Copyright (c) 1993 Digital Equipment Corporation\n\
60 All rights reserved.\n";
61#endif /* not lint */
62
63/*
64 * Actually, this program is from Rutgers University, however it is
65 * based on nslookup and other pieces of named tools, so it needs
66 * that copyright notice.
67 */
68
69#ifndef lint
ed554bc5 70static char rcsid[] = "$Id: host.c,v 4.9.1.6 1993/12/06 00:43:14 vixie Exp $";
ad787160
C
71#endif /* not lint */
72
73#include <sys/types.h>
74#include <sys/param.h>
75#include <sys/socket.h>
76
77#include <netinet/in.h>
78#include <arpa/inet.h>
79#include <arpa/nameser.h>
80
81#include <stdio.h>
82#include <netdb.h>
83#include <resolv.h>
ad787160
C
84#include <ctype.h>
85
ed554bc5
C
86#include "../conf/portability.h"
87
ad787160
C
88extern int h_errno;
89
90#define NUMMX 50
91
92#define SUCCESS 0
93#define TIME_OUT -1
94#define NO_INFO -2
95#define ERROR -3
96#define NONAUTH -4
97
98#define NAME_LEN 256
99
100#ifndef T_TXT
101#define T_TXT 16
102#endif
103#ifndef NO_DATA
104#define NO_DATA NO_ADDRESS
105#endif
106#ifndef C_HS
107#define C_HS 4
108#endif
109
110int sockFD;
111FILE *filePtr;
112char *DecodeError();
113
114static struct __res_state orig;
115extern struct __res_state _res;
ed554bc5 116static u_char *cname = NULL;
ad787160
C
117int getclass = C_IN;
118int gettype;
119int verbose = 0;
120int list = 0;
121int server_specified = 0;
122
123char *pr_class(), *pr_rr(), *pr_cdname(), *pr_type();
124extern char *hostalias();
125
126main(c, v)
127 char **v;
128{
129 unsigned addr;
130 register struct hostent *hp;
131 register char *s;
132 register inverse = 0;
133 register waitmode = 0;
ed554bc5 134 u_char *oldcname;
ad787160
C
135 int ncnames;
136
137 res_init();
138 _res.retrans = 5;
139
140 if (c < 2) {
141 fprintf(stderr, "Usage: host [-w] [-v] [-r] [-d] [-t querytype] [-c class] [-a] host [server]\n -w to wait forever until reply\n -v for verbose output\n -r to disable recursive processing\n -d to turn on debugging output\n -t querytype to look for a specific type of information\n -c class to look for non-Internet data\n -a is equivalent to '-v -t *'\n");
142 exit(1);
143 }
144 while (c > 2 && v[1][0] == '-') {
145 if (strcmp (v[1], "-w") == 0) {
146 _res.retry = 1;
147 _res.retrans = 15;
148 waitmode = 1;
149 v++;
150 c--;
151 }
152 else if (strcmp (v[1], "-r") == 0) {
153 _res.options &= ~RES_RECURSE;
154 v++;
155 c--;
156 }
157 else if (strcmp (v[1], "-d") == 0) {
158 _res.options |= RES_DEBUG;
159 v++;
160 c--;
161 }
162 else if (strcmp (v[1], "-v") == 0) {
163 verbose = 1;
164 v++;
165 c--;
166 }
167 else if (strcmp (v[1], "-l") == 0) {
168 list = 1;
169 v++;
170 c--;
171 }
172 else if (strncmp (v[1], "-t", 2) == 0) {
173 v++;
174 c--;
175 gettype = parsetype(v[1]);
176 v++;
177 c--;
178 }
179 else if (strncmp (v[1], "-c", 2) == 0) {
180 v++;
181 c--;
182 getclass = parseclass(v[1]);
183 v++;
184 c--;
185 }
186 else if (strcmp (v[1], "-a") == 0) {
187 verbose = 1;
188 gettype = T_ANY;
189 v++;
190 c--;
191 }
192 }
193 if (c > 2) {
194 s = v[2];
195 server_specified++;
196
197 addr = inet_addr(s);
198 if (addr == -1) {
199 hp = gethostbyname(s);
200 if (hp == NULL) {
201 fprintf(stderr,"Error in looking up server name:\n");
202 hperror(h_errno);
203 exit(1);
204 }
205 _res.nsaddr.sin_addr = *(struct in_addr *)hp->h_addr;
206 printf("Using domain server:\n");
207 printanswer(hp);
208 }
209 else {
210 _res.nsaddr.sin_family = AF_INET;
211 _res.nsaddr.sin_addr.s_addr = addr;
212 _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
213 printf("Using domain server %s:\n",
214 inet_ntoa(_res.nsaddr.sin_addr));
215 }
216 _res.nscount = 1;
217 _res.retry = 2;
218 }
219 if (strcmp (v[1], ".") == 0)
220 addr = -1;
221 else
222 addr = inet_addr(v[1]);
223 hp = NULL;
224 h_errno = TRY_AGAIN;
225/*
226 * we handle default domains ourselves, thank you
227 */
228 _res.options &= ~RES_DEFNAMES;
229
230 if (list)
231 exit(ListHosts(v[1], gettype ? gettype : T_A));
232 oldcname = NULL;
233 ncnames = 5;
234 while (hp == NULL && h_errno == TRY_AGAIN) {
235 if (addr == -1) {
236 cname = NULL;
237 if (oldcname == NULL)
238 hp = (struct hostent *)gethostinfo(v[1]);
239 else
240 hp = (struct hostent *)gethostinfo(oldcname);
241 if (cname) {
242 if (ncnames-- == 0) {
243 printf("Too many cnames. Possible loop.\n");
244 exit(1);
245 }
246 oldcname = cname;
247 hp = NULL;
248 h_errno = TRY_AGAIN;
249 continue;
250 }
251 }
252 else {
253 hp = gethostbyaddr((char*)&addr, 4, AF_INET);
254 if (hp)
255 printanswer(hp);
256 }
257 if (!waitmode)
258 break;
259 }
260
261 if (hp == NULL) {
262 hperror(h_errno);
263 exit(1);
264 }
265
266 exit(0);
267
268}
269
270parsetype(s)
271 char *s;
272{
273if (strcmp(s,"a") == 0)
274 return(1);
275if (strcmp(s,"ns") == 0)
276 return(2);
277if (strcmp(s,"md") == 0)
278 return(3);
279if (strcmp(s,"mf") == 0)
280 return(4);
281if (strcmp(s,"cname") == 0)
282 return(5);
283if (strcmp(s,"soa") == 0)
284 return(6);
285if (strcmp(s,"mb") == 0)
286 return(7);
287if (strcmp(s,"mg") == 0)
288 return(8);
289if (strcmp(s,"mr") == 0)
290 return(9);
291if (strcmp(s,"null") == 0)
292 return(10);
293if (strcmp(s,"wks") == 0)
294 return(11);
295if (strcmp(s,"ptr") == 0)
296 return(12);
297if (strcmp(s,"hinfo") == 0)
298 return(13);
299if (strcmp(s,"minfo") == 0)
300 return(14);
301if (strcmp(s,"mx") == 0)
302 return(15);
303if (strcmp(s,"txt") == 0) /* Roy */
304 return(T_TXT); /* Roy */
ed554bc5
C
305if (strcmp(s,"afsdb") == 0)
306 return(T_AFSDB);
ad787160
C
307if (strcmp(s,"uinfo") == 0)
308 return(100);
309if (strcmp(s,"uid") == 0)
310 return(101);
311if (strcmp(s,"gid") == 0)
312 return(102);
313if (strcmp(s,"unspec") == 0)
314 return(103);
315if (strcmp(s,"any") == 0)
316 return(255);
317if (strcmp(s,"*") == 0)
318 return(255);
319if (atoi(s))
320 return(atoi(s));
321fprintf(stderr, "Invalid query type: %s\n", s);
322exit(2);
323}
324
325parseclass(s)
326 char *s;
327{
328if (strcmp(s,"in") == 0)
329 return(C_IN);
330if (strcmp(s,"hs") == 0)
331 return(C_HS);
332if (strcmp(s,"any") == 0)
333 return(C_ANY);
334if (atoi(s))
335 return(atoi(s));
336fprintf(stderr, "Invalid query class: %s\n", s);
337exit(2);
338}
339
340printanswer(hp)
341 register struct hostent *hp;
342{
343 register char **cp;
344 register long **hptr;
345
346 printf("Name: %s\n", hp->h_name);
347 printf("Address:");
348 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
349 printf(" %s", inet_ntoa(*(struct in_addr *)*hptr));
350 printf("\nAliases:");
351 for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
352 printf(" %s", *cp);
353 printf("\n\n");
354}
355
356hperror(errno)
357int errno;
358{
359switch(errno) {
360 case HOST_NOT_FOUND:
361 fprintf(stderr,"Host not found.\n");
362 break;
363 case TRY_AGAIN:
364 fprintf(stderr,"Host not found, try again.\n");
365 break;
366 case NO_RECOVERY:
367 fprintf(stderr,"No recovery, Host not found.\n");
368 break;
369 case NO_ADDRESS:
ed554bc5
C
370 fprintf(stderr,"There is an entry for this host, but it doesn't have ");
371 switch (gettype) {
372 case T_A:
373 fprintf(stderr,"an Internet address.\n");
374 break;
375 case T_NS:
376 fprintf(stderr,"a Name Server.\n");
377 break;
378 case T_MD:
379 fprintf(stderr,"a Mail Destination.\n");
380 break;
381 case T_MF:
382 fprintf(stderr,"a Mail Forwarder.\n");
383 break;
384 case T_CNAME:
385 fprintf(stderr,"a Canonical Name.\n");
386 break;
387 case T_SOA:
388 fprintf(stderr,"a Start of Authority record.\n");
389 break;
390 case T_MB:
391 fprintf(stderr,"a Mailbox Domain Name.\n");
392 break;
393 case T_MG:
394 fprintf(stderr,"a Mail Group Member.\n");
395 break;
396 case T_MR:
397 fprintf(stderr,"a Mail Rename Name.\n");
398 break;
399 case T_NULL:
400 fprintf(stderr,"a Null Resource record.\n");
401 break;
402 case T_WKS:
403 fprintf(stderr,"any Well Known Service information.\n");
404 break;
405 case T_PTR:
406 fprintf(stderr,"a Pointer record.\n");
407 break;
408 case T_HINFO:
409 fprintf(stderr,"any Host Information.\n");
410 break;
411 case T_MINFO:
412 fprintf(stderr,"any Mailbox Information.\n");
413 break;
414 case T_MX:
415 fprintf(stderr,"a Mail Exchanger record.\n");
416 break;
417 case T_TXT:
418 fprintf(stderr,"a Text record.\n");
419 break;
420 case T_UINFO:
421 fprintf(stderr,"any User Information.\n");
422 break;
423 case T_UID:
424 fprintf(stderr,"a User ID.\n");
425 break;
426 case T_GID:
427 fprintf(stderr,"a Group ID.\n");
428 break;
429 case T_UNSPEC:
430 fprintf(stderr,"any Unspecified Format data.\n");
431 break;
432 default:
433 fprintf(stderr,"the information you requested.\n");
434 break;
435 }
ad787160
C
436 break;
437 }
438}
439
440
441typedef union {
442 HEADER qb1;
ed554bc5 443 u_char qb2[PACKETSZ];
ad787160
C
444} querybuf;
445
ed554bc5 446static u_char hostbuf[BUFSIZ+1];
ad787160
C
447
448gethostinfo(name)
449 char *name;
450{
451 register char *cp, **domain;
452 int n;
453 int hp;
454 int nDomain;
455
456 if (strcmp(name, ".") == 0)
457 return(getdomaininfo(name, NULL));
458 for (cp = name, n = 0; *cp; cp++)
459 if (*cp == '.')
460 n++;
461 if (n && cp[-1] == '.') {
462 if (cp[-1] == '.')
463 cp[-1] = 0;
464 hp = getdomaininfo(name, (char *)NULL);
465 if (cp[-1] == 0)
466 cp[-1] = '.';
467 return (hp);
468 }
469 if (n == 0 && (cp = hostalias(name))) {
470 if (verbose)
471 printf("Aliased to \"%s\"\n", cp);
472 _res.options |= RES_DEFNAMES;
473 return (getdomaininfo(cp, (char *)NULL));
474 }
475#ifdef MAXDS
476 for (nDomain = 0;
477 _res.defdname_list[nDomain][0] != 0;
478 nDomain++) {
479 for (domain = _res.dnsrch_list[nDomain]; *domain; domain++) {
480 if (verbose)
481 printf("Trying domain \"%s\"\n", *domain);
482 hp = getdomaininfo(name, *domain);
483 if (hp)
484 return (hp);
485 }
486 }
487#else
488 for (domain = _res.dnsrch; *domain; domain++) {
489 if (verbose)
490 printf("Trying domain \"%s\"\n", *domain);
491 hp = getdomaininfo(name, *domain);
492 if (hp)
493 return (hp);
494 }
495#endif
496 if (h_errno != HOST_NOT_FOUND ||
497 (_res.options & RES_DNSRCH) == 0)
498 return (0);
499 if (verbose)
500 printf("Trying null domain\n");
501 return (getdomaininfo(name, (char *)NULL));
502}
503
504getdomaininfo(name, domain)
505 char *name, *domain;
506{
507 int val1, val2;
508
509 if (gettype)
510 return getinfo(name, domain, gettype);
511 else {
512 val1 = getinfo(name, domain, T_A);
513 if (cname || verbose)
514 return val1;
515 val2 = getinfo(name, domain, T_MX);
516 return val1 || val2;
517 }
518}
519
520getinfo(name, domain, type)
521 char *name, *domain;
522{
523
524 HEADER *hp;
525 char *eom, *bp, *cp;
526 querybuf buf, answer;
527 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
528 u_short pref, class;
529 char host[2*MAXDNAME+2];
530
531 if (domain == NULL)
532 (void)sprintf(host, "%.*s", MAXDNAME, name);
533 else
534 (void)sprintf(host, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
535
536 n = res_mkquery(QUERY, host, getclass, type, (char *)NULL, 0, NULL,
537 (char *)&buf, sizeof(buf));
538 if (n < 0) {
539 if (_res.options & RES_DEBUG)
540 printf("res_mkquery failed\n");
541 h_errno = NO_RECOVERY;
542 return(0);
543 }
544 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
545 if (n < 0) {
546 if (_res.options & RES_DEBUG)
547 printf("res_send failed\n");
548 h_errno = TRY_AGAIN;
549 return (0);
550 }
551 eom = (char *)&answer + n;
552 return(printinfo(&answer, eom, T_ANY, 0));
553 }
554
555printinfo(answer, eom, filter, isls)
556 querybuf *answer;
ed554bc5 557 u_char *eom;
ad787160
C
558 int filter;
559 int isls;
560{
561 HEADER *hp;
ed554bc5 562 u_char *bp, *cp;
ad787160
C
563 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
564 u_short pref, class;
565
566 /*
567 * find first satisfactory answer
568 */
569 hp = (HEADER *) answer;
570 ancount = ntohs(hp->ancount);
571 qdcount = ntohs(hp->qdcount);
572 nscount = ntohs(hp->nscount);
573 arcount = ntohs(hp->arcount);
574 if (_res.options & RES_DEBUG || (verbose && isls == 0))
575 printf("rcode = %d (%s), ancount=%d\n",
576 hp->rcode, DecodeError(hp->rcode), ancount);
577 if (hp->rcode != NOERROR || (ancount+nscount+arcount) == 0) {
578 switch (hp->rcode) {
579 case NXDOMAIN:
ed554bc5
C
580 h_errno = HOST_NOT_FOUND;
581 return(0);
ad787160
C
582 case SERVFAIL:
583 h_errno = TRY_AGAIN;
584 return(0);
585#ifdef OLDJEEVES
586 /*
587 * Jeeves (TOPS-20 server) still does not
588 * support MX records. For the time being,
589 * we must accept FORMERRs as the same as
590 * NOERROR.
591 */
592 case FORMERR:
ed554bc5 593#endif /*OLDJEEVES*/
ad787160
C
594 case NOERROR:
595/* TpB - set a return error for this case. NO_DATA */
596 h_errno = NO_DATA;
597 return(0); /* was 1,but now indicates exception */
598#ifndef OLDJEEVES
599 case FORMERR:
ed554bc5 600#endif /*OLDJEEVES*/
ad787160
C
601 case NOTIMP:
602 case REFUSED:
603 h_errno = NO_RECOVERY;
604 return(0);
605 }
606 return (0);
607 }
608 bp = hostbuf;
609 nmx = 0;
610 buflen = sizeof(hostbuf);
ed554bc5 611 cp = (u_char *)answer + sizeof(HEADER);
ad787160 612 if (qdcount) {
ed554bc5 613 cp += dn_skipname(cp, eom) + QFIXEDSZ;
ad787160 614 while (--qdcount > 0)
ed554bc5 615 cp += dn_skipname(cp, eom) + QFIXEDSZ;
ad787160
C
616 }
617 if (ancount) {
618 if (!hp->aa)
619 if (verbose && isls == 0)
620 printf("The following answer is not authoritative:\n");
621 while (--ancount >= 0 && cp && cp < eom) {
ed554bc5 622 cp = (u_char *)pr_rr(cp, answer, stdout, filter);
ad787160
C
623/*
624 * When we ask for address and there is a CNAME, it seems to return
625 * both the CNAME and the address. Since we trace down the CNAME
626 * chain ourselves, we don't really want to print the address at
627 * this point.
628 */
629 if (cname && ! verbose)
630 return (1);
631 }
632 }
633 if (! verbose)
634 return (1);
635 if (nscount) {
636 printf("For authoritative answers, see:\n");
637 while (--nscount >= 0 && cp && cp < eom) {
ed554bc5 638 cp = (u_char *)pr_rr(cp, answer, stdout, filter);
ad787160
C
639 }
640 }
641 if (arcount) {
642 printf("Additional information:\n");
643 while (--arcount >= 0 && cp && cp < eom) {
ed554bc5 644 cp = (u_char *)pr_rr(cp, answer, stdout, filter);
ad787160
C
645 }
646 }
647 return(1);
648 }
649
ed554bc5 650static u_char cnamebuf[MAXDNAME];
ad787160
C
651
652/*
653 * Print resource record fields in human readable form.
654 */
655char *
656pr_rr(cp, msg, file, filter)
ed554bc5 657 u_char *cp, *msg;
ad787160
C
658 FILE *file;
659 int filter;
660{
661 int type, class, dlen, n, c, proto, ttl;
662 struct in_addr inaddr;
ed554bc5 663 u_char *cp1;
ad787160
C
664 struct protoent *protop;
665 struct servent *servp;
666 char punc;
667 int doprint;
668 char name[MAXDNAME];
669
ed554bc5 670 if ((cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name))) == NULL)
ad787160
C
671 return (NULL); /* compression error */
672
673 type = _getshort(cp);
674 cp += sizeof(u_short);
675
676 class = _getshort(cp);
677 cp += sizeof(u_short);
678
679 ttl = _getlong(cp);
ed554bc5 680 cp += sizeof(u_int32_t);
ad787160
C
681
682 if (filter == type || filter == T_ANY ||
683 (filter == T_A && (type == T_PTR || type == T_NS)))
684 doprint = 1;
685 else
686 doprint = 0;
687
688 if (doprint)
689 if (verbose)
690 fprintf(file,"%s\t%d%s\t%s",
691 name, ttl, pr_class(class), pr_type(type));
692 else
693 fprintf(file,"%s%s %s",name, pr_class(class), pr_type(type));
694 if (verbose)
695 punc = '\t';
696 else
697 punc = ' ';
698
699 dlen = _getshort(cp);
700 cp += sizeof(u_short);
701 cp1 = cp;
702 /*
703 * Print type specific data, if appropriate
704 */
705 switch (type) {
706 case T_A:
707 switch (class) {
708 case C_IN:
709 bcopy(cp, (char *)&inaddr, sizeof(inaddr));
710 if (dlen == 4) {
711 if (doprint)
712 fprintf(file,"%c%s", punc,
713 inet_ntoa(inaddr));
714 cp += dlen;
715 } else if (dlen == 7) {
716 if (doprint) {
717 fprintf(file,"%c%s", punc,
718 inet_ntoa(inaddr));
719 fprintf(file,", protocol = %d", cp[4]);
720 fprintf(file,", port = %d",
721 (cp[5] << 8) + cp[6]);
722 }
723 cp += dlen;
724 }
725 break;
726 }
727 break;
728 case T_CNAME:
729 if (dn_expand(msg, msg + 512, cp, cnamebuf,
730 sizeof(cnamebuf)) >= 0)
731 cname = cnamebuf;
732 case T_MB:
733#ifdef OLDRR
734 case T_MD:
735 case T_MF:
736#endif /* OLDRR */
737 case T_MG:
738 case T_MR:
739 case T_NS:
740 case T_PTR:
ed554bc5 741 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
742 if (doprint)
743 fprintf(file,"%c%s",punc, name);
744 break;
745
746 case T_HINFO:
747 if (n = *cp++) {
748 if (doprint)
749 fprintf(file,"%c%.*s", punc, n, cp);
750 cp += n;
751 }
752 if (n = *cp++) {
753 if (doprint)
754 fprintf(file,"%c%.*s", punc, n, cp);
755 cp += n;
756 }
757 break;
758
759 case T_SOA:
ed554bc5 760 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
761 if (doprint)
762 fprintf(file,"\t%s", name);
ed554bc5 763 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
764 if (doprint)
765 fprintf(file," %s", name);
766 if (doprint)
767 fprintf(file,"(\n\t\t\t%ld\t;serial (version)", _getlong(cp));
ed554bc5 768 cp += sizeof(u_int32_t);
ad787160
C
769 if (doprint)
770 fprintf(file,"\n\t\t\t%ld\t;refresh period", _getlong(cp));
ed554bc5 771 cp += sizeof(u_int32_t);
ad787160
C
772 if (doprint)
773 fprintf(file,"\n\t\t\t%ld\t;retry refresh this often", _getlong(cp));
ed554bc5 774 cp += sizeof(u_int32_t);
ad787160
C
775 if (doprint)
776 fprintf(file,"\n\t\t\t%ld\t;expiration period", _getlong(cp));
ed554bc5 777 cp += sizeof(u_int32_t);
ad787160
C
778 if (doprint)
779 fprintf(file,"\n\t\t\t%ld\t;minimum TTL\n\t\t\t)", _getlong(cp));
ed554bc5 780 cp += sizeof(u_int32_t);
ad787160
C
781 break;
782
783 case T_MX:
ed554bc5 784 case T_AFSDB:
ad787160
C
785 if (doprint)
786 if (verbose)
787 fprintf(file,"\t%ld ",_getshort(cp));
788 else
789 fprintf(file," ");
790 cp += sizeof(u_short);
ed554bc5 791 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
792 if (doprint)
793 fprintf(file, "%s", name);
794 break;
795
796 case T_MINFO:
797 case T_RP:
ed554bc5 798 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
799 if (doprint)
800 fprintf(file, "%c%s", punc, name);
ed554bc5 801 cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
ad787160
C
802 if (doprint)
803 fprintf(file, " %s", name);
804 break;
805
806 case T_TXT:
807 if (doprint)
808 fprintf(file,"%c%.*s", punc, dlen, cp);
809 cp += dlen;
810 break;
811
812 case T_UINFO:
813 if (doprint)
814 fprintf(file,"%c%s", punc, cp);
815 cp += dlen;
816 break;
817
818 case T_UID:
819 case T_GID:
820 if (dlen == 4) {
821 if (doprint)
822 fprintf(file,"%c%ld", punc, _getlong(cp));
823 cp += sizeof(int);
824 }
825 break;
826
827 case T_WKS:
ed554bc5 828 if (dlen < sizeof(u_int32_t) + 1)
ad787160
C
829 break;
830 bcopy(cp, (char *)&inaddr, sizeof(inaddr));
ed554bc5 831 cp += sizeof(u_int32_t);
ad787160
C
832 proto = *cp++;
833 protop = getprotobynumber(proto);
834 if (doprint)
835 if (protop)
836 fprintf(file,"%c%s %s", punc,
837 inet_ntoa(inaddr), protop->p_name);
838 else
839 fprintf(file,"%c%s %d", punc,
840 inet_ntoa(inaddr), proto);
841
842 n = 0;
843 while (cp < cp1 + dlen) {
844 c = *cp++;
845 do {
846 if (c & 0200) {
847 servp = NULL;
848 if (protop)
849 servp = getservbyport (htons(n),
850 protop->p_name);
851 if (doprint)
852 if (servp)
853 fprintf(file, " %s", servp->s_name);
854 else
855 fprintf(file, " %d", n);
856 }
857 c <<= 1;
858 } while (++n & 07);
859 }
860 break;
861
862 default:
863 if (doprint)
864 fprintf(file,"%c???", punc);
865 cp += dlen;
866 }
867 if (cp != cp1 + dlen)
868 fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
869 if (doprint)
870 fprintf(file,"\n");
ed554bc5 871 return (char *)cp;
ad787160
C
872}
873
874static char nbuf[20];
875
876/*
877 * Return a string for the type
878 */
879char *
880pr_type(type)
881 int type;
882{
883 switch (type) {
884 case T_A:
885 return(verbose? "A" : "has address");
886 case T_NS: /* authoritative server */
887 return("NS");
888#ifdef OLDRR
889 case T_MD: /* mail destination */
890 return("MD");
891 case T_MF: /* mail forwarder */
892 return("MF");
893#endif /* OLDRR */
894 case T_CNAME: /* connonical name */
895 return(verbose? "CNAME" : "is a nickname for");
896 case T_SOA: /* start of authority zone */
897 return("SOA");
898 case T_MB: /* mailbox domain name */
899 return("MB");
900 case T_MG: /* mail group member */
901 return("MG");
902 case T_MX: /* mail routing info */
903 return(verbose? "MX" : "mail is handled by");
904 /* Roy start */
905 case T_TXT: /* TXT - descriptive info */
906 return(verbose? "TXT" : "descriptive text");
907 /* Roy end */
ed554bc5
C
908 case T_AFSDB: /* AFS/DCE info */
909 return(verbose? "AFSDB" : "DCE or AFS service from");
ad787160
C
910 case T_MR: /* mail rename name */
911 return("MR");
912 case T_NULL: /* null resource record */
913 return("NULL");
914 case T_WKS: /* well known service */
915 return("WKS");
916 case T_PTR: /* domain name pointer */
917 return("PTR");
918 case T_HINFO: /* host information */
919 return("HINFO");
920 case T_MINFO: /* mailbox information */
921 return("MINFO");
922 case T_AXFR: /* zone transfer */
923 return("AXFR");
924 case T_MAILB: /* mail box */
925 return("MAILB");
926 case T_MAILA: /* mail address */
927 return("MAILA");
928 case T_ANY: /* matches any type */
929 return("ANY");
930 case T_UINFO:
931 return("UINFO");
932 case T_UID:
933 return("UID");
934 case T_GID:
935 return("GID");
936 default:
937 sprintf(nbuf, "%d", type);
938 return nbuf;
939 }
940}
941
942/*
943 * Return a mnemonic for class
944 */
945char *
946pr_class(class)
947 int class;
948{
949
950 switch (class) {
951 case C_IN: /* internet class */
952 return(verbose? " IN" : "");
953 case C_HS: /* internet class */
954 return(verbose? " HS" : "");
955 case C_ANY: /* matches any class */
956 return(" ANY");
957 default:
958 (void) sprintf(nbuf," %d", class);
959 return nbuf;
960 }
961}
962
963char *
964pr_cdname(cp, msg, name, namelen)
ed554bc5
C
965 u_char *cp, *msg;
966 u_char *name;
ad787160
C
967 int namelen;
968{
969 int n;
970
971 if ((n = dn_expand(msg, msg + 512, cp, name, namelen - 2)) < 0)
972 return (NULL);
973 if (name[0] == '\0') {
974 name[0] = '.';
975 name[1] = '\0';
976 }
ed554bc5 977 return (char *)(cp + n);
ad787160
C
978}
979
980char *resultcodes[] = {
981 "NOERROR",
982 "FORMERR",
983 "SERVFAIL",
984 "NXDOMAIN",
985 "NOTIMP",
986 "REFUSED",
987 "6",
988 "7",
989 "8",
990 "9",
991 "10",
992 "11",
993 "12",
994 "13",
995 "14",
996 "NOCHANGE",
997};
998
999
1000\f
1001/*
1002 ******************************************************************************
1003 *
1004 * ListHosts --
1005 *
1006 * Requests the name server to do a zone transfer so we
1007 * find out what hosts it knows about.
1008 *
1009 * Results:
1010 * SUCCESS the listing was successful.
1011 * ERROR the server could not be contacted because
1012 * a socket could not be obtained or an error
1013 * occured while receiving, or the output file
1014 * could not be opened.
1015 *
1016 ******************************************************************************
1017 */
1018
1019int
1020ListHosts(namePtr, queryType)
1021 char *namePtr;
1022 int queryType; /* e.g. T_A */
1023{
1024 querybuf buf, answer;
1025 struct sockaddr_in sin;
1026 HEADER *headerPtr;
1027
1028 int msglen;
1029 int amtToRead;
1030 int numRead;
1031 int i;
1032 int numAnswers = 0;
1033 int result;
1034 int soacnt = 0;
1035 u_short len;
1036 int dlen;
1037 int type;
1038 int nscount;
ed554bc5
C
1039 u_char *cp, *nmp;
1040 u_char name[NAME_LEN];
1041 u_char dname[2][NAME_LEN];
1042 u_char domain[NAME_LEN];
ad787160
C
1043/* names and addresses of name servers to try */
1044#define NUMNS 8
1045 char nsname[NUMNS][NAME_LEN];
1046 int nshaveaddr[NUMNS];
1047#define IPADDRSIZE 4
1048#define NUMNSADDR 16
1049 char nsipaddr[NUMNSADDR][IPADDRSIZE];
1050 int numns;
1051 int numnsaddr;
1052 int thisns;
1053 struct hostent *hp;
1054 enum {
1055 NO_ERRORS,
1056 ERR_READING_LEN,
1057 ERR_READING_MSG,
1058 ERR_PRINTING,
1059 } error = NO_ERRORS;
1060
1061/*
1062 * normalize to not have trailing dot. We do string compares below
1063 * of info from name server, and it won't have trailing dots.
1064 */
1065 i = strlen(namePtr);
1066 if (namePtr[i-1] == '.')
1067 namePtr[i-1] = 0;
1068
1069 if (server_specified) {
1070 bcopy(&_res.nsaddr.sin_addr, nsipaddr[0], IPADDRSIZE);
1071 numnsaddr = 1;
1072 }
1073 else {
1074
1075/*
1076 * First we have to find out where to look. This needs a NS query,
1077 * possibly followed by looking up addresses for some of the names.
1078 */
1079
1080 msglen = res_mkquery(QUERY, namePtr, C_IN, T_NS,
1081 (char *)0, 0, (char *)0,
1082 (char *) &buf, sizeof(buf));
1083
1084 if (msglen < 0) {
1085 printf("res_mkquery failed\n");
1086 return (ERROR);
1087 }
1088
1089 msglen = res_send((char *)&buf,msglen,(char *)&answer, sizeof(answer));
1090
1091 if (msglen < 0) {
1092 printf("Unable to get to nameserver -- try again later\n");
1093 return (ERROR);
1094 }
1095 if (_res.options & RES_DEBUG || verbose)
1096 printf("rcode = %d (%s), ancount=%d\n",
1097 answer.qb1.rcode, DecodeError(answer.qb1.rcode),
1098 ntohs(answer.qb1.ancount));
1099
1100/*
1101 * Analyze response to our NS lookup
1102 */
1103
1104 nscount = ntohs(answer.qb1.ancount) + ntohs(answer.qb1.nscount) +
1105 ntohs(answer.qb1.arcount);
1106
1107 if (answer.qb1.rcode != NOERROR || nscount == 0) {
1108 switch (answer.qb1.rcode) {
1109 case NXDOMAIN:
1110 /* Check if it's an authoritive answer */
1111 if (answer.qb1.aa) {
1112 printf("No such domain\n");
1113 } else {
1114 printf("Unable to get information about domain -- try again later.\n");
1115 }
1116 break;
1117 case SERVFAIL:
1118 printf("Unable to get information about that domain -- try again later.\n");
1119 break;
1120 case NOERROR:
1121 printf("That domain exists, but seems to be a leaf node.\n");
1122 break;
1123 case FORMERR:
1124 case NOTIMP:
1125 case REFUSED:
1126 printf("Unrecoverable error looking up domain name.\n");
1127 break;
1128 }
1129 return (0);
1130 }
1131
ed554bc5 1132 cp = (u_char *)answer.qb2 + sizeof(HEADER);
ad787160
C
1133 if (ntohs(answer.qb1.qdcount) > 0)
1134 cp += dn_skipname(cp, answer.qb2 + msglen) + QFIXEDSZ;
1135
1136 numns = 0;
1137 numnsaddr = 0;
1138
1139/*
1140 * Look at response from NS lookup for NS and A records.
1141 */
1142
1143 for (;nscount; nscount--) {
1144 cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1145 domain, sizeof(domain));
1146 type = _getshort(cp);
ed554bc5 1147 cp += sizeof(u_short) + sizeof(u_short) + sizeof(u_int32_t);
ad787160
C
1148 dlen = _getshort(cp);
1149 cp += sizeof(u_short);
1150 if (type == T_NS) {
1151 if (dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1152 name, sizeof(name)) >= 0) {
ed554bc5 1153 if (numns < NUMNS && strcasecmp((char *)domain, namePtr) == 0) {
ad787160 1154 for (i = 0; i < numns; i++)
ed554bc5 1155 if (strcasecmp(nsname[i], (char *)name) == 0)
ad787160
C
1156 break; /* duplicate */
1157 if (i >= numns) {
ed554bc5 1158 strncpy(nsname[numns], (char *)name, sizeof(name));
ad787160
C
1159 nshaveaddr[numns] = 0;
1160 numns++;
1161 }
1162 }
1163 }
1164 }
1165 else if (type == T_A) {
1166 if (numnsaddr < NUMNSADDR)
1167 for (i = 0; i < numns; i++) {
ed554bc5 1168 if (strcasecmp(nsname[i], (char *)domain) == 0) {
ad787160
C
1169 nshaveaddr[i]++;
1170 bcopy(cp, nsipaddr[numnsaddr],IPADDRSIZE);
1171 numnsaddr++;
1172 break;
1173 }
1174 }
1175 }
1176 cp += dlen;
1177 }
1178
1179/*
1180 * Usually we'll get addresses for all the servers in the additional
1181 * info section. But in case we don't, look up their addresses.
1182 */
1183
1184 for (i = 0; i < numns; i++) {
1185 if (! nshaveaddr[i]) {
1186 register long **hptr;
1187 int numaddrs = 0;
1188
1189 hp = gethostbyname(nsname[i]);
1190 if (hp) {
1191 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
1192 if (numnsaddr < NUMNSADDR) {
1193 bcopy((char *)*hptr, nsipaddr[numnsaddr],IPADDRSIZE);
1194 numnsaddr++;
1195 numaddrs++;
1196 }
1197 }
1198 if (_res.options & RES_DEBUG || verbose)
1199 printf("Found %d addresses for %s by extra query\n",
1200 numaddrs, nsname[i]);
1201 }
1202 else
1203 if (_res.options & RES_DEBUG || verbose)
1204 printf("Found %d addresses for %s\n",
1205 nshaveaddr[i], nsname[i]);
1206 }
1207 }
1208/*
1209 * Now nsipaddr has numnsaddr addresses for name servers that
1210 * serve the requested domain. Now try to find one that will
1211 * accept a zone transfer.
1212 */
1213
1214 thisns = 0;
1215
1216again:
1217
1218 numAnswers = 0;
1219 soacnt = 0;
1220
1221 /*
1222 * Create a query packet for the requested domain name.
1223 *
1224 */
1225 msglen = res_mkquery(QUERY, namePtr, getclass, T_AXFR,
1226 (char *)0, 0, (char *)0,
1227 (char *) &buf, sizeof(buf));
1228 if (msglen < 0) {
1229 if (_res.options & RES_DEBUG) {
1230 fprintf(stderr, "ListHosts: Res_mkquery failed\n");
1231 }
1232 return (ERROR);
1233 }
1234
1235 bzero((char *)&sin, sizeof(sin));
1236 sin.sin_family = AF_INET;
1237 sin.sin_port = htons(NAMESERVER_PORT);
1238
1239 /*
1240 * Set up a virtual circuit to the server.
1241 */
1242
1243 for (;thisns < numnsaddr; thisns++) {
1244 if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1245 perror("ListHosts");
1246 return(ERROR);
1247 }
1248 bcopy(nsipaddr[thisns], &sin.sin_addr, IPADDRSIZE);
1249 if (_res.options & RES_DEBUG || verbose)
1250 printf("Trying %s\n", inet_ntoa(sin.sin_addr));
1251 if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
1252 break;
1253 if (verbose)
1254 perror("Connection failed, trying next server");
1255 (void) close(sockFD);
1256 sockFD = -1;
1257 }
1258 if (thisns >= numnsaddr) {
1259 printf("No server for that domain responded\n");
1260 if (!verbose)
1261 perror("Error from the last server was");
1262 return(ERROR);
1263 }
1264
1265 /*
1266 * Send length & message for zone transfer
1267 */
1268
1269 len = htons(msglen);
1270
1271 if (write(sockFD, (char *)&len, sizeof(len)) != sizeof(len) ||
1272 write(sockFD, (char *) &buf, msglen) != msglen) {
1273 perror("ListHosts");
1274 (void) close(sockFD);
1275 sockFD = -1;
1276 return(ERROR);
1277 }
1278
1279 filePtr = stdout;
1280
1281 while (1) {
1282
1283 /*
1284 * Read the length of the response.
1285 */
1286
ed554bc5 1287 cp = (u_char *) &buf;
ad787160
C
1288 amtToRead = sizeof(u_short);
1289 while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
1290 cp += numRead;
1291 amtToRead -= numRead;
1292 }
1293 if (numRead <= 0) {
1294 error = ERR_READING_LEN;
1295 break;
1296 }
1297
1298 if ((len = htons(*(u_short *)&buf)) == 0) {
1299 break; /* nothing left to read */
1300 }
1301
1302 /*
1303 * Read the response.
1304 */
1305
1306 amtToRead = len;
ed554bc5 1307 cp = (u_char *) &buf;
ad787160
C
1308 while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
1309 cp += numRead;
1310 amtToRead -= numRead;
1311 }
1312 if (numRead <= 0) {
1313 error = ERR_READING_MSG;
1314 break;
1315 }
1316
1317 i = buf.qb1.rcode;
1318 if (i != NOERROR || ntohs(buf.qb1.ancount) == 0) {
1319 if ((thisns+1) < numnsaddr &&
1320 (i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
1321 if (_res.options & RES_DEBUG || verbose)
1322 printf("Server failed, trying next server: %s\n",
1323 i != NOERROR ?
1324 DecodeError(i) : "Premature end of data");
1325 (void) close(sockFD);
1326 sockFD = -1;
1327 thisns++;
1328 goto again;
1329 }
1330 printf("Server failed: %s\n",
1331 i != NOERROR ? DecodeError(i) : "Premature end of data");
1332 break;
1333 }
1334
1335
1336 result = printinfo(&buf, cp, queryType, 1);
1337 if (! result) {
1338 error = ERR_PRINTING;
1339 break;
1340 }
1341 numAnswers++;
1342 cp = buf.qb2 + sizeof(HEADER);
1343 if (ntohs(buf.qb1.qdcount) > 0)
1344 cp += dn_skipname(cp, buf.qb2 + len) + QFIXEDSZ;
1345
1346 nmp = cp;
1347 cp += dn_skipname(cp, (u_char *)&buf + len);
1348 if ((_getshort(cp) == T_SOA)) {
1349 dn_expand(buf.qb2, buf.qb2 + len, nmp, dname[soacnt],
1350 sizeof(dname[0]));
1351 if (soacnt) {
ed554bc5 1352 if (strcmp((char *)dname[0], (char *)dname[1]) == 0)
ad787160
C
1353 break;
1354 } else
1355 soacnt++;
1356 }
1357 }
1358
1359 (void) close(sockFD);
1360 sockFD = -1;
1361
1362 switch (error) {
1363 case NO_ERRORS:
1364 return (SUCCESS);
1365
1366 case ERR_READING_LEN:
1367 return(ERROR);
1368
1369 case ERR_PRINTING:
1370 fprintf(stderr,"*** Error during listing of %s: %s\n",
1371 namePtr, DecodeError(result));
1372 return(result);
1373
1374 case ERR_READING_MSG:
1375 headerPtr = (HEADER *) &buf;
1376 fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
1377 fprintf(stderr,
1378 " result: %s, answers = %d, authority = %d, additional = %d\n",
1379 resultcodes[headerPtr->rcode],
1380 ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
1381 ntohs(headerPtr->arcount));
1382 return(ERROR);
1383 default:
1384 return(ERROR);
1385 }
1386}
1387
1388char *
1389DecodeError(result)
1390 int result;
1391{
1392 switch(result) {
1393 case NOERROR: return("Success"); break;
1394 case FORMERR: return("Format error"); break;
1395 case SERVFAIL: return("Server failed"); break;
1396 case NXDOMAIN: return("Non-existent domain"); break;
1397 case NOTIMP: return("Not implemented"); break;
1398 case REFUSED: return("Query refused"); break;
1399 case NOCHANGE: return("No change"); break;
1400 case NO_INFO: return("No information"); break;
1401 case ERROR: return("Unspecified error"); break;
1402 case TIME_OUT: return("Timed out"); break;
1403 case NONAUTH: return("Non-authoritative answer"); break;
1404 default: break;
1405 }
1406 return("BAD ERROR VALUE");
1407}