source: trunk/minix/commands/simple/host.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 31.1 KB
Line 
1/*
2 * Copyright (c) 1986 Regents of the University of California
3 * All Rights Reserved
4 *
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.
11 */
12
13/*
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.
17 */
18
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>
29
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>
40
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
54
55extern int h_errno;
56
57#define NUMMX 50
58
59#define SUCCESS 0
60#define TIME_OUT -1
61#define NO_INFO -2
62#define ERROR -3
63#define NONAUTH -4
64
65#define NAME_LEN 256
66
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
76
77FILE *filePtr;
78
79struct state orig;
80extern struct state _res;
81static u8_t *cname = NULL;
82int getclass = C_IN;
83int gettype, getdeftype = T_A;
84int verbose = 0;
85int list = 0;
86int server_specified = 0;
87
88union querybuf;
89
90int main _ARGS(( int c, char *v[] ));
91
92static int parsetype _ARGS(( char *s ));
93static int parseclass _ARGS(( char *s ));
94static void hperror _ARGS(( int errno ));
95static void printanswer _ARGS(( struct hostent *hp ));
96static int ListHosts _ARGS(( char *namePtr, int queryType ));
97static int gethostinfo _ARGS(( char *name ));
98static int getdomaininfo _ARGS(( char *name, char *domain ));
99static int getinfo _ARGS(( char *name, char *domain, int type ));
100static int printinfo _ARGS(( union querybuf *answer, u8_t *eom, int filter,
101 int isls ));
102static char *DecodeError _ARGS(( int result ));
103static u8_t *pr_rr _ARGS(( u8_t *cp, u8_t *msg, FILE *file, int filter ));
104static u8_t * pr_cdname _ARGS(( u8_t *cp, u8_t *msg, u8_t *name, int namelen ));
105static char *pr_class _ARGS(( int class ));
106static char *pr_type _ARGS(( int type ));
107static int tcpip_writeall _ARGS(( int fd, char *buf, unsigned siz ));
108
109int
110main(c, v)
111 char **v;
112{
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;
122
123 res_init();
124 _res.retrans = 5;
125
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);
129 }
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--;
137 }
138 else if (strcmp (v[1], "-r") == 0) {
139 _res.options &= ~RES_RECURSE;
140 v++;
141 c--;
142 }
143 else if (strcmp (v[1], "-d") == 0) {
144 _res.options |= RES_DEBUG;
145 v++;
146 c--;
147 }
148 else if (strcmp (v[1], "-v") == 0) {
149 verbose = 1;
150 v++;
151 c--;
152 }
153 else if (strcmp (v[1], "-l") == 0) {
154 list = 1;
155 v++;
156 c--;
157 }
158 else if (strncmp (v[1], "-t", 2) == 0) {
159 v++;
160 c--;
161 gettype = parsetype(v[1]);
162 v++;
163 c--;
164 }
165 else if (strncmp (v[1], "-c", 2) == 0) {
166 v++;
167 c--;
168 getclass = parseclass(v[1]);
169 v++;
170 c--;
171 }
172 else if (strcmp (v[1], "-a") == 0) {
173 verbose = 1;
174 gettype = T_ANY;
175 v++;
176 c--;
177 }
178 else if (strcmp (v[1], "-V") == 0) {
179 _res.options |= RES_USEVC;
180 v++;
181 c--;
182 }
183 }
184 if (c > 2) {
185 s = v[2];
186 server_specified++;
187
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);
197 }
198 _res.nsaddr= *(ipaddr_t *)hp->h_addr;
199 printf("Using domain server:\n");
200 printanswer(hp);
201 }
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));
210 }
211 printf(":\n");
212 }
213 }
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;
224 }
225
226 hp = NULL;
227 h_errno = TRY_AGAIN;
228/*
229 * we handle default domains ourselves, thank you
230 */
231 _res.options &= ~RES_DEFNAMES;
232
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);
247 }
248 oldcname = cname;
249 hp = NULL;
250 h_errno = TRY_AGAIN;
251 continue;
252 }
253 if (!waitmode)
254 break;
255 }
256
257 if (hp == NULL) {
258 hperror(h_errno);
259 exit(1);
260 }
261
262 exit(0);
263
264}
265
266static int
267parsetype(s)
268 char *s;
269{
270if (strcmp(s,"a") == 0)
271 return(1);
272if (strcmp(s,"ns") == 0)
273 return(2);
274if (strcmp(s,"md") == 0)
275 return(3);
276if (strcmp(s,"mf") == 0)
277 return(4);
278if (strcmp(s,"cname") == 0)
279 return(5);
280if (strcmp(s,"soa") == 0)
281 return(6);
282if (strcmp(s,"mb") == 0)
283 return(7);
284if (strcmp(s,"mg") == 0)
285 return(8);
286if (strcmp(s,"mr") == 0)
287 return(9);
288if (strcmp(s,"null") == 0)
289 return(10);
290if (strcmp(s,"wks") == 0)
291 return(11);
292if (strcmp(s,"ptr") == 0)
293 return(12);
294if (strcmp(s,"hinfo") == 0)
295 return(13);
296if (strcmp(s,"minfo") == 0)
297 return(14);
298if (strcmp(s,"mx") == 0)
299 return(15);
300if (strcmp(s,"txt") == 0) /* Roy */
301 return(T_TXT); /* Roy */
302if (strcmp(s,"uinfo") == 0)
303 return(100);
304if (strcmp(s,"uid") == 0)
305 return(101);
306if (strcmp(s,"gid") == 0)
307 return(102);
308if (strcmp(s,"unspec") == 0)
309 return(103);
310if (strcmp(s,"any") == 0)
311 return(255);
312if (strcmp(s,"*") == 0)
313 return(255);
314if (atoi(s))
315 return(atoi(s));
316fprintf(stderr, "Invalid query type: %s\n", s);
317exit(2);
318}
319
320static int
321parseclass(s)
322 char *s;
323{
324if (strcmp(s,"in") == 0)
325 return(C_IN);
326if (strcmp(s,"chaos") == 0)
327 return(C_CHAOS);
328if (strcmp(s,"hs") == 0)
329 return(C_HS);
330if (strcmp(s,"any") == 0)
331 return(C_ANY);
332if (atoi(s))
333 return(atoi(s));
334fprintf(stderr, "Invalid query class: %s\n", s);
335exit(2);
336}
337
338static void
339printanswer(hp)
340 register struct hostent *hp;
341{
342 register char **cp;
343 register ipaddr_t **hptr;
344
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");
353}
354
355static void
356hperror(errno)
357int errno;
358{
359switch(errno) {
360 case HOST_NOT_FOUND:
361 fprintf(stderr,"Host not found.\n");
362 break;
363 case TRY_AGAIN:
364 fprintf(stderr,"Host not found, try again.\n");
365 break;
366 case NO_RECOVERY:
367 fprintf(stderr,"No recovery, Host not found.\n");
368 break;
369 case NO_ADDRESS:
370 fprintf(stderr,"There is an entry for this host, but it doesn't have what you requested.\n");
371 break;
372 }
373}
374
375
376typedef union querybuf {
377 dns_hdr_t qb1;
378 u8_t qb2[PACKETSZ];
379} querybuf_t;
380
381static u8_t hostbuf[BUFSIZ+1];
382
383
384static int
385gethostinfo(name)
386 char *name;
387{
388 register char *cp, **domain;
389 int n;
390 int hp;
391 int nDomain;
392
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);
405 }
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));
411 }
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);
422 }
423 }
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);
431 }
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));
439}
440
441static int
442getdomaininfo(name, domain)
443 char *name, *domain;
444{
445 return getinfo(name, domain, gettype ? gettype : getdeftype);
446}
447
448static int
449getinfo(name, domain, type)
450 char *name, *domain;
451{
452
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];
459
460 if (domain == NULL)
461 (void)sprintf(host, "%.*s", MAXDNAME, name);
462 else
463 (void)sprintf(host, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
464
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);
472 }
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);
479 }
480 eom = (u8_t *)&answer + n;
481 return(printinfo(&answer, eom, T_ANY, 0));
482}
483
484static int
485printinfo(answer, eom, filter, isls)
486 querybuf_t *answer;
487 u8_t *eom;
488 int filter;
489 int isls;
490{
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;
495
496 /*
497 * find first satisfactory answer
498 */
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);
519 }
520 case SERVFAIL:
521 h_errno = TRY_AGAIN;
522 return(0);
523#ifdef OLDJEEVES
524 /*
525 * Jeeves (TOPS-20 server) still does not
526 * support MX records. For the time being,
527 * we must accept FORMERRs as the same as
528 * NOERROR.
529 */
530 case FORMERR:
531#endif /* OLDJEEVES */
532 case NOERROR:
533/* TpB - set a return error for this case. NO_DATA */
534 h_errno = NO_DATA;
535 return(0); /* was 1,but now indicates exception */
536#ifndef OLDJEEVES
537 case FORMERR:
538#endif /* OLDJEEVES */
539 case NOTIMP:
540 case REFUSED:
541 h_errno = NO_RECOVERY;
542 return(0);
543 }
544 return (0);
545 }
546 bp = hostbuf;
547 nmx = 0;
548 buflen = sizeof(hostbuf);
549 cp = (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;
554 }
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);
561/*
562 * When we ask for address and there is a CNAME, it seems to return
563 * both the CNAME and the address. Since we trace down the CNAME
564 * chain ourselves, we don't really want to print the address at
565 * this point.
566 */
567 if (cname && ! verbose)
568 return (1);
569 }
570 }
571 if (! verbose)
572 return (1);
573 if (nscount) {
574 printf("For authoritative answers, see:\n");
575 while (--nscount >= 0 && cp && cp < eom) {
576 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
577 }
578 }
579 if (arcount) {
580 printf("Additional information:\n");
581 while (--arcount >= 0 && cp && cp < eom) {
582 cp = pr_rr(cp, (u8_t *)answer, stdout, filter);
583 }
584 }
585 return(1);
586 }
587
588static u8_t cnamebuf[MAXDNAME];
589
590/*
591 * Print resource record fields in human readable form.
592 */
593static u8_t *
594pr_rr(cp, msg, file, filter)
595 u8_t *cp, *msg;
596 FILE *file;
597 int filter;
598{
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];
607
608 if ((cp = pr_cdname(cp, msg, name, sizeof(name))) == NULL)
609 return (NULL); /* compression error */
610
611 type = _getshort(cp);
612 cp += sizeof(u_short);
613
614 class = _getshort(cp);
615 cp += sizeof(u_short);
616
617 ttl = _getlong(cp);
618 cp += sizeof(u_long);
619
620 if (filter == type || filter == T_ANY ||
621 (filter == T_A && (type == T_PTR || type == T_NS)))
622 doprint = 1;
623 else
624 doprint = 0;
625
626 if (doprint)
627 if (verbose)
628 fprintf(file,"%s\t%d%s\t%s",
629 name, ttl, pr_class(class), pr_type(type));
630 else
631 fprintf(file,"%s%s %s",name, pr_class(class), pr_type(type));
632 if (verbose)
633 punc = '\t';
634 else
635 punc = ' ';
636
637 dlen = _getshort(cp);
638 cp += sizeof(u_short);
639 cp1 = cp;
640 /*
641 * Print type specific data, if appropriate
642 */
643 switch (type) {
644 case T_A:
645 switch (class) {
646 case C_IN:
647 bcopy((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]);
660 }
661 cp += dlen;
662 }
663 break;
664 }
665 break;
666 case T_CNAME:
667 if (dn_expand(msg, msg + 512, cp, cnamebuf,
668 sizeof(cnamebuf)-1) >= 0) {
669 strcat((char *) cnamebuf, ".");
670 if (gettype != T_CNAME && gettype != T_ANY)
671 cname = cnamebuf;
672 }
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;
686
687 case T_HINFO:
688 if (n = *cp++) {
689 if (doprint)
690 fprintf(file,"%c%.*s", punc, n, cp);
691 cp += n;
692 }
693 if (n = *cp++) {
694 if (doprint)
695 fprintf(file,"%c%.*s", punc, n, cp);
696 cp += n;
697 }
698 break;
699
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;
723
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;
735
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;
744
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;
751 }
752 break;
753 /* Roy end */
754
755 case T_UINFO:
756 if (doprint)
757 fprintf(file,"%c%s", punc, cp);
758 cp += dlen;
759 break;
760
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);
767 }
768 break;
769
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);
784
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);
799 }
800 c <<= 1;
801 } while (++n & 07);
802 }
803 break;
804
805 default:
806 if (doprint)
807 fprintf(file,"%c???", punc);
808 cp += dlen;
809 }
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);
815}
816
817static char nbuf[20];
818
819/*
820 * Return a string for the type
821 */
822static char *
823pr_type(type)
824 int type;
825{
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);
879 }
880}
881
882/*
883 * Return a mnemonic for class
884 */
885static char *
886pr_class(class)
887 int class;
888{
889
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);
901 }
902}
903
904static u8_t *
905pr_cdname(cp, msg, name, namelen)
906 u8_t *cp, *msg;
907 u8_t *name;
908 int namelen;
909{
910 int n;
911
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';
917 }
918 return (cp + n);
919}
920
921char *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",
938};
939
940
941
942
943/*
944 ******************************************************************************
945 *
946 * ListHosts --
947 *
948 * Requests the name server to do a zone transfer so we
949 * find out what hosts it knows about.
950 *
951 * Results:
952 * SUCCESS the listing was successful.
953 * ERROR the server could not be contacted because
954 * a socket could not be obtained or an error
955 * occured while receiving, or the output file
956 * could not be opened.
957 *
958 ******************************************************************************
959 */
960
961static int
962ListHosts(namePtr, queryType)
963 char *namePtr;
964 int queryType; /* e.g. T_A */
965{
966 querybuf_t buf, answer;
967 dns_hdr_t *headerPtr;
968
969 int msglen;
970 int amtToRead;
971 int numRead;
972 int i;
973 int numAnswers = 0;
974 int result;
975 int soacnt = 0;
976 u_short len;
977 int dlen;
978 int type;
979 int nscount;
980 u8_t *cp, *nmp;
981 u8_t name[NAME_LEN];
982 char dname[2][NAME_LEN];
983 u8_t domain[NAME_LEN];
984/* names and addresses of name servers to try */
985#define NUMNS 8
986 char nsname[NUMNS][NAME_LEN];
987 int nshaveaddr[NUMNS];
988#define IPADDRSIZE 4
989#define NUMNSADDR 16
990 char nsipaddr[NUMNSADDR][IPADDRSIZE];
991 int numns;
992 int numnsaddr;
993 int thisns;
994 struct hostent *hp;
995 enum {
996 NO_ERRORS,
997 ERR_READING_LEN,
998 ERR_READING_MSG,
999 ERR_PRINTING
1000 } error = NO_ERRORS;
1001 char *tcp_serv_name;
1002 int tcp_fd;
1003 nwio_tcpconf_t tcpconf;
1004 nwio_tcpcl_t clopt;
1005 int terrno;
1006
1007/*
1008 * normalize to not have trailing dot. We do string compares below
1009 * of info from name server, and it won't have trailing dots.
1010 */
1011 i = strlen(namePtr);
1012 if (namePtr[i-1] == '.')
1013 namePtr[i-1] = 0;
1014
1015 if (server_specified) {
1016 bcopy((char *)&_res.nsaddr, nsipaddr[0], IPADDRSIZE);
1017 numnsaddr = 1;
1018 }
1019 else {
1020
1021/*
1022 * First we have to find out where to look. This needs a NS query,
1023 * possibly followed by looking up addresses for some of the names.
1024 */
1025
1026 msglen = res_mkquery(QUERY, namePtr, C_IN, T_NS,
1027 (char *)0, 0, (struct rrec *)0,
1028 (char *)&buf, sizeof(buf));
1029
1030 if (msglen < 0) {
1031 printf("res_mkquery failed\n");
1032 return (ERROR);
1033 }
1034
1035 msglen = res_send((char *)&buf,msglen,(char *)&answer, sizeof(answer));
1036
1037 if (msglen < 0) {
1038 printf("Unable to get to nameserver -- try again later\n");
1039 return (ERROR);
1040 }
1041 if (_res.options & RES_DEBUG || verbose)
1042 printf("rcode = %d (%s), ancount=%d\n",
1043 answer.qb1.dh_flag2 & DHF_RCODE,
1044 DecodeError(answer.qb1.dh_flag2 & DHF_RCODE),
1045 ntohs(answer.qb1.dh_ancount));
1046
1047/*
1048 * Analyze response to our NS lookup
1049 */
1050
1051 nscount = ntohs(answer.qb1.dh_ancount) + ntohs(answer.qb1.dh_nscount) +
1052 ntohs(answer.qb1.dh_arcount);
1053
1054 if (answer.qb1.dh_flag2 & DHF_RCODE != NOERROR || nscount == 0) {
1055 switch (answer.qb1.dh_flag2 & DHF_RCODE) {
1056 case NXDOMAIN:
1057 /* Check if it's an authoritive answer */
1058 if (answer.qb1.dh_flag1 & DHF_AA) {
1059 printf("No such domain\n");
1060 } else {
1061 printf("Unable to get information about domain -- try again later.\n");
1062 }
1063 break;
1064 case SERVFAIL:
1065 printf("Unable to get information about that domain -- try again later.\n");
1066 break;
1067 case NOERROR:
1068 printf("That domain exists, but seems to be a leaf node.\n");
1069 break;
1070 case FORMERR:
1071 case NOTIMP:
1072 case REFUSED:
1073 printf("Unrecoverable error looking up domain name.\n");
1074 break;
1075 }
1076 return (0);
1077 }
1078
1079 cp = answer.qb2 + sizeof(dns_hdr_t);
1080 if (ntohs(answer.qb1.dh_qdcount) > 0)
1081 cp += dn_skipname(cp, answer.qb2 + msglen) + QFIXEDSZ;
1082
1083 numns = 0;
1084 numnsaddr = 0;
1085
1086/*
1087 * Look at response from NS lookup for NS and A records.
1088 */
1089
1090 for (;nscount; nscount--) {
1091 cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1092 domain, sizeof(domain));
1093 type = _getshort(cp);
1094 cp += sizeof(u_short) + sizeof(u_short) + sizeof(u_long);
1095 dlen = _getshort(cp);
1096 cp += sizeof(u_short);
1097 if (type == T_NS) {
1098 if (dn_expand(answer.qb2, answer.qb2 + msglen, cp,
1099 name, sizeof(name)) >= 0) {
1100 if (numns < NUMNS && strcasecmp((char *)domain, namePtr) == 0) {
1101 for (i = 0; i < numns; i++)
1102 if (strcasecmp(nsname[i], (char *)name) == 0)
1103 break; /* duplicate */
1104 if (i >= numns) {
1105 strncpy(nsname[numns], (char *)name, sizeof(name));
1106 nshaveaddr[numns] = 0;
1107 numns++;
1108 }
1109 }
1110 }
1111 }
1112 else if (type == T_A) {
1113 if (numnsaddr < NUMNSADDR)
1114 for (i = 0; i < numns; i++) {
1115 if (strcasecmp(nsname[i], (char *)domain) == 0) {
1116 nshaveaddr[i]++;
1117 bcopy((char *)cp, nsipaddr[numnsaddr],IPADDRSIZE);
1118 numnsaddr++;
1119 break;
1120 }
1121 }
1122 }
1123 cp += dlen;
1124 }
1125
1126/*
1127 * Usually we'll get addresses for all the servers in the additional
1128 * info section. But in case we don't, look up their addresses.
1129 */
1130
1131 for (i = 0; i < numns; i++) {
1132 if (! nshaveaddr[i]) {
1133 register long **hptr;
1134 int numaddrs = 0;
1135
1136 hp = gethostbyname(nsname[i]);
1137 if (hp) {
1138 for (hptr = (long **)hp->h_addr_list; *hptr; hptr++)
1139 if (numnsaddr < NUMNSADDR) {
1140 bcopy((char *)*hptr, nsipaddr[numnsaddr],IPADDRSIZE);
1141 numnsaddr++;
1142 numaddrs++;
1143 }
1144 }
1145 if (_res.options & RES_DEBUG || verbose)
1146 printf("Found %d addresses for %s by extra query\n",
1147 numaddrs, nsname[i]);
1148 }
1149 else
1150 if (_res.options & RES_DEBUG || verbose)
1151 printf("Found %d addresses for %s\n",
1152 nshaveaddr[i], nsname[i]);
1153 }
1154 }
1155/*
1156 * Now nsipaddr has numnsaddr addresses for name servers that
1157 * serve the requested domain. Now try to find one that will
1158 * accept a zone transfer.
1159 */
1160
1161 thisns = 0;
1162
1163again:
1164
1165 numAnswers = 0;
1166 soacnt = 0;
1167
1168 /*
1169 * Create a query packet for the requested domain name.
1170 *
1171 */
1172 msglen = res_mkquery(QUERY, namePtr, getclass, T_AXFR,
1173 (char *)0, 0, (struct rrec *)0,
1174 (char *) &buf, sizeof(buf));
1175 if (msglen < 0) {
1176 if (_res.options & RES_DEBUG) {
1177 fprintf(stderr, "ListHosts: Res_mkquery failed\n");
1178 }
1179 return (ERROR);
1180 }
1181
1182 /*
1183 * Set up a virtual circuit to the server.
1184 */
1185
1186 tcp_serv_name= getenv("TCP_DEVICE");
1187 if (!tcp_serv_name)
1188 tcp_serv_name= TCP_DEVICE;
1189 for (;thisns < numnsaddr; thisns++)
1190 {
1191 tcp_fd= open(tcp_serv_name, O_RDWR);
1192 if (tcp_fd == -1)
1193 {
1194 fprintf(stderr, "unable to open '%s': %s\n", tcp_serv_name,
1195 strerror(errno));
1196 return ERROR;
1197 }
1198
1199 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
1200 NWTC_SET_RP;
1201 tcpconf.nwtc_remaddr= *(ipaddr_t *)nsipaddr[thisns];
1202 tcpconf.nwtc_remport= _res.nsport_list[0];
1203 result= ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf);
1204 if (result == -1)
1205 {
1206 fprintf(stderr, "tcp_ioc_setconf failed: %s\n",
1207 strerror(errno));
1208 close(tcp_fd);
1209 return ERROR;
1210 }
1211 if (_res.options & RES_DEBUG || verbose)
1212 printf("Trying %s\n", inet_ntoa(tcpconf.nwtc_remaddr));
1213 clopt.nwtcl_flags= 0;
1214 result= ioctl(tcp_fd, NWIOTCPCONN, &clopt);
1215 if (result == 0)
1216 break;
1217 terrno= errno;
1218 if (verbose)
1219 fprintf(stderr,
1220 "Connection failed, trying next server: %s\n",
1221 strerror(errno));
1222 close(tcp_fd);
1223 }
1224 if (thisns >= numnsaddr) {
1225 printf("No server for that domain responded\n");
1226 if (!verbose)
1227 fprintf(stderr, "Error from the last server was: %s\n",
1228 strerror(terrno));
1229 return(ERROR);
1230 }
1231
1232 /*
1233 * Send length & message for zone transfer
1234 */
1235
1236 len = htons(msglen);
1237
1238 result= tcpip_writeall(tcp_fd, (char *)&len, sizeof(len));
1239 if (result != sizeof(len))
1240 {
1241 fprintf(stderr, "write failed: %s\n", strerror(errno));
1242 close(tcp_fd);
1243 return ERROR;
1244 }
1245 result= tcpip_writeall(tcp_fd, (char *)&buf, msglen);
1246 if (result != msglen)
1247 {
1248 fprintf(stderr, "write failed: %s\n",
1249 strerror(errno));
1250 close(tcp_fd);
1251 return ERROR;
1252 }
1253 filePtr = stdout;
1254
1255 while (1) {
1256
1257 /*
1258 * Read the length of the response.
1259 */
1260
1261 cp = (u8_t *) &buf;
1262 amtToRead = sizeof(u_short);
1263 while(amtToRead > 0)
1264 {
1265 result = read(tcp_fd, (char *)cp, amtToRead);
1266 if (result <= 0)
1267 break;
1268 cp += result;
1269 amtToRead -= result;
1270 }
1271 if (amtToRead) {
1272 error = ERR_READING_LEN;
1273 break;
1274 }
1275
1276 if ((len = htons(*(u_short *)&buf)) == 0) {
1277 break; /* nothing left to read */
1278 }
1279
1280 /*
1281 * Read the response.
1282 */
1283
1284 amtToRead = len;
1285 cp = (u8_t *) &buf;
1286 while(amtToRead > 0)
1287 {
1288 result = read(tcp_fd, (char *)cp, amtToRead);
1289 if (result<= 0)
1290 break;
1291 cp += result;
1292 amtToRead -= result;
1293 }
1294 if (amtToRead) {
1295 error = ERR_READING_MSG;
1296 break;
1297 }
1298
1299 i = buf.qb1.dh_flag2 & DHF_RCODE;
1300 if (i != NOERROR || ntohs(buf.qb1.dh_ancount) == 0) {
1301 if ((thisns+1) < numnsaddr &&
1302 (i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
1303 if (_res.options & RES_DEBUG || verbose)
1304 printf("Server failed, trying next server: %s\n",
1305 i != NOERROR ?
1306 DecodeError(i) : "Premature end of data");
1307 close(tcp_fd);
1308 thisns++;
1309 goto again;
1310 }
1311 printf("Server failed: %s\n",
1312 i != NOERROR ? DecodeError(i) : "Premature end of data");
1313 break;
1314 }
1315
1316
1317 result = printinfo(&buf, cp, queryType, 1);
1318 if (! result) {
1319 error = ERR_PRINTING;
1320 break;
1321 }
1322 numAnswers++;
1323 cp = buf.qb2 + sizeof(dns_hdr_t);
1324 if (ntohs(buf.qb1.dh_qdcount) > 0)
1325 cp += dn_skipname(cp, buf.qb2 + len) + QFIXEDSZ;
1326
1327 nmp = cp;
1328 cp += dn_skipname(cp, (u_char *)&buf + len);
1329 if ((_getshort(cp) == T_SOA)) {
1330 dn_expand(buf.qb2, buf.qb2 + len, nmp, (u8_t *)dname[soacnt],
1331 sizeof(dname[0]));
1332 if (soacnt) {
1333 if (strcmp(dname[0], dname[1]) == 0)
1334 break;
1335 } else
1336 soacnt++;
1337 }
1338 }
1339
1340 close(tcp_fd);
1341
1342 switch (error) {
1343 case NO_ERRORS:
1344 return (SUCCESS);
1345
1346 case ERR_READING_LEN:
1347 return(ERROR);
1348
1349 case ERR_PRINTING:
1350 fprintf(stderr,"*** Error during listing of %s: %s\n",
1351 namePtr, DecodeError(result));
1352 return(result);
1353
1354 case ERR_READING_MSG:
1355 headerPtr = (dns_hdr_t *) &buf;
1356 fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
1357 fprintf(stderr,
1358 " result: %s, answers = %d, authority = %d, additional = %d\n",
1359 resultcodes[headerPtr->dh_flag2 & DHF_RCODE],
1360 ntohs(headerPtr->dh_ancount),
1361 ntohs(headerPtr->dh_nscount),
1362 ntohs(headerPtr->dh_arcount));
1363 return(ERROR);
1364 default:
1365 return(ERROR);
1366 }
1367}
1368
1369static char *
1370DecodeError(result)
1371 int result;
1372{
1373 switch(result) {
1374 case NOERROR: return("Success"); break;
1375 case FORMERR: return("Format error"); break;
1376 case SERVFAIL: return("Server failed"); break;
1377 case NXDOMAIN: return("Non-existent domain"); break;
1378 case NOTIMP: return("Not implemented"); break;
1379 case REFUSED: return("Query refused"); break;
1380 case NOCHANGE: return("No change"); break;
1381 case NO_INFO: return("No information"); break;
1382 case ERROR: return("Unspecified error"); break;
1383 case TIME_OUT: return("Timed out"); break;
1384 case NONAUTH: return("Non-authoritative answer"); break;
1385 default: break;
1386 }
1387 return("BAD ERROR VALUE");
1388}
1389
1390static int tcpip_writeall(fd, buf, siz)
1391int fd;
1392char *buf;
1393unsigned siz;
1394{
1395 unsigned siz_org;
1396 int nbytes;
1397
1398 siz_org= siz;
1399
1400 while (siz)
1401 {
1402 nbytes= write(fd, buf, siz);
1403 if (nbytes == -1)
1404 return nbytes;
1405 assert(siz >= nbytes);
1406 buf += nbytes;
1407 siz -= nbytes;
1408 }
1409 return siz_org;
1410}
Note: See TracBrowser for help on using the repository browser.