kernel: restore setting KTS_NONE
[minix.git] / commands / host / host.c
blob0a5fa787e0fff423a18abc85d41f9574a819b88c
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 #if _MINIX && !defined(__NBSD_LIBC)
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
30 #include <net/hton.h>
31 #include <net/netlib.h>
32 #include <net/gen/in.h>
33 #include <net/gen/inet.h>
34 #include <net/gen/netdb.h>
35 #include <net/gen/nameser.h>
36 #include <net/gen/resolv.h>
37 #include <net/gen/socket.h>
38 #include <net/gen/tcp.h>
39 #include <net/gen/tcp_io.h>
41 #undef ERROR
42 #else
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <arpa/nameser.h>
46 #include <netdb.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <resolv.h>
50 #include <sys/param.h>
51 #include <strings.h>
52 #include <ctype.h>
54 #include <assert.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <sys/ioctl.h>
58 #include <sys/ioc_net.h>
59 #include <net/netlib.h>
60 #include <net/gen/in.h>
61 #include <net/gen/tcp.h>
62 #include <net/gen/tcp_io.h>
63 #endif
65 extern int h_errno;
67 #define NUMMX 50
69 #define SUCCESS 0
70 #define TIME_OUT -1
71 #define NO_INFO -2
72 #define ERROR -3
73 #define NONAUTH -4
75 #define NAME_LEN 256
77 #ifndef T_TXT
78 #define T_TXT 16
79 #endif
80 #ifndef NO_DATA
81 #define NO_DATA NO_ADDRESS
82 #endif
83 #ifndef C_HS
84 #define C_HS 4
85 #endif
86 #ifndef NOCHANGE
87 #define NOCHANGE 0xf
88 #endif
90 FILE *filePtr;
92 #ifdef __NBSD_LIBC
93 static struct __res_state orig;
94 #else
95 struct state orig;
96 extern struct state _res;
97 #endif
98 static u8_t *cname = NULL;
99 int getclass = C_IN;
100 int gettype, getdeftype = T_A;
101 int verbose = 0;
102 int list = 0;
103 int server_specified = 0;
105 union querybuf;
107 int main( int c, char *v[] );
109 static int parsetype( char *s );
110 static int parseclass( char *s );
111 static void hperror( int err_no );
112 static void printanswer( struct hostent *hp );
113 static int ListHosts( char *namePtr, int queryType );
114 static int gethostinfo( char *name );
115 static int getdomaininfo( char *name, char *domain );
116 static int getinfo( char *name, char *domain, int type );
117 static int printinfo( union querybuf *answer, u8_t *eom, int filter, int
118 isls );
119 static char *DecodeError( int result );
120 static u8_t *pr_rr( u8_t *cp, u8_t *msg, FILE *file, int filter );
121 static u8_t * pr_cdname( u8_t *cp, u8_t *msg, u8_t *name, int namelen );
122 static char *pr_class( int class );
123 static char *pr_type( int type );
124 static int tcpip_writeall( int fd, char *buf, unsigned siz );
127 main(c, v)
128 char **v;
130 char *domain;
131 #ifdef __NBSD_LIBC
132 struct in_addr addr;
133 #else
134 ipaddr_t addr;
135 #endif
136 register struct hostent *hp;
137 register char *s, *p;
138 register inverse = 0;
139 register waitmode = 0;
140 u8_t *oldcname;
141 int ncnames;
142 int isaddr;
144 res_init();
145 _res.retrans = 5;
147 if (c < 2) {
148 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");
149 exit(1);
151 while (c > 2 && v[1][0] == '-') {
152 if (strcmp (v[1], "-w") == 0) {
153 _res.retry = 1;
154 _res.retrans = 15;
155 waitmode = 1;
156 v++;
157 c--;
159 else if (strcmp (v[1], "-r") == 0) {
160 _res.options &= ~RES_RECURSE;
161 v++;
162 c--;
164 else if (strcmp (v[1], "-d") == 0) {
165 _res.options |= RES_DEBUG;
166 v++;
167 c--;
169 else if (strcmp (v[1], "-v") == 0) {
170 verbose = 1;
171 v++;
172 c--;
174 else if (strcmp (v[1], "-l") == 0) {
175 list = 1;
176 v++;
177 c--;
179 else if (strncmp (v[1], "-t", 2) == 0) {
180 v++;
181 c--;
182 gettype = parsetype(v[1]);
183 v++;
184 c--;
186 else if (strncmp (v[1], "-c", 2) == 0) {
187 v++;
188 c--;
189 getclass = parseclass(v[1]);
190 v++;
191 c--;
193 else if (strcmp (v[1], "-a") == 0) {
194 verbose = 1;
195 gettype = T_ANY;
196 v++;
197 c--;
199 else if (strcmp (v[1], "-V") == 0) {
200 _res.options |= RES_USEVC;
201 v++;
202 c--;
205 if (c > 2) {
206 s = v[2];
207 server_specified++;
209 if ((p = strchr(s, ':')) != NULL) *p++ = 0;
210 isaddr = inet_aton(s, &addr);
211 if (p != NULL) p[-1] = ':';
212 if (!isaddr) {
213 hp = gethostbyname(s);
214 if (hp == NULL) {
215 fprintf(stderr,"Error in looking up server name:\n");
216 hperror(h_errno);
217 exit(1);
219 #ifdef __NBSD_LIBC
220 memcpy(&_res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ);
221 #else
222 _res.nsaddr= *(ipaddr_t *)hp->h_addr;
223 #endif
224 printf("Using domain server:\n");
225 printanswer(hp);
227 else {
228 #ifdef __NBSD_LIBC
229 _res.nsaddr.sin_family = AF_INET;
230 _res.nsaddr.sin_addr = addr;
231 _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
232 printf("Using domain server %s:\n",
233 inet_ntoa(_res.nsaddr.sin_addr));
235 #else
236 _res.nsaddr_list[0]= addr;
237 _res.nsport_list[0]= htons(NAMESERVER_PORT);
238 printf("Using domain server %s",
239 inet_ntoa(_res.nsaddr));
240 if (p != NULL) {
241 printf(" on port %d", atoi(p));
242 _res.nsport_list[0]= htons(atoi(p));
244 printf(":\n");
245 #endif
248 domain = v[1];
249 if (strcmp (domain, ".") != 0 && inet_aton(domain, &addr)) {
250 static char ipname[sizeof("255.255.255.255.in-addr.arpa.")];
251 sprintf(ipname, "%d.%d.%d.%d.in-addr.arpa.",
252 ((unsigned char *) &addr)[3],
253 ((unsigned char *) &addr)[2],
254 ((unsigned char *) &addr)[1],
255 ((unsigned char *) &addr)[0]);
256 domain = ipname;
257 getdeftype = T_PTR;
260 hp = NULL;
261 h_errno = TRY_AGAIN;
263 * we handle default domains ourselves, thank you
265 _res.options &= ~RES_DEFNAMES;
267 if (list)
268 exit(ListHosts(domain, gettype ? gettype : getdeftype));
269 oldcname = NULL;
270 ncnames = 5;
271 while (hp == NULL && h_errno == TRY_AGAIN) {
272 cname = NULL;
273 if (oldcname == NULL)
274 hp = (struct hostent *)gethostinfo(domain);
275 else
276 hp = (struct hostent *)gethostinfo((char *)oldcname);
277 if (cname) {
278 if (ncnames-- == 0) {
279 printf("Too many cnames. Possible loop.\n");
280 exit(1);
282 oldcname = cname;
283 hp = NULL;
284 h_errno = TRY_AGAIN;
285 continue;
287 if (!waitmode)
288 break;
291 if (hp == NULL) {
292 hperror(h_errno);
293 exit(1);
296 exit(0);
300 static int
301 parsetype(s)
302 char *s;
304 if (strcmp(s,"a") == 0)
305 return(1);
306 if (strcmp(s,"ns") == 0)
307 return(2);
308 if (strcmp(s,"md") == 0)
309 return(3);
310 if (strcmp(s,"mf") == 0)
311 return(4);
312 if (strcmp(s,"cname") == 0)
313 return(5);
314 if (strcmp(s,"soa") == 0)
315 return(6);
316 if (strcmp(s,"mb") == 0)
317 return(7);
318 if (strcmp(s,"mg") == 0)
319 return(8);
320 if (strcmp(s,"mr") == 0)
321 return(9);
322 if (strcmp(s,"null") == 0)
323 return(10);
324 if (strcmp(s,"wks") == 0)
325 return(11);
326 if (strcmp(s,"ptr") == 0)
327 return(12);
328 if (strcmp(s,"hinfo") == 0)
329 return(13);
330 if (strcmp(s,"minfo") == 0)
331 return(14);
332 if (strcmp(s,"mx") == 0)
333 return(15);
334 if (strcmp(s,"txt") == 0) /* Roy */
335 return(T_TXT); /* Roy */
336 if (strcmp(s,"uinfo") == 0)
337 return(100);
338 if (strcmp(s,"uid") == 0)
339 return(101);
340 if (strcmp(s,"gid") == 0)
341 return(102);
342 if (strcmp(s,"unspec") == 0)
343 return(103);
344 if (strcmp(s,"any") == 0)
345 return(255);
346 if (strcmp(s,"*") == 0)
347 return(255);
348 if (atoi(s))
349 return(atoi(s));
350 fprintf(stderr, "Invalid query type: %s\n", s);
351 exit(2);
354 static int
355 parseclass(s)
356 char *s;
358 if (strcmp(s,"in") == 0)
359 return(C_IN);
360 if (strcmp(s,"chaos") == 0)
361 return(C_CHAOS);
362 if (strcmp(s,"hs") == 0)
363 return(C_HS);
364 if (strcmp(s,"any") == 0)
365 return(C_ANY);
366 if (atoi(s))
367 return(atoi(s));
368 fprintf(stderr, "Invalid query class: %s\n", s);
369 exit(2);
372 static void
373 printanswer(hp)
374 register struct hostent *hp;
376 register char **cp;
377 #ifdef __NBSD_LIBC
378 struct in_addr **hptr;
379 #else
380 register ipaddr_t **hptr;
381 #endif
383 printf("Name: %s\n", hp->h_name);
384 printf("Address:");
385 #ifdef __NBSD_LIBC
386 for (hptr = (struct in_addr **)hp->h_addr_list; *hptr; hptr++)
387 printf(" %s", inet_ntoa(**hptr));
388 #else
389 for (hptr = (ipaddr_t **)hp->h_addr_list; *hptr; hptr++)
390 printf(" %s", inet_ntoa(*(ipaddr_t *)*hptr));
391 #endif
392 printf("\nAliases:");
393 for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
394 printf(" %s", *cp);
395 printf("\n\n");
398 static void
399 hperror(err_no)
400 int err_no;
402 switch(err_no) {
403 case HOST_NOT_FOUND:
404 fprintf(stderr,"Host not found.\n");
405 break;
406 case TRY_AGAIN:
407 fprintf(stderr,"Host not found, try again.\n");
408 break;
409 case NO_RECOVERY:
410 fprintf(stderr,"No recovery, Host not found.\n");
411 break;
412 case NO_ADDRESS:
413 fprintf(stderr,"There is an entry for this host, but it doesn't have what you requested.\n");
414 break;
418 typedef union querybuf {
419 HEADER qb1;
420 u8_t qb2[PACKETSZ];
421 } querybuf_t;
423 static u8_t hostbuf[BUFSIZ+1];
426 static int
427 gethostinfo(name)
428 char *name;
430 register char *cp, **domain;
431 int n;
432 int hp;
433 int nDomain;
435 if (strcmp(name, ".") == 0)
436 return(getdomaininfo(name, NULL));
437 for (cp = name, n = 0; *cp; cp++)
438 if (*cp == '.')
439 n++;
440 if (n && cp[-1] == '.') {
441 if (cp[-1] == '.')
442 cp[-1] = 0;
443 hp = getdomaininfo(name, (char *)NULL);
444 if (cp[-1] == 0)
445 cp[-1] = '.';
446 return (hp);
448 if (n == 0 && (cp = __hostalias(name))) {
449 if (verbose)
450 printf("Aliased to \"%s\"\n", cp);
451 _res.options |= RES_DEFNAMES;
452 return (getdomaininfo(cp, (char *)NULL));
454 #ifdef MAXDS
455 for (nDomain = 0;
456 _res.defdname_list[nDomain][0] != 0;
457 nDomain++) {
458 for (domain = _res.dnsrch_list[nDomain]; *domain; domain++) {
459 if (verbose)
460 printf("Trying domain \"%s\"\n", *domain);
461 hp = getdomaininfo(name, *domain);
462 if (hp)
463 return (hp);
466 #else
467 for (domain = _res.dnsrch; *domain; domain++) {
468 if (verbose)
469 printf("Trying domain \"%s\"\n", *domain);
470 hp = getdomaininfo(name, *domain);
471 if (hp)
472 return (hp);
474 #endif
475 if (h_errno != HOST_NOT_FOUND ||
476 (_res.options & RES_DNSRCH) == 0)
477 return (0);
478 if (verbose)
479 printf("Trying null domain\n");
480 return (getdomaininfo(name, (char *)NULL));
483 static int
484 getdomaininfo(name, domain)
485 char *name, *domain;
487 return getinfo(name, domain, gettype ? gettype : getdeftype);
490 static int
491 getinfo(name, domain, type)
492 char *name, *domain;
495 HEADER *hp;
496 u8_t *eom, *bp, *cp;
497 querybuf_t buf, answer;
498 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
499 u_short pref, class;
500 char host[2*MAXDNAME+2];
502 if (domain == NULL)
503 (void)sprintf(host, "%.*s", MAXDNAME, name);
504 else
505 (void)sprintf(host, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
507 n = res_mkquery(QUERY, host, getclass, type, (char *)NULL, 0, NULL,
508 (char *)&buf, sizeof(buf));
509 if (n < 0) {
510 if (_res.options & RES_DEBUG)
511 printf("res_mkquery failed\n");
512 h_errno = NO_RECOVERY;
513 return(0);
515 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
516 if (n < 0) {
517 if (_res.options & RES_DEBUG)
518 printf("res_send failed\n");
519 h_errno = TRY_AGAIN;
520 return (0);
522 eom = (u8_t *)&answer + n;
523 return(printinfo(&answer, eom, T_ANY, 0));
526 static int
527 printinfo(answer, eom, filter, isls)
528 querybuf_t *answer;
529 u8_t *eom;
530 int filter;
531 int isls;
533 HEADER *hp;
534 u8_t *bp, *cp;
535 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
536 u_short pref, class;
539 * find first satisfactory answer
541 hp = (HEADER *) answer;
542 ancount = ntohs(hp->dh_ancount);
543 qdcount = ntohs(hp->dh_qdcount);
544 nscount = ntohs(hp->dh_nscount);
545 arcount = ntohs(hp->dh_arcount);
546 if (_res.options & RES_DEBUG || (verbose && isls == 0))
547 printf("rcode = %d (%s), ancount=%d\n",
548 #ifdef __NBSD_LIBC
549 hp->rcode,
550 DecodeError(hp->rcode),
551 #else
552 hp->dh_flag2 & DHF_RCODE,
553 DecodeError(hp->dh_flag2 & DHF_RCODE),
554 #endif
555 ancount);
556 if (
557 #ifdef __NBSD_LIBC
558 hp->rcode != NOERROR ||
559 #else
560 hp->dh_flag2 & DHF_RCODE != NOERROR ||
561 #endif
562 (ancount+nscount+arcount) == 0) {
563 switch (
564 #ifdef __NBSD_LIBC
565 hp->rcode
566 #else
567 hp->dh_flag2 & DHF_RCODE
568 #endif
570 case NXDOMAIN:
571 /* Check if it's an authoritive answer */
572 if (
573 #ifdef __NBSD_LIBC
574 hp->aa
575 #else
576 hp->dh_flag1 & DHF_AA
577 #endif
579 h_errno = HOST_NOT_FOUND;
580 return(0);
581 } else {
582 h_errno = TRY_AGAIN;
583 return(0);
585 case SERVFAIL:
586 h_errno = TRY_AGAIN;
587 return(0);
588 #ifdef OLDJEEVES
590 * Jeeves (TOPS-20 server) still does not
591 * support MX records. For the time being,
592 * we must accept FORMERRs as the same as
593 * NOERROR.
595 case FORMERR:
596 #endif /* OLDJEEVES */
597 case NOERROR:
598 /* TpB - set a return error for this case. NO_DATA */
599 h_errno = NO_DATA;
600 return(0); /* was 1,but now indicates exception */
601 #ifndef OLDJEEVES
602 case FORMERR:
603 #endif /* OLDJEEVES */
604 case NOTIMP:
605 case REFUSED:
606 h_errno = NO_RECOVERY;
607 return(0);
609 return (0);
611 bp = hostbuf;
612 nmx = 0;
613 buflen = sizeof(hostbuf);
614 cp = (u8_t *)answer + sizeof(HEADER);
615 if (qdcount) {
616 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
617 while (--qdcount > 0)
618 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
620 if (ancount) {
621 if (!
622 #ifdef __NBSD_LIBC
623 hp->aa
624 #else
625 (hp->dh_flag1 & DHF_AA)
626 #endif
628 if (verbose && isls == 0)
629 printf("The following answer is not authoritative:\n");
630 while (--ancount >= 0 && cp && cp < eom) {
631 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
633 * When we ask for address and there is a CNAME, it seems to return
634 * both the CNAME and the address. Since we trace down the CNAME
635 * chain ourselves, we don't really want to print the address at
636 * this point.
638 if (cname && ! verbose)
639 return (1);
642 if (! verbose)
643 return (1);
644 if (nscount) {
645 printf("For authoritative answers, see:\n");
646 while (--nscount >= 0 && cp && cp < eom) {
647 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
650 if (arcount) {
651 printf("Additional information:\n");
652 while (--arcount >= 0 && cp && cp < eom) {
653 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
656 return(1);
659 static u8_t cnamebuf[MAXDNAME];
662 * Print resource record fields in human readable form.
664 static u8_t *
665 pr_rr(cp, msg, file, filter)
666 u8_t *cp, *msg;
667 FILE *file;
668 int filter;
670 int type, class, dlen, n, c, proto, ttl;
671 #ifdef __NBSD_LIBC
672 struct in_addr inaddr;
673 #else
674 ipaddr_t inaddr;
675 #endif
676 u8_t *cp1;
677 struct protoent *protop;
678 struct servent *servp;
679 char punc;
680 int doprint;
681 u8_t name[MAXDNAME];
683 if ((cp = pr_cdname(cp, msg, name, sizeof(name))) == NULL)
684 return (NULL); /* compression error */
686 type = _getshort(cp);
687 cp += sizeof(u_short);
689 class = _getshort(cp);
690 cp += sizeof(u_short);
692 ttl = _getlong(cp);
693 cp += sizeof(u_long);
695 if (filter == type || filter == T_ANY ||
696 (filter == T_A && (type == T_PTR || type == T_NS)))
697 doprint = 1;
698 else
699 doprint = 0;
701 if (doprint)
702 if (verbose)
703 fprintf(file,"%s\t%d%s\t%s",
704 name, ttl, pr_class(class), pr_type(type));
705 else
706 fprintf(file,"%s%s %s",name, pr_class(class), pr_type(type));
707 if (verbose)
708 punc = '\t';
709 else
710 punc = ' ';
712 dlen = _getshort(cp);
713 cp += sizeof(u_short);
714 cp1 = cp;
716 * Print type specific data, if appropriate
718 switch (type) {
719 case T_A:
720 switch (class) {
721 case C_IN:
722 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
723 if (dlen == 4) {
724 if (doprint)
725 fprintf(file,"%c%s", punc,
726 inet_ntoa(inaddr));
727 cp += dlen;
728 } else if (dlen == 7) {
729 if (doprint) {
730 fprintf(file,"%c%s", punc,
731 inet_ntoa(inaddr));
732 fprintf(file,", protocol = %d", cp[4]);
733 fprintf(file,", port = %d",
734 (cp[5] << 8) + cp[6]);
736 cp += dlen;
738 break;
740 break;
741 case T_CNAME:
742 if (dn_expand(msg, msg + 512, cp, cnamebuf,
743 sizeof(cnamebuf)-1) >= 0) {
744 strcat((char *) cnamebuf, ".");
745 if (gettype != T_CNAME && gettype != T_ANY)
746 cname = cnamebuf;
748 case T_MB:
749 #ifdef OLDRR
750 case T_MD:
751 case T_MF:
752 #endif /* OLDRR */
753 case T_MG:
754 case T_MR:
755 case T_NS:
756 case T_PTR:
757 cp = pr_cdname(cp, msg, name, sizeof(name));
758 if (doprint)
759 fprintf(file,"%c%s",punc, name);
760 break;
762 case T_HINFO:
763 if (n = *cp++) {
764 if (doprint)
765 fprintf(file,"%c%.*s", punc, n, cp);
766 cp += n;
768 if (n = *cp++) {
769 if (doprint)
770 fprintf(file,"%c%.*s", punc, n, cp);
771 cp += n;
773 break;
775 case T_SOA:
776 cp = pr_cdname(cp, msg, name, sizeof(name));
777 if (doprint)
778 fprintf(file,"\t%s", name);
779 cp = pr_cdname(cp, msg, name, sizeof(name));
780 if (doprint)
781 fprintf(file," %s", name);
782 if (doprint)
783 fprintf(file,"(\n\t\t\t%ld\t;serial (version)", _getlong(cp));
784 cp += sizeof(u_long);
785 if (doprint)
786 fprintf(file,"\n\t\t\t%ld\t;refresh period", _getlong(cp));
787 cp += sizeof(u_long);
788 if (doprint)
789 fprintf(file,"\n\t\t\t%ld\t;retry refresh this often", _getlong(cp));
790 cp += sizeof(u_long);
791 if (doprint)
792 fprintf(file,"\n\t\t\t%ld\t;expiration period", _getlong(cp));
793 cp += sizeof(u_long);
794 if (doprint)
795 fprintf(file,"\n\t\t\t%ld\t;minimum TTL\n\t\t\t)", _getlong(cp));
796 cp += sizeof(u_long);
797 break;
799 case T_MX:
800 if (doprint)
801 if (verbose)
802 fprintf(file,"\t%d ",_getshort(cp));
803 else
804 fprintf(file," (pri=%d) by ",_getshort(cp));
805 cp += sizeof(u_short);
806 cp = pr_cdname(cp, msg, name, sizeof(name));
807 if (doprint)
808 fprintf(file, "%s", name);
809 break;
811 case T_MINFO:
812 cp = pr_cdname(cp, msg, name, sizeof(name));
813 if (doprint)
814 fprintf(file,"%c%s",punc, name);
815 cp = pr_cdname(cp, msg, name, sizeof(name));
816 if (doprint)
817 fprintf(file," %s", name);
818 break;
820 /* Roy start */
821 case T_TXT:
822 if (n = *cp++) {
823 if (doprint)
824 fprintf(file,"%c%.*s", punc, n, cp);
825 cp += n;
827 break;
828 /* Roy end */
829 #ifndef __NBSD_LIBC
830 case T_UINFO:
831 if (doprint)
832 fprintf(file,"%c%s", punc, cp);
833 cp += dlen;
834 break;
836 case T_UID:
837 case T_GID:
838 if (dlen == 4) {
839 if (doprint)
840 fprintf(file,"%c%ld", punc, _getlong(cp));
841 cp += sizeof(int);
843 break;
844 #endif
845 case T_WKS:
846 if (dlen < sizeof(u_long) + 1)
847 break;
848 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
849 cp += sizeof(u_long);
850 proto = *cp++;
851 protop = getprotobynumber(proto);
852 if (doprint)
853 if (protop)
854 fprintf(file,"%c%s %s", punc,
855 inet_ntoa(inaddr), protop->p_name);
856 else
857 fprintf(file,"%c%s %d", punc,
858 inet_ntoa(inaddr), proto);
860 n = 0;
861 while (cp < cp1 + dlen) {
862 c = *cp++;
863 do {
864 if (c & 0200) {
865 servp = NULL;
866 if (protop)
867 servp = getservbyport (htons(n),
868 protop->p_name);
869 if (doprint)
870 if (servp)
871 fprintf(file, " %s", servp->s_name);
872 else
873 fprintf(file, " %d", n);
875 c <<= 1;
876 } while (++n & 07);
878 break;
880 default:
881 if (doprint)
882 fprintf(file,"%c???", punc);
883 cp += dlen;
885 if (cp != cp1 + dlen)
886 fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
887 if (doprint)
888 fprintf(file,"\n");
889 return (cp);
892 static char nbuf[20];
895 * Return a string for the type
897 static char *
898 pr_type(type)
899 int type;
901 switch (type) {
902 case T_A:
903 return(verbose? "A" : "has address");
904 case T_NS: /* authoritative server */
905 return("NS");
906 #ifdef OLDRR
907 case T_MD: /* mail destination */
908 return("MD");
909 case T_MF: /* mail forwarder */
910 return("MF");
911 #endif /* OLDRR */
912 case T_CNAME: /* connonical name */
913 return(verbose? "CNAME" : "is a nickname for");
914 case T_SOA: /* start of authority zone */
915 return("SOA");
916 case T_MB: /* mailbox domain name */
917 return("MB");
918 case T_MG: /* mail group member */
919 return("MG");
920 case T_MX: /* mail routing info */
921 return(verbose? "MX" : "mail is handled");
922 /* Roy start */
923 case T_TXT: /* TXT - descriptive info */
924 return(verbose? "TXT" : "descriptive text");
925 /* Roy end */
926 case T_MR: /* mail rename name */
927 return("MR");
928 case T_NULL: /* null resource record */
929 return("NULL");
930 case T_WKS: /* well known service */
931 return("WKS");
932 case T_PTR: /* domain name pointer */
933 return("PTR");
934 case T_HINFO: /* host information */
935 return("HINFO");
936 case T_MINFO: /* mailbox information */
937 return("MINFO");
938 case T_AXFR: /* zone transfer */
939 return("AXFR");
940 case T_MAILB: /* mail box */
941 return("MAILB");
942 case T_MAILA: /* mail address */
943 return("MAILA");
944 case T_ANY: /* matches any type */
945 return("ANY");
946 #ifndef __NBSD_LIBC
947 case T_UINFO:
948 return("UINFO");
949 case T_UID:
950 return("UID");
951 case T_GID:
952 return("GID");
953 #endif
954 default:
955 return (sprintf(nbuf, "%d", type) == EOF ? NULL : nbuf);
960 * Return a mnemonic for class
962 static char *
963 pr_class(class)
964 int class;
967 switch (class) {
968 case C_IN: /* internet class */
969 return(verbose? " IN" : "");
970 case C_CHAOS: /* chaos class */
971 return(verbose? " CHAOS" : "");
972 case C_HS: /* Hesiod class */
973 return(verbose? " HS" : "");
974 case C_ANY: /* matches any class */
975 return(" ANY");
976 default:
977 return (sprintf(nbuf," %d", class) == EOF ? NULL : nbuf);
981 static u8_t *
982 pr_cdname(cp, msg, name, namelen)
983 u8_t *cp, *msg;
984 u8_t *name;
985 int namelen;
987 int n;
989 if ((n = dn_expand(msg, msg + 512, cp, name, namelen - 2)) < 0)
990 return (NULL);
991 if (name[0] == '\0') {
992 name[0] = '.';
993 name[1] = '\0';
995 return (cp + n);
998 char *resultcodes[] = {
999 "NOERROR",
1000 "FORMERR",
1001 "SERVFAIL",
1002 "NXDOMAIN",
1003 "NOTIMP",
1004 "REFUSED",
1005 "6",
1006 "7",
1007 "8",
1008 "9",
1009 "10",
1010 "11",
1011 "12",
1012 "13",
1013 "14",
1014 "NOCHANGE",
1020 ******************************************************************************
1022 * ListHosts --
1024 * Requests the name server to do a zone transfer so we
1025 * find out what hosts it knows about.
1027 * Results:
1028 * SUCCESS the listing was successful.
1029 * ERROR the server could not be contacted because
1030 * a socket could not be obtained or an error
1031 * occured while receiving, or the output file
1032 * could not be opened.
1034 ******************************************************************************
1037 static int
1038 ListHosts(namePtr, queryType)
1039 char *namePtr;
1040 int queryType; /* e.g. T_A */
1042 querybuf_t buf, answer;
1043 HEADER *headerPtr;
1045 int msglen;
1046 int amtToRead;
1047 int numRead;
1048 int i;
1049 int numAnswers = 0;
1050 int result;
1051 int soacnt = 0;
1052 u_short len;
1053 int dlen;
1054 int type;
1055 int nscount;
1056 u8_t *cp, *nmp;
1057 u8_t name[NAME_LEN];
1058 char dname[2][NAME_LEN];
1059 u8_t domain[NAME_LEN];
1060 /* names and addresses of name servers to try */
1061 #define NUMNS 8
1062 char nsname[NUMNS][NAME_LEN];
1063 int nshaveaddr[NUMNS];
1064 #define IPADDRSIZE 4
1065 #define NUMNSADDR 16
1066 char nsipaddr[NUMNSADDR][IPADDRSIZE];
1067 int numns;
1068 int numnsaddr;
1069 int thisns;
1070 struct hostent *hp;
1071 enum {
1072 NO_ERRORS,
1073 ERR_READING_LEN,
1074 ERR_READING_MSG,
1075 ERR_PRINTING
1076 } error = NO_ERRORS;
1077 char *tcp_serv_name;
1078 int tcp_fd;
1079 nwio_tcpconf_t tcpconf;
1080 nwio_tcpcl_t clopt;
1081 int terrno;
1084 * normalize to not have trailing dot. We do string compares below
1085 * of info from name server, and it won't have trailing dots.
1087 i = strlen(namePtr);
1088 if (namePtr[i-1] == '.')
1089 namePtr[i-1] = 0;
1091 if (server_specified) {
1092 bcopy((char *)&_res.nsaddr, nsipaddr[0], IPADDRSIZE);
1093 numnsaddr = 1;
1095 else {
1098 * First we have to find out where to look. This needs a NS query,
1099 * possibly followed by looking up addresses for some of the names.
1102 msglen = res_mkquery(QUERY, namePtr, C_IN, T_NS,
1103 (char *)0, 0, (struct rrec *)0,
1104 (char *)&buf, sizeof(buf));
1106 if (msglen < 0) {
1107 printf("res_mkquery failed\n");
1108 return (ERROR);
1111 msglen = res_send((char *)&buf,msglen,(char *)&answer, sizeof(answer));
1113 if (msglen < 0) {
1114 printf("Unable to get to nameserver -- try again later\n");
1115 return (ERROR);
1117 if (_res.options & RES_DEBUG || verbose)
1118 printf("rcode = %d (%s), ancount=%d\n",
1119 #ifdef __NBSD_LIBC
1120 answer.qb1.rcode,
1121 DecodeError(answer.qb1.rcode),
1122 ntohs(answer.qb1.ancount)
1123 #else
1124 answer.qb1.dh_flag2 & DHF_RCODE,
1125 DecodeError(answer.qb1.dh_flag2 & DHF_RCODE),
1126 ntohs(answer.qb1.dh_ancount)
1127 #endif
1131 * Analyze response to our NS lookup
1134 #ifdef __NBSD_LIBC
1135 nscount = ntohs(answer.qb1.ancount) +
1136 ntohs(answer.qb1.nscount) +
1137 ntohs(answer.qb1.arcount);
1138 #else
1139 nscount = ntohs(answer.qb1.dh_ancount) + ntohs(answer.qb1.dh_nscount) +
1140 ntohs(answer.qb1.dh_arcount);
1141 #endif
1144 if (
1145 #ifdef __NBSD_LIBC
1146 answer.qb1.rcode != NOERROR || nscount == 0
1147 #else
1148 answer.qb1.dh_flag2 & DHF_RCODE != NOERROR || nscount == 0
1149 #endif
1151 switch (
1152 #ifdef __NBSD_LIBC
1153 answer.qb1.rcode
1154 #else
1155 answer.qb1.dh_flag2 & DHF_RCODE
1156 #endif
1158 case NXDOMAIN:
1159 /* Check if it's an authoritive answer */
1160 if (
1161 #ifdef __NBSD_LIBC
1162 answer.qb1.aa
1163 #else
1164 answer.qb1.dh_flag1 & DHF_AA
1165 #endif
1168 printf("No such domain\n");
1169 } else {
1170 printf("Unable to get information about domain -- try again later.\n");
1172 break;
1173 case SERVFAIL:
1174 printf("Unable to get information about that domain -- try again later.\n");
1175 break;
1176 case NOERROR:
1177 printf("That domain exists, but seems to be a leaf node.\n");
1178 break;
1179 case FORMERR:
1180 case NOTIMP:
1181 case REFUSED:
1182 printf("Unrecoverable error looking up domain name.\n");
1183 break;
1185 return (0);
1188 cp = answer.qb2 + sizeof(HEADER);
1189 if (ntohs(answer.qb1.dh_qdcount) > 0)
1190 cp += dn_skipname(cp, answer.qb2 + msglen) + QFIXEDSZ;
1192 numns = 0;
1193 numnsaddr = 0;
1196 * Look at response from NS lookup for NS and A records.
1199 for (;nscount; nscount--) {
1200 cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1201 domain, sizeof(domain));
1202 type = _getshort(cp);
1203 cp += sizeof(u_short) + sizeof(u_short) + sizeof(u_long);
1204 dlen = _getshort(cp);
1205 cp += sizeof(u_short);
1206 if (type == T_NS) {
1207 if (dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1208 name, sizeof(name)) >= 0) {
1209 if (numns < NUMNS && strcasecmp((char *)domain, namePtr) == 0) {
1210 for (i = 0; i < numns; i++)
1211 if (strcasecmp(nsname[i], (char *)name) == 0)
1212 break; /* duplicate */
1213 if (i >= numns) {
1214 strncpy(nsname[numns], (char *)name, sizeof(name));
1215 nshaveaddr[numns] = 0;
1216 numns++;
1221 else if (type == T_A) {
1222 if (numnsaddr < NUMNSADDR)
1223 for (i = 0; i < numns; i++) {
1224 if (strcasecmp(nsname[i], (char *)domain) == 0) {
1225 nshaveaddr[i]++;
1226 bcopy((char *)cp, nsipaddr[numnsaddr],IPADDRSIZE);
1227 numnsaddr++;
1228 break;
1232 cp += dlen;
1236 * Usually we'll get addresses for all the servers in the additional
1237 * info section. But in case we don't, look up their addresses.
1240 for (i = 0; i < numns; i++) {
1241 if (! nshaveaddr[i]) {
1242 register long **hptr;
1243 int numaddrs = 0;
1245 hp = gethostbyname(nsname[i]);
1246 if (hp) {
1247 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
1248 if (numnsaddr < NUMNSADDR) {
1249 bcopy((char *)*hptr, nsipaddr[numnsaddr],IPADDRSIZE);
1250 numnsaddr++;
1251 numaddrs++;
1254 if (_res.options & RES_DEBUG || verbose)
1255 printf("Found %d addresses for %s by extra query\n",
1256 numaddrs, nsname[i]);
1258 else
1259 if (_res.options & RES_DEBUG || verbose)
1260 printf("Found %d addresses for %s\n",
1261 nshaveaddr[i], nsname[i]);
1265 * Now nsipaddr has numnsaddr addresses for name servers that
1266 * serve the requested domain. Now try to find one that will
1267 * accept a zone transfer.
1270 thisns = 0;
1272 again:
1274 numAnswers = 0;
1275 soacnt = 0;
1278 * Create a query packet for the requested domain name.
1281 msglen = res_mkquery(QUERY, namePtr, getclass, T_AXFR,
1282 (char *)0, 0, (struct rrec *)0,
1283 (char *) &buf, sizeof(buf));
1284 if (msglen < 0) {
1285 if (_res.options & RES_DEBUG) {
1286 fprintf(stderr, "ListHosts: Res_mkquery failed\n");
1288 return (ERROR);
1292 * Set up a virtual circuit to the server.
1295 tcp_serv_name= getenv("TCP_DEVICE");
1296 if (!tcp_serv_name)
1297 tcp_serv_name= TCP_DEVICE;
1298 for (;thisns < numnsaddr; thisns++)
1300 tcp_fd= open(tcp_serv_name, O_RDWR);
1301 if (tcp_fd == -1)
1303 fprintf(stderr, "unable to open '%s': %s\n", tcp_serv_name,
1304 strerror(errno));
1305 return ERROR;
1308 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
1309 NWTC_SET_RP;
1310 tcpconf.nwtc_remaddr= *(ipaddr_t *)nsipaddr[thisns];
1311 #ifdef __NBSD_LIBC
1312 tcpconf.nwtc_remport= _res.nsaddr.sin_port;
1313 #else
1314 tcpconf.nwtc_remport= _res.nsport_list[0];
1315 #endif
1316 result= ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf);
1317 if (result == -1)
1319 fprintf(stderr, "tcp_ioc_setconf failed: %s\n",
1320 strerror(errno));
1321 close(tcp_fd);
1322 return ERROR;
1324 if (_res.options & RES_DEBUG || verbose)
1325 printf("Trying %s\n", inet_ntoa(tcpconf.nwtc_remaddr));
1326 clopt.nwtcl_flags= 0;
1327 result= ioctl(tcp_fd, NWIOTCPCONN, &clopt);
1328 if (result == 0)
1329 break;
1330 terrno= errno;
1331 if (verbose)
1332 fprintf(stderr,
1333 "Connection failed, trying next server: %s\n",
1334 strerror(errno));
1335 close(tcp_fd);
1337 if (thisns >= numnsaddr) {
1338 printf("No server for that domain responded\n");
1339 if (!verbose)
1340 fprintf(stderr, "Error from the last server was: %s\n",
1341 strerror(terrno));
1342 return(ERROR);
1346 * Send length & message for zone transfer
1349 len = htons(msglen);
1351 result= tcpip_writeall(tcp_fd, (char *)&len, sizeof(len));
1352 if (result != sizeof(len))
1354 fprintf(stderr, "write failed: %s\n", strerror(errno));
1355 close(tcp_fd);
1356 return ERROR;
1358 result= tcpip_writeall(tcp_fd, (char *)&buf, msglen);
1359 if (result != msglen)
1361 fprintf(stderr, "write failed: %s\n",
1362 strerror(errno));
1363 close(tcp_fd);
1364 return ERROR;
1366 filePtr = stdout;
1368 while (1) {
1371 * Read the length of the response.
1374 cp = (u8_t *) &buf;
1375 amtToRead = sizeof(u_short);
1376 while(amtToRead > 0)
1378 result = read(tcp_fd, (char *)cp, amtToRead);
1379 if (result <= 0)
1380 break;
1381 cp += result;
1382 amtToRead -= result;
1384 if (amtToRead) {
1385 error = ERR_READING_LEN;
1386 break;
1389 if ((len = htons(*(u_short *)&buf)) == 0) {
1390 break; /* nothing left to read */
1394 * Read the response.
1397 amtToRead = len;
1398 cp = (u8_t *) &buf;
1399 while(amtToRead > 0)
1401 result = read(tcp_fd, (char *)cp, amtToRead);
1402 if (result<= 0)
1403 break;
1404 cp += result;
1405 amtToRead -= result;
1407 if (amtToRead) {
1408 error = ERR_READING_MSG;
1409 break;
1412 #ifdef __NBSD_LIBC
1413 i = buf.qb1.rcode;
1414 #else
1415 i = buf.qb1.dh_flag2 & DHF_RCODE;
1416 #endif
1417 if (i != NOERROR || ntohs(buf.qb1.dh_ancount) == 0) {
1418 if ((thisns+1) < numnsaddr &&
1419 (i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
1420 if (_res.options & RES_DEBUG || verbose)
1421 printf("Server failed, trying next server: %s\n",
1422 i != NOERROR ?
1423 DecodeError(i) : "Premature end of data");
1424 close(tcp_fd);
1425 thisns++;
1426 goto again;
1428 printf("Server failed: %s\n",
1429 i != NOERROR ? DecodeError(i) : "Premature end of data");
1430 break;
1434 result = printinfo(&buf, cp, queryType, 1);
1435 if (! result) {
1436 error = ERR_PRINTING;
1437 break;
1439 numAnswers++;
1440 cp = buf.qb2 + sizeof(HEADER);
1441 if (ntohs(buf.qb1.dh_qdcount) > 0)
1442 cp += dn_skipname(cp, buf.qb2 + len) + QFIXEDSZ;
1444 nmp = cp;
1445 cp += dn_skipname(cp, (u_char *)&buf + len);
1446 if ((_getshort(cp) == T_SOA)) {
1447 dn_expand(buf.qb2, buf.qb2 + len, nmp, (u8_t *)dname[soacnt],
1448 sizeof(dname[0]));
1449 if (soacnt) {
1450 if (strcmp(dname[0], dname[1]) == 0)
1451 break;
1452 } else
1453 soacnt++;
1457 close(tcp_fd);
1459 switch (error) {
1460 case NO_ERRORS:
1461 return (SUCCESS);
1463 case ERR_READING_LEN:
1464 return(ERROR);
1466 case ERR_PRINTING:
1467 fprintf(stderr,"*** Error during listing of %s: %s\n",
1468 namePtr, DecodeError(result));
1469 return(result);
1471 case ERR_READING_MSG:
1472 headerPtr = (HEADER *) &buf;
1473 fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
1474 fprintf(stderr,
1475 " result: %s, answers = %d, authority = %d, additional = %d\n",
1476 #ifdef __NBSD_LIBC
1477 resultcodes[headerPtr->rcode],
1478 #else
1479 resultcodes[headerPtr->dh_flag2 & DHF_RCODE],
1480 #endif
1481 ntohs(headerPtr->dh_ancount),
1482 ntohs(headerPtr->dh_nscount),
1483 ntohs(headerPtr->dh_arcount));
1484 return(ERROR);
1485 default:
1486 return(ERROR);
1490 static char *
1491 DecodeError(result)
1492 int result;
1494 switch(result) {
1495 case NOERROR: return("Success"); break;
1496 case FORMERR: return("Format error"); break;
1497 case SERVFAIL: return("Server failed"); break;
1498 case NXDOMAIN: return("Non-existent domain"); break;
1499 case NOTIMP: return("Not implemented"); break;
1500 case REFUSED: return("Query refused"); break;
1501 case NOCHANGE: return("No change"); break;
1502 case NO_INFO: return("No information"); break;
1503 case ERROR: return("Unspecified error"); break;
1504 case TIME_OUT: return("Timed out"); break;
1505 case NONAUTH: return("Non-authoritative answer"); break;
1506 default: break;
1508 return("BAD ERROR VALUE");
1511 static int tcpip_writeall(fd, buf, siz)
1512 int fd;
1513 char *buf;
1514 unsigned siz;
1516 unsigned siz_org;
1517 int nbytes;
1519 siz_org= siz;
1521 while (siz)
1523 nbytes= write(fd, buf, siz);
1524 if (nbytes == -1)
1525 return nbytes;
1526 assert(siz >= nbytes);
1527 buf += nbytes;
1528 siz -= nbytes;
1530 return siz_org;