forget difference between big and small commands - obsolete with vm.
[minix.git] / commands / simple / host.c
blobec800f86ea8aabe7595fc97368cb2d0816fef064
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
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>
53 #endif
55 extern int h_errno;
57 #define NUMMX 50
59 #define SUCCESS 0
60 #define TIME_OUT -1
61 #define NO_INFO -2
62 #define ERROR -3
63 #define NONAUTH -4
65 #define NAME_LEN 256
67 #ifndef T_TXT
68 #define T_TXT 16
69 #endif
70 #ifndef NO_DATA
71 #define NO_DATA NO_ADDRESS
72 #endif
73 #ifndef C_HS
74 #define C_HS 4
75 #endif
77 FILE *filePtr;
79 struct state orig;
80 extern struct state _res;
81 static u8_t *cname = NULL;
82 int getclass = C_IN;
83 int gettype, getdeftype = T_A;
84 int verbose = 0;
85 int list = 0;
86 int server_specified = 0;
88 union querybuf;
90 int main _ARGS(( int c, char *v[] ));
92 static int parsetype _ARGS(( char *s ));
93 static int parseclass _ARGS(( char *s ));
94 static void hperror _ARGS(( int errno ));
95 static void printanswer _ARGS(( struct hostent *hp ));
96 static int ListHosts _ARGS(( char *namePtr, int queryType ));
97 static int gethostinfo _ARGS(( char *name ));
98 static int getdomaininfo _ARGS(( char *name, char *domain ));
99 static int getinfo _ARGS(( char *name, char *domain, int type ));
100 static int printinfo _ARGS(( union querybuf *answer, u8_t *eom, int filter,
101 int isls ));
102 static char *DecodeError _ARGS(( int result ));
103 static u8_t *pr_rr _ARGS(( u8_t *cp, u8_t *msg, FILE *file, int filter ));
104 static u8_t * pr_cdname _ARGS(( u8_t *cp, u8_t *msg, u8_t *name, int namelen ));
105 static char *pr_class _ARGS(( int class ));
106 static char *pr_type _ARGS(( int type ));
107 static int tcpip_writeall _ARGS(( int fd, char *buf, unsigned siz ));
110 main(c, v)
111 char **v;
113 char *domain;
114 ipaddr_t addr;
115 register struct hostent *hp;
116 register char *s, *p;
117 register inverse = 0;
118 register waitmode = 0;
119 u8_t *oldcname;
120 int ncnames;
121 int isaddr;
123 res_init();
124 _res.retrans = 5;
126 if (c < 2) {
127 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");
128 exit(1);
130 while (c > 2 && v[1][0] == '-') {
131 if (strcmp (v[1], "-w") == 0) {
132 _res.retry = 1;
133 _res.retrans = 15;
134 waitmode = 1;
135 v++;
136 c--;
138 else if (strcmp (v[1], "-r") == 0) {
139 _res.options &= ~RES_RECURSE;
140 v++;
141 c--;
143 else if (strcmp (v[1], "-d") == 0) {
144 _res.options |= RES_DEBUG;
145 v++;
146 c--;
148 else if (strcmp (v[1], "-v") == 0) {
149 verbose = 1;
150 v++;
151 c--;
153 else if (strcmp (v[1], "-l") == 0) {
154 list = 1;
155 v++;
156 c--;
158 else if (strncmp (v[1], "-t", 2) == 0) {
159 v++;
160 c--;
161 gettype = parsetype(v[1]);
162 v++;
163 c--;
165 else if (strncmp (v[1], "-c", 2) == 0) {
166 v++;
167 c--;
168 getclass = parseclass(v[1]);
169 v++;
170 c--;
172 else if (strcmp (v[1], "-a") == 0) {
173 verbose = 1;
174 gettype = T_ANY;
175 v++;
176 c--;
178 else if (strcmp (v[1], "-V") == 0) {
179 _res.options |= RES_USEVC;
180 v++;
181 c--;
184 if (c > 2) {
185 s = v[2];
186 server_specified++;
188 if ((p = strchr(s, ':')) != NULL) *p++ = 0;
189 isaddr = inet_aton(s, &addr);
190 if (p != NULL) p[-1] = ':';
191 if (!isaddr) {
192 hp = gethostbyname(s);
193 if (hp == NULL) {
194 fprintf(stderr,"Error in looking up server name:\n");
195 hperror(h_errno);
196 exit(1);
198 _res.nsaddr= *(ipaddr_t *)hp->h_addr;
199 printf("Using domain server:\n");
200 printanswer(hp);
202 else {
203 _res.nsaddr_list[0]= addr;
204 _res.nsport_list[0]= htons(NAMESERVER_PORT);
205 printf("Using domain server %s",
206 inet_ntoa(_res.nsaddr));
207 if (p != NULL) {
208 printf(" on port %d", atoi(p));
209 _res.nsport_list[0]= htons(atoi(p));
211 printf(":\n");
214 domain = v[1];
215 if (strcmp (domain, ".") != 0 && inet_aton(domain, &addr)) {
216 static char ipname[sizeof("255.255.255.255.in-addr.arpa.")];
217 sprintf(ipname, "%d.%d.%d.%d.in-addr.arpa.",
218 ((unsigned char *) &addr)[3],
219 ((unsigned char *) &addr)[2],
220 ((unsigned char *) &addr)[1],
221 ((unsigned char *) &addr)[0]);
222 domain = ipname;
223 getdeftype = T_PTR;
226 hp = NULL;
227 h_errno = TRY_AGAIN;
229 * we handle default domains ourselves, thank you
231 _res.options &= ~RES_DEFNAMES;
233 if (list)
234 exit(ListHosts(domain, gettype ? gettype : getdeftype));
235 oldcname = NULL;
236 ncnames = 5;
237 while (hp == NULL && h_errno == TRY_AGAIN) {
238 cname = NULL;
239 if (oldcname == NULL)
240 hp = (struct hostent *)gethostinfo(domain);
241 else
242 hp = (struct hostent *)gethostinfo((char *)oldcname);
243 if (cname) {
244 if (ncnames-- == 0) {
245 printf("Too many cnames. Possible loop.\n");
246 exit(1);
248 oldcname = cname;
249 hp = NULL;
250 h_errno = TRY_AGAIN;
251 continue;
253 if (!waitmode)
254 break;
257 if (hp == NULL) {
258 hperror(h_errno);
259 exit(1);
262 exit(0);
266 static int
267 parsetype(s)
268 char *s;
270 if (strcmp(s,"a") == 0)
271 return(1);
272 if (strcmp(s,"ns") == 0)
273 return(2);
274 if (strcmp(s,"md") == 0)
275 return(3);
276 if (strcmp(s,"mf") == 0)
277 return(4);
278 if (strcmp(s,"cname") == 0)
279 return(5);
280 if (strcmp(s,"soa") == 0)
281 return(6);
282 if (strcmp(s,"mb") == 0)
283 return(7);
284 if (strcmp(s,"mg") == 0)
285 return(8);
286 if (strcmp(s,"mr") == 0)
287 return(9);
288 if (strcmp(s,"null") == 0)
289 return(10);
290 if (strcmp(s,"wks") == 0)
291 return(11);
292 if (strcmp(s,"ptr") == 0)
293 return(12);
294 if (strcmp(s,"hinfo") == 0)
295 return(13);
296 if (strcmp(s,"minfo") == 0)
297 return(14);
298 if (strcmp(s,"mx") == 0)
299 return(15);
300 if (strcmp(s,"txt") == 0) /* Roy */
301 return(T_TXT); /* Roy */
302 if (strcmp(s,"uinfo") == 0)
303 return(100);
304 if (strcmp(s,"uid") == 0)
305 return(101);
306 if (strcmp(s,"gid") == 0)
307 return(102);
308 if (strcmp(s,"unspec") == 0)
309 return(103);
310 if (strcmp(s,"any") == 0)
311 return(255);
312 if (strcmp(s,"*") == 0)
313 return(255);
314 if (atoi(s))
315 return(atoi(s));
316 fprintf(stderr, "Invalid query type: %s\n", s);
317 exit(2);
320 static int
321 parseclass(s)
322 char *s;
324 if (strcmp(s,"in") == 0)
325 return(C_IN);
326 if (strcmp(s,"chaos") == 0)
327 return(C_CHAOS);
328 if (strcmp(s,"hs") == 0)
329 return(C_HS);
330 if (strcmp(s,"any") == 0)
331 return(C_ANY);
332 if (atoi(s))
333 return(atoi(s));
334 fprintf(stderr, "Invalid query class: %s\n", s);
335 exit(2);
338 static void
339 printanswer(hp)
340 register struct hostent *hp;
342 register char **cp;
343 register ipaddr_t **hptr;
345 printf("Name: %s\n", hp->h_name);
346 printf("Address:");
347 for (hptr = (ipaddr_t **)hp->h_addr_list; *hptr; hptr++)
348 printf(" %s", inet_ntoa(*(ipaddr_t *)*hptr));
349 printf("\nAliases:");
350 for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
351 printf(" %s", *cp);
352 printf("\n\n");
355 static void
356 hperror(errno)
357 int errno;
359 switch(errno) {
360 case HOST_NOT_FOUND:
361 fprintf(stderr,"Host not found.\n");
362 break;
363 case TRY_AGAIN:
364 fprintf(stderr,"Host not found, try again.\n");
365 break;
366 case NO_RECOVERY:
367 fprintf(stderr,"No recovery, Host not found.\n");
368 break;
369 case NO_ADDRESS:
370 fprintf(stderr,"There is an entry for this host, but it doesn't have what you requested.\n");
371 break;
376 typedef union querybuf {
377 dns_hdr_t qb1;
378 u8_t qb2[PACKETSZ];
379 } querybuf_t;
381 static u8_t hostbuf[BUFSIZ+1];
384 static int
385 gethostinfo(name)
386 char *name;
388 register char *cp, **domain;
389 int n;
390 int hp;
391 int nDomain;
393 if (strcmp(name, ".") == 0)
394 return(getdomaininfo(name, NULL));
395 for (cp = name, n = 0; *cp; cp++)
396 if (*cp == '.')
397 n++;
398 if (n && cp[-1] == '.') {
399 if (cp[-1] == '.')
400 cp[-1] = 0;
401 hp = getdomaininfo(name, (char *)NULL);
402 if (cp[-1] == 0)
403 cp[-1] = '.';
404 return (hp);
406 if (n == 0 && (cp = __hostalias(name))) {
407 if (verbose)
408 printf("Aliased to \"%s\"\n", cp);
409 _res.options |= RES_DEFNAMES;
410 return (getdomaininfo(cp, (char *)NULL));
412 #ifdef MAXDS
413 for (nDomain = 0;
414 _res.defdname_list[nDomain][0] != 0;
415 nDomain++) {
416 for (domain = _res.dnsrch_list[nDomain]; *domain; domain++) {
417 if (verbose)
418 printf("Trying domain \"%s\"\n", *domain);
419 hp = getdomaininfo(name, *domain);
420 if (hp)
421 return (hp);
424 #else
425 for (domain = _res.dnsrch; *domain; domain++) {
426 if (verbose)
427 printf("Trying domain \"%s\"\n", *domain);
428 hp = getdomaininfo(name, *domain);
429 if (hp)
430 return (hp);
432 #endif
433 if (h_errno != HOST_NOT_FOUND ||
434 (_res.options & RES_DNSRCH) == 0)
435 return (0);
436 if (verbose)
437 printf("Trying null domain\n");
438 return (getdomaininfo(name, (char *)NULL));
441 static int
442 getdomaininfo(name, domain)
443 char *name, *domain;
445 return getinfo(name, domain, gettype ? gettype : getdeftype);
448 static int
449 getinfo(name, domain, type)
450 char *name, *domain;
453 dns_hdr_t *hp;
454 u8_t *eom, *bp, *cp;
455 querybuf_t buf, answer;
456 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
457 u_short pref, class;
458 char host[2*MAXDNAME+2];
460 if (domain == NULL)
461 (void)sprintf(host, "%.*s", MAXDNAME, name);
462 else
463 (void)sprintf(host, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
465 n = res_mkquery(QUERY, host, getclass, type, (char *)NULL, 0, NULL,
466 (char *)&buf, sizeof(buf));
467 if (n < 0) {
468 if (_res.options & RES_DEBUG)
469 printf("res_mkquery failed\n");
470 h_errno = NO_RECOVERY;
471 return(0);
473 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
474 if (n < 0) {
475 if (_res.options & RES_DEBUG)
476 printf("res_send failed\n");
477 h_errno = TRY_AGAIN;
478 return (0);
480 eom = (u8_t *)&answer + n;
481 return(printinfo(&answer, eom, T_ANY, 0));
484 static int
485 printinfo(answer, eom, filter, isls)
486 querybuf_t *answer;
487 u8_t *eom;
488 int filter;
489 int isls;
491 dns_hdr_t *hp;
492 u8_t *bp, *cp;
493 int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
494 u_short pref, class;
497 * find first satisfactory answer
499 hp = (dns_hdr_t *) answer;
500 ancount = ntohs(hp->dh_ancount);
501 qdcount = ntohs(hp->dh_qdcount);
502 nscount = ntohs(hp->dh_nscount);
503 arcount = ntohs(hp->dh_arcount);
504 if (_res.options & RES_DEBUG || (verbose && isls == 0))
505 printf("rcode = %d (%s), ancount=%d\n",
506 hp->dh_flag2 & DHF_RCODE,
507 DecodeError(hp->dh_flag2 & DHF_RCODE), ancount);
508 if (hp->dh_flag2 & DHF_RCODE != NOERROR ||
509 (ancount+nscount+arcount) == 0) {
510 switch (hp->dh_flag2 & DHF_RCODE) {
511 case NXDOMAIN:
512 /* Check if it's an authoritive answer */
513 if (hp->dh_flag1 & DHF_AA) {
514 h_errno = HOST_NOT_FOUND;
515 return(0);
516 } else {
517 h_errno = TRY_AGAIN;
518 return(0);
520 case SERVFAIL:
521 h_errno = TRY_AGAIN;
522 return(0);
523 #ifdef OLDJEEVES
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.
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);
544 return (0);
546 bp = hostbuf;
547 nmx = 0;
548 buflen = sizeof(hostbuf);
549 cp = (u8_t *)answer + sizeof(dns_hdr_t);
550 if (qdcount) {
551 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
552 while (--qdcount > 0)
553 cp += dn_skipname((u8_t *)cp,(u8_t *)eom) + QFIXEDSZ;
555 if (ancount) {
556 if (!(hp->dh_flag1 & DHF_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, (u8_t *)answer, stdout, filter);
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.
567 if (cname && ! verbose)
568 return (1);
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, (u8_t *)answer, stdout, filter);
579 if (arcount) {
580 printf("Additional information:\n");
581 while (--arcount >= 0 && cp && cp < eom) {
582 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
585 return(1);
588 static u8_t cnamebuf[MAXDNAME];
591 * Print resource record fields in human readable form.
593 static u8_t *
594 pr_rr(cp, msg, file, filter)
595 u8_t *cp, *msg;
596 FILE *file;
597 int filter;
599 int type, class, dlen, n, c, proto, ttl;
600 ipaddr_t inaddr;
601 u8_t *cp1;
602 struct protoent *protop;
603 struct servent *servp;
604 char punc;
605 int doprint;
606 u8_t name[MAXDNAME];
608 if ((cp = pr_cdname(cp, msg, name, sizeof(name))) == NULL)
609 return (NULL); /* compression error */
611 type = _getshort(cp);
612 cp += sizeof(u_short);
614 class = _getshort(cp);
615 cp += sizeof(u_short);
617 ttl = _getlong(cp);
618 cp += sizeof(u_long);
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;
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 = ' ';
637 dlen = _getshort(cp);
638 cp += sizeof(u_short);
639 cp1 = cp;
641 * Print type specific data, if appropriate
643 switch (type) {
644 case T_A:
645 switch (class) {
646 case C_IN:
647 bcopy((char *)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]);
661 cp += dlen;
663 break;
665 break;
666 case T_CNAME:
667 if (dn_expand(msg, msg + 512, cp, cnamebuf,
668 sizeof(cnamebuf)-1) >= 0) {
669 strcat((char *) cnamebuf, ".");
670 if (gettype != T_CNAME && gettype != T_ANY)
671 cname = cnamebuf;
673 case T_MB:
674 #ifdef OLDRR
675 case T_MD:
676 case T_MF:
677 #endif /* OLDRR */
678 case T_MG:
679 case T_MR:
680 case T_NS:
681 case T_PTR:
682 cp = pr_cdname(cp, msg, name, sizeof(name));
683 if (doprint)
684 fprintf(file,"%c%s",punc, name);
685 break;
687 case T_HINFO:
688 if (n = *cp++) {
689 if (doprint)
690 fprintf(file,"%c%.*s", punc, n, cp);
691 cp += n;
693 if (n = *cp++) {
694 if (doprint)
695 fprintf(file,"%c%.*s", punc, n, cp);
696 cp += n;
698 break;
700 case T_SOA:
701 cp = pr_cdname(cp, msg, name, sizeof(name));
702 if (doprint)
703 fprintf(file,"\t%s", name);
704 cp = pr_cdname(cp, msg, name, sizeof(name));
705 if (doprint)
706 fprintf(file," %s", name);
707 if (doprint)
708 fprintf(file,"(\n\t\t\t%ld\t;serial (version)", _getlong(cp));
709 cp += sizeof(u_long);
710 if (doprint)
711 fprintf(file,"\n\t\t\t%ld\t;refresh period", _getlong(cp));
712 cp += sizeof(u_long);
713 if (doprint)
714 fprintf(file,"\n\t\t\t%ld\t;retry refresh this often", _getlong(cp));
715 cp += sizeof(u_long);
716 if (doprint)
717 fprintf(file,"\n\t\t\t%ld\t;expiration period", _getlong(cp));
718 cp += sizeof(u_long);
719 if (doprint)
720 fprintf(file,"\n\t\t\t%ld\t;minimum TTL\n\t\t\t)", _getlong(cp));
721 cp += sizeof(u_long);
722 break;
724 case T_MX:
725 if (doprint)
726 if (verbose)
727 fprintf(file,"\t%d ",_getshort(cp));
728 else
729 fprintf(file," (pri=%d) by ",_getshort(cp));
730 cp += sizeof(u_short);
731 cp = pr_cdname(cp, msg, name, sizeof(name));
732 if (doprint)
733 fprintf(file, "%s", name);
734 break;
736 case T_MINFO:
737 cp = pr_cdname(cp, msg, name, sizeof(name));
738 if (doprint)
739 fprintf(file,"%c%s",punc, name);
740 cp = pr_cdname(cp, msg, name, sizeof(name));
741 if (doprint)
742 fprintf(file," %s", name);
743 break;
745 /* Roy start */
746 case T_TXT:
747 if (n = *cp++) {
748 if (doprint)
749 fprintf(file,"%c%.*s", punc, n, cp);
750 cp += n;
752 break;
753 /* Roy end */
755 case T_UINFO:
756 if (doprint)
757 fprintf(file,"%c%s", punc, cp);
758 cp += dlen;
759 break;
761 case T_UID:
762 case T_GID:
763 if (dlen == 4) {
764 if (doprint)
765 fprintf(file,"%c%ld", punc, _getlong(cp));
766 cp += sizeof(int);
768 break;
770 case T_WKS:
771 if (dlen < sizeof(u_long) + 1)
772 break;
773 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
774 cp += sizeof(u_long);
775 proto = *cp++;
776 protop = getprotobynumber(proto);
777 if (doprint)
778 if (protop)
779 fprintf(file,"%c%s %s", punc,
780 inet_ntoa(inaddr), protop->p_name);
781 else
782 fprintf(file,"%c%s %d", punc,
783 inet_ntoa(inaddr), proto);
785 n = 0;
786 while (cp < cp1 + dlen) {
787 c = *cp++;
788 do {
789 if (c & 0200) {
790 servp = NULL;
791 if (protop)
792 servp = getservbyport (htons(n),
793 protop->p_name);
794 if (doprint)
795 if (servp)
796 fprintf(file, " %s", servp->s_name);
797 else
798 fprintf(file, " %d", n);
800 c <<= 1;
801 } while (++n & 07);
803 break;
805 default:
806 if (doprint)
807 fprintf(file,"%c???", punc);
808 cp += dlen;
810 if (cp != cp1 + dlen)
811 fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
812 if (doprint)
813 fprintf(file,"\n");
814 return (cp);
817 static char nbuf[20];
820 * Return a string for the type
822 static char *
823 pr_type(type)
824 int type;
826 switch (type) {
827 case T_A:
828 return(verbose? "A" : "has address");
829 case T_NS: /* authoritative server */
830 return("NS");
831 #ifdef OLDRR
832 case T_MD: /* mail destination */
833 return("MD");
834 case T_MF: /* mail forwarder */
835 return("MF");
836 #endif /* OLDRR */
837 case T_CNAME: /* connonical name */
838 return(verbose? "CNAME" : "is a nickname for");
839 case T_SOA: /* start of authority zone */
840 return("SOA");
841 case T_MB: /* mailbox domain name */
842 return("MB");
843 case T_MG: /* mail group member */
844 return("MG");
845 case T_MX: /* mail routing info */
846 return(verbose? "MX" : "mail is handled");
847 /* Roy start */
848 case T_TXT: /* TXT - descriptive info */
849 return(verbose? "TXT" : "descriptive text");
850 /* Roy end */
851 case T_MR: /* mail rename name */
852 return("MR");
853 case T_NULL: /* null resource record */
854 return("NULL");
855 case T_WKS: /* well known service */
856 return("WKS");
857 case T_PTR: /* domain name pointer */
858 return("PTR");
859 case T_HINFO: /* host information */
860 return("HINFO");
861 case T_MINFO: /* mailbox information */
862 return("MINFO");
863 case T_AXFR: /* zone transfer */
864 return("AXFR");
865 case T_MAILB: /* mail box */
866 return("MAILB");
867 case T_MAILA: /* mail address */
868 return("MAILA");
869 case T_ANY: /* matches any type */
870 return("ANY");
871 case T_UINFO:
872 return("UINFO");
873 case T_UID:
874 return("UID");
875 case T_GID:
876 return("GID");
877 default:
878 return (sprintf(nbuf, "%d", type) == EOF ? NULL : nbuf);
883 * Return a mnemonic for class
885 static char *
886 pr_class(class)
887 int class;
890 switch (class) {
891 case C_IN: /* internet class */
892 return(verbose? " IN" : "");
893 case C_CHAOS: /* chaos class */
894 return(verbose? " CHAOS" : "");
895 case C_HS: /* Hesiod class */
896 return(verbose? " HS" : "");
897 case C_ANY: /* matches any class */
898 return(" ANY");
899 default:
900 return (sprintf(nbuf," %d", class) == EOF ? NULL : nbuf);
904 static u8_t *
905 pr_cdname(cp, msg, name, namelen)
906 u8_t *cp, *msg;
907 u8_t *name;
908 int namelen;
910 int n;
912 if ((n = dn_expand(msg, msg + 512, cp, name, namelen - 2)) < 0)
913 return (NULL);
914 if (name[0] == '\0') {
915 name[0] = '.';
916 name[1] = '\0';
918 return (cp + n);
921 char *resultcodes[] = {
922 "NOERROR",
923 "FORMERR",
924 "SERVFAIL",
925 "NXDOMAIN",
926 "NOTIMP",
927 "REFUSED",
928 "6",
929 "7",
930 "8",
931 "9",
932 "10",
933 "11",
934 "12",
935 "13",
936 "14",
937 "NOCHANGE",
943 ******************************************************************************
945 * ListHosts --
947 * Requests the name server to do a zone transfer so we
948 * find out what hosts it knows about.
950 * Results:
951 * SUCCESS the listing was successful.
952 * ERROR the server could not be contacted because
953 * a socket could not be obtained or an error
954 * occured while receiving, or the output file
955 * could not be opened.
957 ******************************************************************************
960 static int
961 ListHosts(namePtr, queryType)
962 char *namePtr;
963 int queryType; /* e.g. T_A */
965 querybuf_t buf, answer;
966 dns_hdr_t *headerPtr;
968 int msglen;
969 int amtToRead;
970 int numRead;
971 int i;
972 int numAnswers = 0;
973 int result;
974 int soacnt = 0;
975 u_short len;
976 int dlen;
977 int type;
978 int nscount;
979 u8_t *cp, *nmp;
980 u8_t name[NAME_LEN];
981 char dname[2][NAME_LEN];
982 u8_t domain[NAME_LEN];
983 /* names and addresses of name servers to try */
984 #define NUMNS 8
985 char nsname[NUMNS][NAME_LEN];
986 int nshaveaddr[NUMNS];
987 #define IPADDRSIZE 4
988 #define NUMNSADDR 16
989 char nsipaddr[NUMNSADDR][IPADDRSIZE];
990 int numns;
991 int numnsaddr;
992 int thisns;
993 struct hostent *hp;
994 enum {
995 NO_ERRORS,
996 ERR_READING_LEN,
997 ERR_READING_MSG,
998 ERR_PRINTING
999 } error = NO_ERRORS;
1000 char *tcp_serv_name;
1001 int tcp_fd;
1002 nwio_tcpconf_t tcpconf;
1003 nwio_tcpcl_t clopt;
1004 int terrno;
1007 * normalize to not have trailing dot. We do string compares below
1008 * of info from name server, and it won't have trailing dots.
1010 i = strlen(namePtr);
1011 if (namePtr[i-1] == '.')
1012 namePtr[i-1] = 0;
1014 if (server_specified) {
1015 bcopy((char *)&_res.nsaddr, nsipaddr[0], IPADDRSIZE);
1016 numnsaddr = 1;
1018 else {
1021 * First we have to find out where to look. This needs a NS query,
1022 * possibly followed by looking up addresses for some of the names.
1025 msglen = res_mkquery(QUERY, namePtr, C_IN, T_NS,
1026 (char *)0, 0, (struct rrec *)0,
1027 (char *)&buf, sizeof(buf));
1029 if (msglen < 0) {
1030 printf("res_mkquery failed\n");
1031 return (ERROR);
1034 msglen = res_send((char *)&buf,msglen,(char *)&answer, sizeof(answer));
1036 if (msglen < 0) {
1037 printf("Unable to get to nameserver -- try again later\n");
1038 return (ERROR);
1040 if (_res.options & RES_DEBUG || verbose)
1041 printf("rcode = %d (%s), ancount=%d\n",
1042 answer.qb1.dh_flag2 & DHF_RCODE,
1043 DecodeError(answer.qb1.dh_flag2 & DHF_RCODE),
1044 ntohs(answer.qb1.dh_ancount));
1047 * Analyze response to our NS lookup
1050 nscount = ntohs(answer.qb1.dh_ancount) + ntohs(answer.qb1.dh_nscount) +
1051 ntohs(answer.qb1.dh_arcount);
1053 if (answer.qb1.dh_flag2 & DHF_RCODE != NOERROR || nscount == 0) {
1054 switch (answer.qb1.dh_flag2 & DHF_RCODE) {
1055 case NXDOMAIN:
1056 /* Check if it's an authoritive answer */
1057 if (answer.qb1.dh_flag1 & DHF_AA) {
1058 printf("No such domain\n");
1059 } else {
1060 printf("Unable to get information about domain -- try again later.\n");
1062 break;
1063 case SERVFAIL:
1064 printf("Unable to get information about that domain -- try again later.\n");
1065 break;
1066 case NOERROR:
1067 printf("That domain exists, but seems to be a leaf node.\n");
1068 break;
1069 case FORMERR:
1070 case NOTIMP:
1071 case REFUSED:
1072 printf("Unrecoverable error looking up domain name.\n");
1073 break;
1075 return (0);
1078 cp = answer.qb2 + sizeof(dns_hdr_t);
1079 if (ntohs(answer.qb1.dh_qdcount) > 0)
1080 cp += dn_skipname(cp, answer.qb2 + msglen) + QFIXEDSZ;
1082 numns = 0;
1083 numnsaddr = 0;
1086 * Look at response from NS lookup for NS and A records.
1089 for (;nscount; nscount--) {
1090 cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1091 domain, sizeof(domain));
1092 type = _getshort(cp);
1093 cp += sizeof(u_short) + sizeof(u_short) + sizeof(u_long);
1094 dlen = _getshort(cp);
1095 cp += sizeof(u_short);
1096 if (type == T_NS) {
1097 if (dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1098 name, sizeof(name)) >= 0) {
1099 if (numns < NUMNS && strcasecmp((char *)domain, namePtr) == 0) {
1100 for (i = 0; i < numns; i++)
1101 if (strcasecmp(nsname[i], (char *)name) == 0)
1102 break; /* duplicate */
1103 if (i >= numns) {
1104 strncpy(nsname[numns], (char *)name, sizeof(name));
1105 nshaveaddr[numns] = 0;
1106 numns++;
1111 else if (type == T_A) {
1112 if (numnsaddr < NUMNSADDR)
1113 for (i = 0; i < numns; i++) {
1114 if (strcasecmp(nsname[i], (char *)domain) == 0) {
1115 nshaveaddr[i]++;
1116 bcopy((char *)cp, nsipaddr[numnsaddr],IPADDRSIZE);
1117 numnsaddr++;
1118 break;
1122 cp += dlen;
1126 * Usually we'll get addresses for all the servers in the additional
1127 * info section. But in case we don't, look up their addresses.
1130 for (i = 0; i < numns; i++) {
1131 if (! nshaveaddr[i]) {
1132 register long **hptr;
1133 int numaddrs = 0;
1135 hp = gethostbyname(nsname[i]);
1136 if (hp) {
1137 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
1138 if (numnsaddr < NUMNSADDR) {
1139 bcopy((char *)*hptr, nsipaddr[numnsaddr],IPADDRSIZE);
1140 numnsaddr++;
1141 numaddrs++;
1144 if (_res.options & RES_DEBUG || verbose)
1145 printf("Found %d addresses for %s by extra query\n",
1146 numaddrs, nsname[i]);
1148 else
1149 if (_res.options & RES_DEBUG || verbose)
1150 printf("Found %d addresses for %s\n",
1151 nshaveaddr[i], nsname[i]);
1155 * Now nsipaddr has numnsaddr addresses for name servers that
1156 * serve the requested domain. Now try to find one that will
1157 * accept a zone transfer.
1160 thisns = 0;
1162 again:
1164 numAnswers = 0;
1165 soacnt = 0;
1168 * Create a query packet for the requested domain name.
1171 msglen = res_mkquery(QUERY, namePtr, getclass, T_AXFR,
1172 (char *)0, 0, (struct rrec *)0,
1173 (char *) &buf, sizeof(buf));
1174 if (msglen < 0) {
1175 if (_res.options & RES_DEBUG) {
1176 fprintf(stderr, "ListHosts: Res_mkquery failed\n");
1178 return (ERROR);
1182 * Set up a virtual circuit to the server.
1185 tcp_serv_name= getenv("TCP_DEVICE");
1186 if (!tcp_serv_name)
1187 tcp_serv_name= TCP_DEVICE;
1188 for (;thisns < numnsaddr; thisns++)
1190 tcp_fd= open(tcp_serv_name, O_RDWR);
1191 if (tcp_fd == -1)
1193 fprintf(stderr, "unable to open '%s': %s\n", tcp_serv_name,
1194 strerror(errno));
1195 return ERROR;
1198 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
1199 NWTC_SET_RP;
1200 tcpconf.nwtc_remaddr= *(ipaddr_t *)nsipaddr[thisns];
1201 tcpconf.nwtc_remport= _res.nsport_list[0];
1202 result= ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf);
1203 if (result == -1)
1205 fprintf(stderr, "tcp_ioc_setconf failed: %s\n",
1206 strerror(errno));
1207 close(tcp_fd);
1208 return ERROR;
1210 if (_res.options & RES_DEBUG || verbose)
1211 printf("Trying %s\n", inet_ntoa(tcpconf.nwtc_remaddr));
1212 clopt.nwtcl_flags= 0;
1213 result= ioctl(tcp_fd, NWIOTCPCONN, &clopt);
1214 if (result == 0)
1215 break;
1216 terrno= errno;
1217 if (verbose)
1218 fprintf(stderr,
1219 "Connection failed, trying next server: %s\n",
1220 strerror(errno));
1221 close(tcp_fd);
1223 if (thisns >= numnsaddr) {
1224 printf("No server for that domain responded\n");
1225 if (!verbose)
1226 fprintf(stderr, "Error from the last server was: %s\n",
1227 strerror(terrno));
1228 return(ERROR);
1232 * Send length & message for zone transfer
1235 len = htons(msglen);
1237 result= tcpip_writeall(tcp_fd, (char *)&len, sizeof(len));
1238 if (result != sizeof(len))
1240 fprintf(stderr, "write failed: %s\n", strerror(errno));
1241 close(tcp_fd);
1242 return ERROR;
1244 result= tcpip_writeall(tcp_fd, (char *)&buf, msglen);
1245 if (result != msglen)
1247 fprintf(stderr, "write failed: %s\n",
1248 strerror(errno));
1249 close(tcp_fd);
1250 return ERROR;
1252 filePtr = stdout;
1254 while (1) {
1257 * Read the length of the response.
1260 cp = (u8_t *) &buf;
1261 amtToRead = sizeof(u_short);
1262 while(amtToRead > 0)
1264 result = read(tcp_fd, (char *)cp, amtToRead);
1265 if (result <= 0)
1266 break;
1267 cp += result;
1268 amtToRead -= result;
1270 if (amtToRead) {
1271 error = ERR_READING_LEN;
1272 break;
1275 if ((len = htons(*(u_short *)&buf)) == 0) {
1276 break; /* nothing left to read */
1280 * Read the response.
1283 amtToRead = len;
1284 cp = (u8_t *) &buf;
1285 while(amtToRead > 0)
1287 result = read(tcp_fd, (char *)cp, amtToRead);
1288 if (result<= 0)
1289 break;
1290 cp += result;
1291 amtToRead -= result;
1293 if (amtToRead) {
1294 error = ERR_READING_MSG;
1295 break;
1298 i = buf.qb1.dh_flag2 & DHF_RCODE;
1299 if (i != NOERROR || ntohs(buf.qb1.dh_ancount) == 0) {
1300 if ((thisns+1) < numnsaddr &&
1301 (i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
1302 if (_res.options & RES_DEBUG || verbose)
1303 printf("Server failed, trying next server: %s\n",
1304 i != NOERROR ?
1305 DecodeError(i) : "Premature end of data");
1306 close(tcp_fd);
1307 thisns++;
1308 goto again;
1310 printf("Server failed: %s\n",
1311 i != NOERROR ? DecodeError(i) : "Premature end of data");
1312 break;
1316 result = printinfo(&buf, cp, queryType, 1);
1317 if (! result) {
1318 error = ERR_PRINTING;
1319 break;
1321 numAnswers++;
1322 cp = buf.qb2 + sizeof(dns_hdr_t);
1323 if (ntohs(buf.qb1.dh_qdcount) > 0)
1324 cp += dn_skipname(cp, buf.qb2 + len) + QFIXEDSZ;
1326 nmp = cp;
1327 cp += dn_skipname(cp, (u_char *)&buf + len);
1328 if ((_getshort(cp) == T_SOA)) {
1329 dn_expand(buf.qb2, buf.qb2 + len, nmp, (u8_t *)dname[soacnt],
1330 sizeof(dname[0]));
1331 if (soacnt) {
1332 if (strcmp(dname[0], dname[1]) == 0)
1333 break;
1334 } else
1335 soacnt++;
1339 close(tcp_fd);
1341 switch (error) {
1342 case NO_ERRORS:
1343 return (SUCCESS);
1345 case ERR_READING_LEN:
1346 return(ERROR);
1348 case ERR_PRINTING:
1349 fprintf(stderr,"*** Error during listing of %s: %s\n",
1350 namePtr, DecodeError(result));
1351 return(result);
1353 case ERR_READING_MSG:
1354 headerPtr = (dns_hdr_t *) &buf;
1355 fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
1356 fprintf(stderr,
1357 " result: %s, answers = %d, authority = %d, additional = %d\n",
1358 resultcodes[headerPtr->dh_flag2 & DHF_RCODE],
1359 ntohs(headerPtr->dh_ancount),
1360 ntohs(headerPtr->dh_nscount),
1361 ntohs(headerPtr->dh_arcount));
1362 return(ERROR);
1363 default:
1364 return(ERROR);
1368 static char *
1369 DecodeError(result)
1370 int result;
1372 switch(result) {
1373 case NOERROR: return("Success"); break;
1374 case FORMERR: return("Format error"); break;
1375 case SERVFAIL: return("Server failed"); break;
1376 case NXDOMAIN: return("Non-existent domain"); break;
1377 case NOTIMP: return("Not implemented"); break;
1378 case REFUSED: return("Query refused"); break;
1379 case NOCHANGE: return("No change"); break;
1380 case NO_INFO: return("No information"); break;
1381 case ERROR: return("Unspecified error"); break;
1382 case TIME_OUT: return("Timed out"); break;
1383 case NONAUTH: return("Non-authoritative answer"); break;
1384 default: break;
1386 return("BAD ERROR VALUE");
1389 static int tcpip_writeall(fd, buf, siz)
1390 int fd;
1391 char *buf;
1392 unsigned siz;
1394 unsigned siz_org;
1395 int nbytes;
1397 siz_org= siz;
1399 while (siz)
1401 nbytes= write(fd, buf, siz);
1402 if (nbytes == -1)
1403 return nbytes;
1404 assert(siz >= nbytes);
1405 buf += nbytes;
1406 siz -= nbytes;
1408 return siz_org;