tools/llvm: Do not build with symbols
[minix3.git] / minix / commands / host / host.c
blobd70a1947f8022219b156d4006a2f39bd4deab73c
1 /*
2 * Copyright (c) 1986 Regents of the University of California
3 * All Rights Reserved
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
14 * Actually, this program is from Rutgers University, however it is
15 * based on nslookup and other pieces of named tools, so it needs
16 * that copyright notice.
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <arpa/nameser.h>
22 #include <netdb.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <resolv.h>
26 #include <sys/param.h>
27 #include <strings.h>
28 #include <ctype.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/ioc_net.h>
35 #include <net/netlib.h>
36 #include <net/gen/in.h>
37 #include <net/gen/tcp.h>
38 #include <net/gen/tcp_io.h>
40 extern int h_errno;
42 #define NUMMX 50
44 #define SUCCESS 0
45 #define TIME_OUT -1
46 #define NO_INFO -2
47 #define ERROR -3
48 #define NONAUTH -4
50 #define NAME_LEN 256
52 #ifndef T_TXT
53 #define T_TXT 16
54 #endif
55 #ifndef NO_DATA
56 #define NO_DATA NO_ADDRESS
57 #endif
58 #ifndef C_HS
59 #define C_HS 4
60 #endif
61 #ifndef NOCHANGE
62 #define NOCHANGE 0xf
63 #endif
65 FILE *filePtr;
67 static struct __res_state orig;
68 static u8_t *cname = NULL;
69 int getclass = C_IN;
70 int gettype, getdeftype = T_A;
71 int verbose = 0;
72 int list = 0;
73 int server_specified = 0;
75 union querybuf;
77 int main( int c, char *v[] );
79 static int parsetype( char *s );
80 static int parseclass( char *s );
81 static void hperror( int err_no );
82 static void printanswer( struct hostent *hp );
83 static int ListHosts( char *namePtr, int queryType );
84 static int gethostinfo( char *name );
85 static int getdomaininfo( char *name, char *domain );
86 static int getinfo( char *name, char *domain, int type );
87 static int printinfo( union querybuf *answer, u8_t *eom, int filter, int
88 isls );
89 static char *DecodeError( int result );
90 static u8_t *pr_rr( u8_t *cp, u8_t *msg, FILE *file, int filter );
91 static u8_t * pr_cdname( u8_t *cp, u8_t *msg, u8_t *name, int namelen );
92 static char *pr_class( int class );
93 static char *pr_type( int type );
94 static int tcpip_writeall( int fd, char *buf, unsigned siz );
96 int
97 main(c, v)
98 int c;
99 char **v;
101 char *domain;
102 struct in_addr addr;
103 register struct hostent *hp;
104 register char *s, *p;
105 register int inverse = 0;
106 register int waitmode = 0;
107 u8_t *oldcname;
108 int ncnames;
109 int isaddr;
111 res_init();
112 _res.retrans = 5;
114 if (c < 2) {
115 fprintf(stderr, "Usage: host [-w] [-v] [-r] [-d] [-V] [-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 -V to always use a virtual circuit\n");
116 exit(1);
118 while (c > 2 && v[1][0] == '-') {
119 if (strcmp (v[1], "-w") == 0) {
120 _res.retry = 1;
121 _res.retrans = 15;
122 waitmode = 1;
123 v++;
124 c--;
126 else if (strcmp (v[1], "-r") == 0) {
127 _res.options &= ~RES_RECURSE;
128 v++;
129 c--;
131 else if (strcmp (v[1], "-d") == 0) {
132 _res.options |= RES_DEBUG;
133 v++;
134 c--;
136 else if (strcmp (v[1], "-v") == 0) {
137 verbose = 1;
138 v++;
139 c--;
141 else if (strcmp (v[1], "-l") == 0) {
142 list = 1;
143 v++;
144 c--;
146 else if (strncmp (v[1], "-t", 2) == 0) {
147 v++;
148 c--;
149 gettype = parsetype(v[1]);
150 v++;
151 c--;
153 else if (strncmp (v[1], "-c", 2) == 0) {
154 v++;
155 c--;
156 getclass = parseclass(v[1]);
157 v++;
158 c--;
160 else if (strcmp (v[1], "-a") == 0) {
161 verbose = 1;
162 gettype = T_ANY;
163 v++;
164 c--;
166 else if (strcmp (v[1], "-V") == 0) {
167 _res.options |= RES_USEVC;
168 v++;
169 c--;
172 if (c > 2) {
173 s = v[2];
174 server_specified++;
176 if ((p = strchr(s, ':')) != NULL) *p++ = 0;
177 isaddr = inet_aton(s, &addr);
178 if (p != NULL) p[-1] = ':';
179 if (!isaddr) {
180 hp = gethostbyname(s);
181 if (hp == NULL) {
182 fprintf(stderr,"Error in looking up server name:\n");
183 hperror(h_errno);
184 exit(1);
186 memcpy(&_res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ);
187 printf("Using domain server:\n");
188 printanswer(hp);
190 else {
191 _res.nsaddr.sin_family = AF_INET;
192 _res.nsaddr.sin_addr = addr;
193 _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
194 printf("Using domain server %s:\n",
195 inet_ntoa(_res.nsaddr.sin_addr));
199 domain = v[1];
200 if (strcmp (domain, ".") != 0 && inet_aton(domain, &addr)) {
201 static char ipname[sizeof("255.255.255.255.in-addr.arpa.")];
202 sprintf(ipname, "%d.%d.%d.%d.in-addr.arpa.",
203 ((unsigned char *) &addr)[3],
204 ((unsigned char *) &addr)[2],
205 ((unsigned char *) &addr)[1],
206 ((unsigned char *) &addr)[0]);
207 domain = ipname;
208 getdeftype = T_PTR;
211 hp = NULL;
212 h_errno = TRY_AGAIN;
214 * we handle default domains ourselves, thank you
216 _res.options &= ~RES_DEFNAMES;
218 if (list)
219 exit(ListHosts(domain, gettype ? gettype : getdeftype));
220 oldcname = NULL;
221 ncnames = 5;
222 while (hp == NULL && h_errno == TRY_AGAIN) {
223 cname = NULL;
224 if (oldcname == NULL)
225 hp = (struct hostent *)gethostinfo(domain);
226 else
227 hp = (struct hostent *)gethostinfo((char *)oldcname);
228 if (cname) {
229 if (ncnames-- == 0) {
230 printf("Too many cnames. Possible loop.\n");
231 exit(1);
233 oldcname = cname;
234 hp = NULL;
235 h_errno = TRY_AGAIN;
236 continue;
238 if (!waitmode)
239 break;
242 if (hp == NULL) {
243 hperror(h_errno);
244 exit(1);
247 exit(0);
251 static int
252 parsetype(s)
253 char *s;
255 if (strcmp(s,"a") == 0)
256 return(1);
257 if (strcmp(s,"ns") == 0)
258 return(2);
259 if (strcmp(s,"md") == 0)
260 return(3);
261 if (strcmp(s,"mf") == 0)
262 return(4);
263 if (strcmp(s,"cname") == 0)
264 return(5);
265 if (strcmp(s,"soa") == 0)
266 return(6);
267 if (strcmp(s,"mb") == 0)
268 return(7);
269 if (strcmp(s,"mg") == 0)
270 return(8);
271 if (strcmp(s,"mr") == 0)
272 return(9);
273 if (strcmp(s,"null") == 0)
274 return(10);
275 if (strcmp(s,"wks") == 0)
276 return(11);
277 if (strcmp(s,"ptr") == 0)
278 return(12);
279 if (strcmp(s,"hinfo") == 0)
280 return(13);
281 if (strcmp(s,"minfo") == 0)
282 return(14);
283 if (strcmp(s,"mx") == 0)
284 return(15);
285 if (strcmp(s,"txt") == 0) /* Roy */
286 return(T_TXT); /* Roy */
287 if (strcmp(s,"uinfo") == 0)
288 return(100);
289 if (strcmp(s,"uid") == 0)
290 return(101);
291 if (strcmp(s,"gid") == 0)
292 return(102);
293 if (strcmp(s,"unspec") == 0)
294 return(103);
295 if (strcmp(s,"any") == 0)
296 return(255);
297 if (strcmp(s,"*") == 0)
298 return(255);
299 if (atoi(s))
300 return(atoi(s));
301 fprintf(stderr, "Invalid query type: %s\n", s);
302 exit(2);
305 static int
306 parseclass(s)
307 char *s;
309 if (strcmp(s,"in") == 0)
310 return(C_IN);
311 if (strcmp(s,"chaos") == 0)
312 return(C_CHAOS);
313 if (strcmp(s,"hs") == 0)
314 return(C_HS);
315 if (strcmp(s,"any") == 0)
316 return(C_ANY);
317 if (atoi(s))
318 return(atoi(s));
319 fprintf(stderr, "Invalid query class: %s\n", s);
320 exit(2);
323 static void
324 printanswer(hp)
325 register struct hostent *hp;
327 register char **cp;
328 struct in_addr **hptr;
330 printf("Name: %s\n", hp->h_name);
331 printf("Address:");
332 for (hptr = (struct in_addr **)hp->h_addr_list; *hptr; hptr++)
333 printf(" %s", inet_ntoa(**hptr));
334 printf("\nAliases:");
335 for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
336 printf(" %s", *cp);
337 printf("\n\n");
340 static void
341 hperror(err_no)
342 int err_no;
344 switch(err_no) {
345 case HOST_NOT_FOUND:
346 fprintf(stderr,"Host not found.\n");
347 break;
348 case TRY_AGAIN:
349 fprintf(stderr,"Host not found, try again.\n");
350 break;
351 case NO_RECOVERY:
352 fprintf(stderr,"No recovery, Host not found.\n");
353 break;
354 case NO_ADDRESS:
355 fprintf(stderr,"There is an entry for this host, but it doesn't have what you requested.\n");
356 break;
360 typedef union querybuf {
361 HEADER qb1;
362 u8_t qb2[PACKETSZ];
363 } querybuf_t;
365 static u8_t hostbuf[BUFSIZ+1];
368 static int
369 gethostinfo(name)
370 char *name;
372 register char *cp, **domain;
373 int n;
374 int hp;
375 int nDomain;
377 if (strcmp(name, ".") == 0)
378 return(getdomaininfo(name, NULL));
379 for (cp = name, n = 0; *cp; cp++)
380 if (*cp == '.')
381 n++;
382 if (n && cp[-1] == '.') {
383 if (cp[-1] == '.')
384 cp[-1] = 0;
385 hp = getdomaininfo(name, (char *)NULL);
386 if (cp[-1] == 0)
387 cp[-1] = '.';
388 return (hp);
390 if (n == 0 && (cp = __hostalias(name))) {
391 if (verbose)
392 printf("Aliased to \"%s\"\n", cp);
393 _res.options |= RES_DEFNAMES;
394 return (getdomaininfo(cp, (char *)NULL));
396 #ifdef MAXDS
397 for (nDomain = 0;
398 _res.defdname_list[nDomain][0] != 0;
399 nDomain++) {
400 for (domain = _res.dnsrch_list[nDomain]; *domain; domain++) {
401 if (verbose)
402 printf("Trying domain \"%s\"\n", *domain);
403 hp = getdomaininfo(name, *domain);
404 if (hp)
405 return (hp);
408 #else
409 for (domain = _res.dnsrch; *domain; domain++) {
410 if (verbose)
411 printf("Trying domain \"%s\"\n", *domain);
412 hp = getdomaininfo(name, *domain);
413 if (hp)
414 return (hp);
416 #endif
417 if (h_errno != HOST_NOT_FOUND ||
418 (_res.options & RES_DNSRCH) == 0)
419 return (0);
420 if (verbose)
421 printf("Trying null domain\n");
422 return (getdomaininfo(name, (char *)NULL));
425 static int
426 getdomaininfo(name, domain)
427 char *name, *domain;
429 return getinfo(name, domain, gettype ? gettype : getdeftype);
432 static int
433 getinfo(name, domain, type)
434 char *name, *domain;
437 HEADER *hp;
438 u8_t *eom, *bp, *cp;
439 querybuf_t buf, answer;
440 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
441 char host[2*MAXDNAME+2];
443 if (domain == NULL)
444 (void)sprintf(host, "%.*s", MAXDNAME, name);
445 else
446 (void)sprintf(host, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
448 n = res_mkquery(QUERY, host, getclass, type, (char *)NULL, 0, NULL,
449 (char *)&buf, sizeof(buf));
450 if (n < 0) {
451 if (_res.options & RES_DEBUG)
452 printf("res_mkquery failed\n");
453 h_errno = NO_RECOVERY;
454 return(0);
456 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
457 if (n < 0) {
458 if (_res.options & RES_DEBUG)
459 printf("res_send failed\n");
460 h_errno = TRY_AGAIN;
461 return (0);
463 eom = (u8_t *)&answer + n;
464 return(printinfo(&answer, eom, T_ANY, 0));
467 static int
468 printinfo(answer, eom, filter, isls)
469 querybuf_t *answer;
470 u8_t *eom;
471 int filter;
472 int isls;
474 HEADER *hp;
475 u8_t *bp, *cp;
476 int nmx, ancount, nscount, arcount, qdcount, buflen;
479 * find first satisfactory answer
481 hp = (HEADER *) answer;
482 ancount = ntohs(hp->ancount);
483 qdcount = ntohs(hp->qdcount);
484 nscount = ntohs(hp->nscount);
485 arcount = ntohs(hp->arcount);
486 if (_res.options & RES_DEBUG || (verbose && isls == 0))
487 printf("rcode = %d (%s), ancount=%d\n",
488 hp->rcode,
489 DecodeError(hp->rcode),
490 ancount);
491 if (hp->rcode != NOERROR || (ancount+nscount+arcount) == 0) {
492 switch (hp->rcode) {
493 case NXDOMAIN:
494 /* Check if it's an authoritive answer */
495 if (hp->aa) {
496 h_errno = HOST_NOT_FOUND;
497 return(0);
498 } else {
499 h_errno = TRY_AGAIN;
500 return(0);
502 case SERVFAIL:
503 h_errno = TRY_AGAIN;
504 return(0);
505 #ifdef OLDJEEVES
507 * Jeeves (TOPS-20 server) still does not
508 * support MX records. For the time being,
509 * we must accept FORMERRs as the same as
510 * NOERROR.
512 case FORMERR:
513 #endif /* OLDJEEVES */
514 case NOERROR:
515 /* TpB - set a return error for this case. NO_DATA */
516 h_errno = NO_DATA;
517 return(0); /* was 1,but now indicates exception */
518 #ifndef OLDJEEVES
519 case FORMERR:
520 #endif /* OLDJEEVES */
521 case NOTIMP:
522 case REFUSED:
523 h_errno = NO_RECOVERY;
524 return(0);
526 return (0);
528 bp = hostbuf;
529 nmx = 0;
530 buflen = sizeof(hostbuf);
531 cp = (u8_t *)answer + sizeof(HEADER);
532 if (qdcount) {
533 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
534 while (--qdcount > 0)
535 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
537 if (ancount) {
538 if (!hp->aa)
539 if (verbose && isls == 0)
540 printf("The following answer is not authoritative:\n");
541 while (--ancount >= 0 && cp && cp < eom) {
542 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
544 * When we ask for address and there is a CNAME, it seems to return
545 * both the CNAME and the address. Since we trace down the CNAME
546 * chain ourselves, we don't really want to print the address at
547 * this point.
549 if (cname && ! verbose)
550 return (1);
553 if (! verbose)
554 return (1);
555 if (nscount) {
556 printf("For authoritative answers, see:\n");
557 while (--nscount >= 0 && cp && cp < eom) {
558 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
561 if (arcount) {
562 printf("Additional information:\n");
563 while (--arcount >= 0 && cp && cp < eom) {
564 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
567 return(1);
570 static u8_t cnamebuf[MAXDNAME];
573 * Print resource record fields in human readable form.
575 static u8_t *
576 pr_rr(cp, msg, file, filter)
577 u8_t *cp, *msg;
578 FILE *file;
579 int filter;
581 int type, class, dlen, n, c, proto, ttl;
582 struct in_addr inaddr;
583 u8_t *cp1;
584 struct protoent *protop;
585 struct servent *servp;
586 char punc;
587 int doprint;
588 u8_t name[MAXDNAME];
590 if ((cp = pr_cdname(cp, msg, name, sizeof(name))) == NULL)
591 return (NULL); /* compression error */
593 type = _getshort(cp);
594 cp += sizeof(u_short);
596 class = _getshort(cp);
597 cp += sizeof(u_short);
599 ttl = _getlong(cp);
600 cp += sizeof(u_long);
602 if (filter == type || filter == T_ANY ||
603 (filter == T_A && (type == T_PTR || type == T_NS)))
604 doprint = 1;
605 else
606 doprint = 0;
608 if (doprint)
609 if (verbose)
610 fprintf(file,"%s\t%d%s\t%s",
611 name, ttl, pr_class(class), pr_type(type));
612 else {
613 fprintf(file,"%s%s %s",name, pr_class(class), pr_type(type));
615 if (verbose)
616 punc = '\t';
617 else
618 punc = ' ';
620 dlen = _getshort(cp);
621 cp += sizeof(u_short);
622 cp1 = cp;
624 * Print type specific data, if appropriate
626 switch (type) {
627 case T_A:
628 switch (class) {
629 case C_IN:
630 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
631 if (dlen == 4) {
632 if (doprint)
633 fprintf(file,"%c%s", punc,
634 inet_ntoa(inaddr));
635 cp += dlen;
636 } else if (dlen == 7) {
637 if (doprint) {
638 fprintf(file,"%c%s", punc,
639 inet_ntoa(inaddr));
640 fprintf(file,", protocol = %d", cp[4]);
641 fprintf(file,", port = %d",
642 (cp[5] << 8) + cp[6]);
644 cp += dlen;
646 break;
648 break;
649 case T_CNAME:
650 if (dn_expand(msg, msg + 512, cp, cnamebuf,
651 sizeof(cnamebuf)-1) >= 0) {
652 strcat((char *) cnamebuf, ".");
653 if (gettype != T_CNAME && gettype != T_ANY)
654 cname = cnamebuf;
656 case T_MB:
657 #ifdef OLDRR
658 case T_MD:
659 case T_MF:
660 #endif /* OLDRR */
661 case T_MG:
662 case T_MR:
663 case T_NS:
664 case T_PTR:
665 cp = pr_cdname(cp, msg, name, sizeof(name));
666 if (doprint)
667 fprintf(file,"%c%s",punc, name);
668 break;
670 case T_HINFO:
671 if ((n = *cp++)) {
672 if (doprint)
673 fprintf(file,"%c%.*s", punc, n, cp);
674 cp += n;
676 if ((n = *cp++)) {
677 if (doprint)
678 fprintf(file,"%c%.*s", punc, n, cp);
679 cp += n;
681 break;
683 case T_SOA:
684 cp = pr_cdname(cp, msg, name, sizeof(name));
685 if (doprint)
686 fprintf(file,"\t%s", name);
687 cp = pr_cdname(cp, msg, name, sizeof(name));
688 if (doprint)
689 fprintf(file," %s", name);
690 if (doprint)
691 fprintf(file,"(\n\t\t\t%d\t;serial (version)", _getlong(cp));
692 cp += sizeof(u_long);
693 if (doprint)
694 fprintf(file,"\n\t\t\t%d\t;refresh period", _getlong(cp));
695 cp += sizeof(u_long);
696 if (doprint)
697 fprintf(file,"\n\t\t\t%d\t;retry refresh this often", _getlong(cp));
698 cp += sizeof(u_long);
699 if (doprint)
700 fprintf(file,"\n\t\t\t%d\t;expiration period", _getlong(cp));
701 cp += sizeof(u_long);
702 if (doprint)
703 fprintf(file,"\n\t\t\t%d\t;minimum TTL\n\t\t\t)", _getlong(cp));
704 cp += sizeof(u_long);
705 break;
707 case T_MX:
708 if (doprint) {
709 if (verbose)
710 fprintf(file,"\t%d ",_getshort(cp));
711 else
712 fprintf(file," (pri=%d) by ",_getshort(cp));
714 cp += sizeof(u_short);
715 cp = pr_cdname(cp, msg, name, sizeof(name));
716 if (doprint)
717 fprintf(file, "%s", name);
718 break;
720 case T_MINFO:
721 cp = pr_cdname(cp, msg, name, sizeof(name));
722 if (doprint)
723 fprintf(file,"%c%s",punc, name);
724 cp = pr_cdname(cp, msg, name, sizeof(name));
725 if (doprint)
726 fprintf(file," %s", name);
727 break;
729 /* Roy start */
730 case T_TXT:
731 if ((n = *cp++)) {
732 if (doprint)
733 fprintf(file,"%c%.*s", punc, n, cp);
734 cp += n;
736 break;
737 /* Roy end */
738 case T_WKS:
739 if (dlen < sizeof(u_long) + 1)
740 break;
741 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
742 cp += sizeof(u_long);
743 proto = *cp++;
744 protop = getprotobynumber(proto);
745 if (doprint)
746 if (protop)
747 fprintf(file,"%c%s %s", punc,
748 inet_ntoa(inaddr), protop->p_name);
749 else
750 fprintf(file,"%c%s %d", punc,
751 inet_ntoa(inaddr), proto);
753 n = 0;
754 while (cp < cp1 + dlen) {
755 c = *cp++;
756 do {
757 if (c & 0200) {
758 servp = NULL;
759 if (protop)
760 servp = getservbyport (htons(n),
761 protop->p_name);
762 if (doprint)
763 if (servp)
764 fprintf(file, " %s", servp->s_name);
765 else
766 fprintf(file, " %d", n);
768 c <<= 1;
769 } while (++n & 07);
771 break;
773 default:
774 if (doprint)
775 fprintf(file,"%c???", punc);
776 cp += dlen;
778 if (cp != cp1 + dlen)
779 fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
780 if (doprint)
781 fprintf(file,"\n");
782 return (cp);
785 static char nbuf[20];
788 * Return a string for the type
790 static char *
791 pr_type(type)
792 int type;
794 switch (type) {
795 case T_A:
796 return(verbose? "A" : "has address");
797 case T_NS: /* authoritative server */
798 return("NS");
799 #ifdef OLDRR
800 case T_MD: /* mail destination */
801 return("MD");
802 case T_MF: /* mail forwarder */
803 return("MF");
804 #endif /* OLDRR */
805 case T_CNAME: /* connonical name */
806 return(verbose? "CNAME" : "is a nickname for");
807 case T_SOA: /* start of authority zone */
808 return("SOA");
809 case T_MB: /* mailbox domain name */
810 return("MB");
811 case T_MG: /* mail group member */
812 return("MG");
813 case T_MX: /* mail routing info */
814 return(verbose? "MX" : "mail is handled");
815 /* Roy start */
816 case T_TXT: /* TXT - descriptive info */
817 return(verbose? "TXT" : "descriptive text");
818 /* Roy end */
819 case T_MR: /* mail rename name */
820 return("MR");
821 case T_NULL: /* null resource record */
822 return("NULL");
823 case T_WKS: /* well known service */
824 return("WKS");
825 case T_PTR: /* domain name pointer */
826 return("PTR");
827 case T_HINFO: /* host information */
828 return("HINFO");
829 case T_MINFO: /* mailbox information */
830 return("MINFO");
831 case T_AXFR: /* zone transfer */
832 return("AXFR");
833 case T_MAILB: /* mail box */
834 return("MAILB");
835 case T_MAILA: /* mail address */
836 return("MAILA");
837 case T_ANY: /* matches any type */
838 return("ANY");
839 default:
840 return (sprintf(nbuf, "%d", type) == EOF ? NULL : nbuf);
845 * Return a mnemonic for class
847 static char *
848 pr_class(class)
849 int class;
852 switch (class) {
853 case C_IN: /* internet class */
854 return(verbose? " IN" : "");
855 case C_CHAOS: /* chaos class */
856 return(verbose? " CHAOS" : "");
857 case C_HS: /* Hesiod class */
858 return(verbose? " HS" : "");
859 case C_ANY: /* matches any class */
860 return(" ANY");
861 default:
862 return (sprintf(nbuf," %d", class) == EOF ? NULL : nbuf);
866 static u8_t *
867 pr_cdname(cp, msg, name, namelen)
868 u8_t *cp, *msg;
869 u8_t *name;
870 int namelen;
872 int n;
874 if ((n = dn_expand(msg, msg + 512, cp, name, namelen - 2)) < 0)
875 return (NULL);
876 if (name[0] == '\0') {
877 name[0] = '.';
878 name[1] = '\0';
880 return (cp + n);
883 char *resultcodes[] = {
884 "NOERROR",
885 "FORMERR",
886 "SERVFAIL",
887 "NXDOMAIN",
888 "NOTIMP",
889 "REFUSED",
890 "6",
891 "7",
892 "8",
893 "9",
894 "10",
895 "11",
896 "12",
897 "13",
898 "14",
899 "NOCHANGE",
905 ******************************************************************************
907 * ListHosts --
909 * Requests the name server to do a zone transfer so we
910 * find out what hosts it knows about.
912 * Results:
913 * SUCCESS the listing was successful.
914 * ERROR the server could not be contacted because
915 * a socket could not be obtained or an error
916 * occured while receiving, or the output file
917 * could not be opened.
919 ******************************************************************************
922 static int
923 ListHosts(namePtr, queryType)
924 char *namePtr;
925 int queryType; /* e.g. T_A */
927 querybuf_t buf, answer;
928 HEADER *headerPtr;
930 int msglen;
931 int amtToRead;
932 int numRead;
933 int i;
934 int numAnswers = 0;
935 int result;
936 int soacnt = 0;
937 u_short len;
938 int dlen;
939 int type;
940 int nscount;
941 u8_t *cp, *nmp;
942 u8_t name[NAME_LEN];
943 char dname[2][NAME_LEN];
944 u8_t domain[NAME_LEN];
945 /* names and addresses of name servers to try */
946 #define NUMNS 8
947 char nsname[NUMNS][NAME_LEN];
948 int nshaveaddr[NUMNS];
949 #define IPADDRSIZE 4
950 #define NUMNSADDR 16
951 char nsipaddr[NUMNSADDR][IPADDRSIZE];
952 int numns;
953 int numnsaddr;
954 int thisns;
955 struct hostent *hp;
956 enum {
957 NO_ERRORS,
958 ERR_READING_LEN,
959 ERR_READING_MSG,
960 ERR_PRINTING
961 } error = NO_ERRORS;
962 char *tcp_serv_name;
963 int tcp_fd;
964 nwio_tcpconf_t tcpconf;
965 nwio_tcpcl_t clopt;
966 int terrno;
969 * normalize to not have trailing dot. We do string compares below
970 * of info from name server, and it won't have trailing dots.
972 i = strlen(namePtr);
973 if (namePtr[i-1] == '.')
974 namePtr[i-1] = 0;
976 if (server_specified) {
977 bcopy((char *)&_res.nsaddr, nsipaddr[0], IPADDRSIZE);
978 numnsaddr = 1;
980 else {
983 * First we have to find out where to look. This needs a NS query,
984 * possibly followed by looking up addresses for some of the names.
987 msglen = res_mkquery(QUERY, namePtr, C_IN, T_NS,
988 (char *)0, 0, (struct rrec *)0,
989 (char *)&buf, sizeof(buf));
991 if (msglen < 0) {
992 printf("res_mkquery failed\n");
993 return (ERROR);
996 msglen = res_send((char *)&buf,msglen,(char *)&answer, sizeof(answer));
998 if (msglen < 0) {
999 printf("Unable to get to nameserver -- try again later\n");
1000 return (ERROR);
1002 if (_res.options & RES_DEBUG || verbose)
1003 printf("rcode = %d (%s), ancount=%d\n",
1004 answer.qb1.rcode,
1005 DecodeError(answer.qb1.rcode),
1006 ntohs(answer.qb1.ancount));
1009 * Analyze response to our NS lookup
1012 nscount = ntohs(answer.qb1.ancount) +
1013 ntohs(answer.qb1.nscount) +
1014 ntohs(answer.qb1.arcount);
1017 if (answer.qb1.rcode != NOERROR || nscount == 0) {
1018 switch (answer.qb1.rcode) {
1019 case NXDOMAIN:
1020 /* Check if it's an authoritive answer */
1021 if (answer.qb1.aa) {
1022 printf("No such domain\n");
1023 } else {
1024 printf("Unable to get information about domain -- try again later.\n");
1026 break;
1027 case SERVFAIL:
1028 printf("Unable to get information about that domain -- try again later.\n");
1029 break;
1030 case NOERROR:
1031 printf("That domain exists, but seems to be a leaf node.\n");
1032 break;
1033 case FORMERR:
1034 case NOTIMP:
1035 case REFUSED:
1036 printf("Unrecoverable error looking up domain name.\n");
1037 break;
1039 return (0);
1042 cp = answer.qb2 + sizeof(HEADER);
1043 if (ntohs(answer.qb1.qdcount) > 0)
1044 cp += dn_skipname(cp, answer.qb2 + msglen) + QFIXEDSZ;
1046 numns = 0;
1047 numnsaddr = 0;
1050 * Look at response from NS lookup for NS and A records.
1053 for (;nscount; nscount--) {
1054 cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1055 domain, sizeof(domain));
1056 type = _getshort(cp);
1057 cp += sizeof(u_short) + sizeof(u_short) + sizeof(u_long);
1058 dlen = _getshort(cp);
1059 cp += sizeof(u_short);
1060 if (type == T_NS) {
1061 if (dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1062 name, sizeof(name)) >= 0) {
1063 if (numns < NUMNS && strcasecmp((char *)domain, namePtr) == 0) {
1064 for (i = 0; i < numns; i++)
1065 if (strcasecmp(nsname[i], (char *)name) == 0)
1066 break; /* duplicate */
1067 if (i >= numns) {
1068 strncpy(nsname[numns], (char *)name, sizeof(name));
1069 nshaveaddr[numns] = 0;
1070 numns++;
1075 else if (type == T_A) {
1076 if (numnsaddr < NUMNSADDR)
1077 for (i = 0; i < numns; i++) {
1078 if (strcasecmp(nsname[i], (char *)domain) == 0) {
1079 nshaveaddr[i]++;
1080 bcopy((char *)cp, nsipaddr[numnsaddr],IPADDRSIZE);
1081 numnsaddr++;
1082 break;
1086 cp += dlen;
1090 * Usually we'll get addresses for all the servers in the additional
1091 * info section. But in case we don't, look up their addresses.
1094 for (i = 0; i < numns; i++) {
1095 if (! nshaveaddr[i]) {
1096 register long **hptr;
1097 int numaddrs = 0;
1099 hp = gethostbyname(nsname[i]);
1100 if (hp) {
1101 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
1102 if (numnsaddr < NUMNSADDR) {
1103 bcopy((char *)*hptr, nsipaddr[numnsaddr],IPADDRSIZE);
1104 numnsaddr++;
1105 numaddrs++;
1108 if (_res.options & RES_DEBUG || verbose)
1109 printf("Found %d addresses for %s by extra query\n",
1110 numaddrs, nsname[i]);
1112 else
1113 if (_res.options & RES_DEBUG || verbose)
1114 printf("Found %d addresses for %s\n",
1115 nshaveaddr[i], nsname[i]);
1119 * Now nsipaddr has numnsaddr addresses for name servers that
1120 * serve the requested domain. Now try to find one that will
1121 * accept a zone transfer.
1124 thisns = 0;
1126 again:
1128 numAnswers = 0;
1129 soacnt = 0;
1132 * Create a query packet for the requested domain name.
1135 msglen = res_mkquery(QUERY, namePtr, getclass, T_AXFR,
1136 (char *)0, 0, (struct rrec *)0,
1137 (char *) &buf, sizeof(buf));
1138 if (msglen < 0) {
1139 if (_res.options & RES_DEBUG) {
1140 fprintf(stderr, "ListHosts: Res_mkquery failed\n");
1142 return (ERROR);
1146 * Set up a virtual circuit to the server.
1149 tcp_serv_name= getenv("TCP_DEVICE");
1150 if (!tcp_serv_name)
1151 tcp_serv_name= TCP_DEVICE;
1152 for (;thisns < numnsaddr; thisns++)
1154 tcp_fd= open(tcp_serv_name, O_RDWR);
1155 if (tcp_fd == -1)
1157 fprintf(stderr, "unable to open '%s': %s\n", tcp_serv_name,
1158 strerror(errno));
1159 return ERROR;
1162 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
1163 NWTC_SET_RP;
1164 tcpconf.nwtc_remaddr= *(ipaddr_t *)nsipaddr[thisns];
1165 tcpconf.nwtc_remport= _res.nsaddr.sin_port;
1166 result= ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf);
1167 if (result == -1)
1169 fprintf(stderr, "tcp_ioc_setconf failed: %s\n",
1170 strerror(errno));
1171 close(tcp_fd);
1172 return ERROR;
1174 if (_res.options & RES_DEBUG || verbose)
1175 printf("Trying %s\n", inet_ntoa(tcpconf.nwtc_remaddr));
1176 clopt.nwtcl_flags= 0;
1177 result= ioctl(tcp_fd, NWIOTCPCONN, &clopt);
1178 if (result == 0)
1179 break;
1180 terrno= errno;
1181 if (verbose)
1182 fprintf(stderr,
1183 "Connection failed, trying next server: %s\n",
1184 strerror(errno));
1185 close(tcp_fd);
1187 if (thisns >= numnsaddr) {
1188 printf("No server for that domain responded\n");
1189 if (!verbose)
1190 fprintf(stderr, "Error from the last server was: %s\n",
1191 strerror(terrno));
1192 return(ERROR);
1196 * Send length & message for zone transfer
1199 len = htons(msglen);
1201 result= tcpip_writeall(tcp_fd, (char *)&len, sizeof(len));
1202 if (result != sizeof(len))
1204 fprintf(stderr, "write failed: %s\n", strerror(errno));
1205 close(tcp_fd);
1206 return ERROR;
1208 result= tcpip_writeall(tcp_fd, (char *)&buf, msglen);
1209 if (result != msglen)
1211 fprintf(stderr, "write failed: %s\n",
1212 strerror(errno));
1213 close(tcp_fd);
1214 return ERROR;
1216 filePtr = stdout;
1218 while (1) {
1221 * Read the length of the response.
1224 cp = (u8_t *) &buf;
1225 amtToRead = sizeof(u_short);
1226 while(amtToRead > 0)
1228 result = read(tcp_fd, (char *)cp, amtToRead);
1229 if (result <= 0)
1230 break;
1231 cp += result;
1232 amtToRead -= result;
1234 if (amtToRead) {
1235 error = ERR_READING_LEN;
1236 break;
1239 if ((len = htons(*(u_short *)&buf)) == 0) {
1240 break; /* nothing left to read */
1244 * Read the response.
1247 amtToRead = len;
1248 cp = (u8_t *) &buf;
1249 while(amtToRead > 0)
1251 result = read(tcp_fd, (char *)cp, amtToRead);
1252 if (result<= 0)
1253 break;
1254 cp += result;
1255 amtToRead -= result;
1257 if (amtToRead) {
1258 error = ERR_READING_MSG;
1259 break;
1262 i = buf.qb1.rcode;
1264 if (i != NOERROR || ntohs(buf.qb1.ancount) == 0) {
1265 if ((thisns+1) < numnsaddr &&
1266 (i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
1267 if (_res.options & RES_DEBUG || verbose)
1268 printf("Server failed, trying next server: %s\n",
1269 i != NOERROR ?
1270 DecodeError(i) : "Premature end of data");
1271 close(tcp_fd);
1272 thisns++;
1273 goto again;
1275 printf("Server failed: %s\n",
1276 i != NOERROR ? DecodeError(i) : "Premature end of data");
1277 break;
1281 result = printinfo(&buf, cp, queryType, 1);
1282 if (! result) {
1283 error = ERR_PRINTING;
1284 break;
1286 numAnswers++;
1287 cp = buf.qb2 + sizeof(HEADER);
1288 if (ntohs(buf.qb1.qdcount) > 0)
1289 cp += dn_skipname(cp, buf.qb2 + len) + QFIXEDSZ;
1291 nmp = cp;
1292 cp += dn_skipname(cp, (u_char *)&buf + len);
1293 if ((_getshort(cp) == T_SOA)) {
1294 dn_expand(buf.qb2, buf.qb2 + len, nmp, (u8_t *)dname[soacnt],
1295 sizeof(dname[0]));
1296 if (soacnt) {
1297 if (strcmp(dname[0], dname[1]) == 0)
1298 break;
1299 } else
1300 soacnt++;
1304 close(tcp_fd);
1306 switch (error) {
1307 case NO_ERRORS:
1308 return (SUCCESS);
1310 case ERR_READING_LEN:
1311 return(ERROR);
1313 case ERR_PRINTING:
1314 fprintf(stderr,"*** Error during listing of %s: %s\n",
1315 namePtr, DecodeError(result));
1316 return(result);
1318 case ERR_READING_MSG:
1319 headerPtr = (HEADER *) &buf;
1320 fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
1321 fprintf(stderr,
1322 " result: %s, answers = %d, authority = %d, additional = %d\n",
1323 resultcodes[headerPtr->rcode],
1324 ntohs(headerPtr->ancount),
1325 ntohs(headerPtr->nscount),
1326 ntohs(headerPtr->arcount));
1327 return(ERROR);
1328 default:
1329 return(ERROR);
1333 static char *
1334 DecodeError(result)
1335 int result;
1337 switch(result) {
1338 case NOERROR: return("Success"); break;
1339 case FORMERR: return("Format error"); break;
1340 case SERVFAIL: return("Server failed"); break;
1341 case NXDOMAIN: return("Non-existent domain"); break;
1342 case NOTIMP: return("Not implemented"); break;
1343 case REFUSED: return("Query refused"); break;
1344 case NOCHANGE: return("No change"); break;
1345 case NO_INFO: return("No information"); break;
1346 case ERROR: return("Unspecified error"); break;
1347 case TIME_OUT: return("Timed out"); break;
1348 case NONAUTH: return("Non-authoritative answer"); break;
1349 default: break;
1351 return("BAD ERROR VALUE");
1354 static int tcpip_writeall(fd, buf, siz)
1355 int fd;
1356 char *buf;
1357 unsigned siz;
1359 unsigned siz_org;
1360 int nbytes;
1362 siz_org= siz;
1364 while (siz)
1366 nbytes= write(fd, buf, siz);
1367 if (nbytes == -1)
1368 return nbytes;
1369 assert(siz >= nbytes);
1370 buf += nbytes;
1371 siz -= nbytes;
1373 return siz_org;