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