|
|
1.1 root 1: /*
2: * Copyright (c) 1985 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: #ifndef lint
14: static char sccsid[] = "@(#)getinfo.c 5.16 (Berkeley) 3/11/88";
15: #endif /* not lint */
16:
17: /*
18: *******************************************************************************
19: *
20: * getinfo.c --
21: *
22: * Routines to create requests to name servers
23: * and interpret the answers.
24: *
25: * Adapted from 4.3BSD BIND gethostnamadr.c
26: *
27: *******************************************************************************
28: */
29:
30: #include <sys/types.h>
31: #include <sys/socket.h>
32: #include <netinet/in.h>
33: #include <stdio.h>
34: #include <ctype.h>
35: #include <arpa/nameser.h>
36: #include <resolv.h>
37: #include "res.h"
38:
39: extern char *_res_resultcodes[];
40: extern char *res_skip();
41:
42: #define MAXALIASES 35
43: #define MAXADDRS 35
44: #define MAXDOMAINS 35
45: #define MAXSERVERS 10
46:
47: static char *addr_list[MAXADDRS + 1];
48:
49: static char *host_aliases[MAXALIASES];
50: static int host_aliases_len[MAXALIASES];
51: static char hostbuf[BUFSIZ+1];
52:
53: typedef struct {
54: char *name;
55: char *domain[MAXDOMAINS];
56: int numDomains;
57: char *address[MAXADDRS];
58: int numAddresses;
59: } ServerTable;
60:
61: ServerTable server[MAXSERVERS];
62:
63: typedef union {
64: HEADER qb1;
65: char qb2[PACKETSZ];
66: } querybuf;
67:
68: static union {
69: long al;
70: char ac;
71: } align;
72:
73:
74: /*
75: *******************************************************************************
76: *
77: * GetAnswer --
78: *
79: * Interprets an answer packet and retrieves the following
80: * information:
81: *
82: * Results:
83: * SUCCESS the info was retrieved.
84: * NO_INFO the packet did not contain an answer.
85: * NONAUTH non-authoritative information was found.
86: * ERROR the answer was malformed.
87: * Other errors returned in the packet header.
88: *
89: *******************************************************************************
90: */
91:
92: static int
93: GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isserver)
94: struct in_addr *nsAddrPtr;
95: char *msg;
96: int queryType;
97: int msglen;
98: int iquery;
99: register HostInfo *hostPtr;
100: int isserver;
101: {
102: register HEADER *headerPtr;
103: register char *cp;
104: querybuf answer;
105: char *eom, *bp, **aliasPtr;
106: char **addrPtr;
107: char *namePtr;
108: char *dnamePtr;
109: int type, class;
110: int qdcount, ancount, arcount, nscount, buflen;
111: int haveanswer, getclass;
112: int numAliases = 0;
113: int numAddresses = 0;
114: int n, i, j;
115: int len;
116: int dlen;
117: int status;
118: int numServers;
119: int found;
120:
121:
122: /*
123: * If the hostPtr was used before, free up
124: * the calloc'd areas.
125: */
126: FreeHostInfoPtr(hostPtr);
127:
128: status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer,
129: sizeof(answer), &n, !isserver);
130:
131: if (status != SUCCESS) {
132: if (_res.options & RES_DEBUG2)
133: printf("SendRequest failed\n");
134: return (status);
135: }
136: eom = (char *) &answer + n;
137:
138: headerPtr = (HEADER *) &answer;
139: qdcount = ntohs(headerPtr->qdcount);
140: ancount = ntohs(headerPtr->ancount);
141: arcount = ntohs(headerPtr->arcount);
142: nscount = ntohs(headerPtr->nscount);
143:
144: if (headerPtr->rcode != NOERROR) {
145: if (_res.options & RES_DEBUG && !isserver) {
146: printf(
147: "Failed: %s, num. answers = %d, ns = %d, additional = %d\n",
148: _res_resultcodes[headerPtr->rcode], ancount, nscount,
149: arcount);
150: }
151: return (headerPtr->rcode);
152: }
153:
154: /*
155: * If there are no answer, n.s. or additional records
156: * then return with an error.
157: */
158: if (ancount == 0 && nscount == 0 && arcount == 0) {
159: return (NO_INFO);
160: }
161:
162:
163: bp = hostbuf;
164: buflen = sizeof(hostbuf);
165: cp = (char *) &answer + sizeof(HEADER);
166:
167: /*
168: * For inverse queries, the desired information is returned
169: * in the question section. If there are no question records,
170: * return with an error.
171: *
172: */
173: if (qdcount) {
174: if (iquery) {
175: if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) {
176: return (ERROR);
177: }
178: cp += n + QFIXEDSZ;
179: len = strlen(bp) + 1;
180: hostPtr->name = Calloc((unsigned)1, (unsigned)len);
181: bcopy(bp, hostPtr->name, len);
182: } else {
183: cp += dn_skipname(cp, eom) + QFIXEDSZ;
184: }
185: while (--qdcount > 0) {
186: cp += dn_skipname(cp, eom) + QFIXEDSZ;
187: }
188: } else if (iquery) {
189: return (NO_INFO);
190: }
191:
192: aliasPtr = host_aliases;
193: addrPtr = addr_list;
194: haveanswer = 0;
195:
196: /*
197: * Scan through the answer resource records.
198: * Answers for address query types are saved.
199: * Other query type answers are just printed.
200: */
201: if (isserver == 0 && !headerPtr->aa && headerPtr->ancount)
202: printf("Non-authoritative answer:\n");
203: while (--ancount >= 0 && cp < eom) {
204: if (queryType != T_A) {
205: if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) {
206: return(ERROR);
207: }
208: continue;
209: } else {
210: if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
211: return(ERROR);
212: }
213: cp += n;
214: type = _getshort(cp);
215: cp += sizeof(u_short);
216: class = _getshort(cp);
217: cp += sizeof(u_short) + sizeof(u_long);
218: dlen = _getshort(cp);
219: cp += sizeof(u_short);
220: if (type == T_CNAME) {
221: /*
222: * Found an alias.
223: */
224: cp += dlen;
225: if (aliasPtr >= &host_aliases[MAXALIASES-1])
226: continue;
227: *aliasPtr++ = bp;
228: n = strlen(bp) + 1;
229: host_aliases_len[numAliases] = n;
230: numAliases++;
231: bp += n;
232: buflen -= n;
233: continue;
234: } else if (type == T_PTR) {
235: /*
236: * Found a "pointer" to the real name.
237: */
238: if((n= dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0){
239: cp += n;
240: continue;
241: }
242: cp += n;
243: len = strlen(bp) + 1;
244: hostPtr->name = Calloc((unsigned)1, (unsigned)len);
245: bcopy(bp, hostPtr->name, len);
246: haveanswer = 1;
247: break;
248: } else if (type != T_A) {
249: cp += dlen;
250: continue;
251: }
252: if (haveanswer) {
253: if (n != hostPtr->addrLen) {
254: cp += dlen;
255: continue;
256: }
257: if (class != getclass) {
258: cp += dlen;
259: continue;
260: }
261: } else {
262: hostPtr->addrLen = dlen;
263: getclass = class;
264: hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC;
265: if (!iquery) {
266: len = strlen(bp) + 1;
267: hostPtr->name = Calloc((unsigned)1, (unsigned)len);
268: bcopy(bp, hostPtr->name, len);
269: }
270: }
271: bp += (((u_long)bp) % sizeof(align));
272:
273: if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) {
274: if (_res.options & RES_DEBUG)
275: printf("Size (%d) too big\n", dlen);
276: break;
277: }
278: bcopy(cp, *addrPtr++ = bp, dlen);
279: bp +=dlen;
280: cp += dlen;
281: numAddresses++;
282: haveanswer = 1;
283: }
284: }
285:
286: if (queryType == T_A && haveanswer) {
287:
288: /*
289: * Go through the alias and address lists and return them
290: * in the hostPtr variable.
291: */
292:
293: if (numAliases > 0) {
294: hostPtr->aliases = (char **) Calloc((unsigned)1+numAliases,
295: sizeof(char *));
296: for (i = 0; i < numAliases; i++) {
297: hostPtr->aliases[i] = Calloc((unsigned)1, (unsigned)host_aliases_len[i]);
298: bcopy(host_aliases[i], hostPtr->aliases[i],
299: host_aliases_len[i]);
300: }
301: hostPtr->aliases[i] = NULL;
302: }
303: if (numAddresses > 0) {
304: hostPtr->addrList = (char **) Calloc((unsigned)1+numAddresses,
305: sizeof(char *));
306: for (i = 0; i < numAddresses; i++) {
307: hostPtr->addrList[i] = Calloc((unsigned)1, (unsigned)hostPtr->addrLen);
308: bcopy(addr_list[i], hostPtr->addrList[i],
309: hostPtr->addrLen);
310: }
311: hostPtr->addrList[i] = NULL;
312: }
313: hostPtr->servers= NULL;
314: return (SUCCESS);
315: }
316:
317: /*
318: * At this point, for the T_A query type, only empty answers remain.
319: * For other query types, additional information might be found
320: * in the additional resource records part.
321: */
322:
323: cp = res_skip((char *) &answer, 2, eom);
324:
325: numServers = 0;
326: while (--nscount >= 0 && cp < eom) {
327: /*
328: * Go through the NS records and retrieve the
329: * names of hosts that server the requested domain,
330: * their addresses and other domains they might serve.
331: */
332:
333: if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
334: return(ERROR);
335: }
336: cp += n;
337: len = strlen(bp) + 1;
338: dnamePtr = Calloc((unsigned)1, (unsigned)len); /* domain name */
339: bcopy(bp, dnamePtr, len);
340:
341: type = _getshort(cp);
342: cp += sizeof(u_short);
343: class = _getshort(cp);
344: cp += sizeof(u_short) + sizeof(u_long);
345: dlen = _getshort(cp);
346: cp += sizeof(u_short);
347:
348: if (type != T_NS) {
349: cp += dlen;
350: } else {
351: if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
352: return(ERROR);
353: }
354: cp += n;
355: len = strlen(bp) + 1;
356: namePtr = Calloc((unsigned)1, (unsigned)len); /* server host name */
357: bcopy(bp, namePtr, len);
358:
359: /*
360: * Store the information keyed by the server host name.
361: */
362: found = FALSE;
363: for (j = 0; j < numServers; j++) {
364: if (strcmp(namePtr, server[j].name) == 0) {
365: found = TRUE;
366: free(namePtr);
367: break;
368: }
369: }
370: if (found) {
371: server[j].numDomains++;
372: if (server[j].numDomains <= MAXDOMAINS) {
373: server[j].domain[server[j].numDomains-1] = dnamePtr;
374: }
375: } else {
376: if (numServers > MAXSERVERS) {
377: break;
378: }
379: numServers++;
380: server[numServers -1].name = namePtr;
381: server[numServers -1].domain[0] = dnamePtr;
382: server[numServers -1].numDomains = 1;
383: server[numServers -1].numAddresses = 0;
384: }
385: }
386: }
387:
388: if (!headerPtr->aa && (queryType != T_A) && arcount > 0) {
389: printf("Authoritative answers can be found from:\n");
390: }
391:
392: /*
393: * Additional resource records contain addresses of
394: * servers.
395: */
396: cp = res_skip((char *) &answer, 3, eom);
397: while (--arcount >= 0 && cp < eom) {
398: /*
399: * If we don't need to save the record, just print it.
400: */
401: if (queryType != T_A) {
402: if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) {
403: return(ERROR);
404: }
405: continue;
406:
407: } else {
408: if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0)
409: break;
410: cp += n;
411: type = _getshort(cp);
412: cp += sizeof(u_short);
413: class = _getshort(cp);
414: cp += sizeof(u_short) + sizeof(u_long);
415: dlen = _getshort(cp);
416: cp += sizeof(u_short);
417:
418: if (type != T_A) {
419: cp += dlen;
420: continue;
421: } else {
422: for (j = 0; j < numServers; j++) {
423: if (strcmp(bp, server[j].name) == 0) {
424: server[j].numAddresses++;
425: if (server[j].numAddresses <= MAXADDRS) {
426: server[j].address[server[j].numAddresses-1]=Calloc((unsigned)1,(unsigned)dlen);
427: bcopy(cp,server[j].address[server[j].numAddresses-1],dlen);
428: break;
429: }
430: }
431: }
432: cp += dlen;
433: }
434: }
435: }
436:
437: /*
438: * If we are returning name server info, transfer it to
439: * the hostPtr.
440: *
441: */
442: if (numServers > 0) {
443: hostPtr->servers = (ServerInfo **) Calloc((unsigned)numServers+1,
444: sizeof(ServerInfo *));
445: for (i = 0; i < numServers; i++) {
446: hostPtr->servers[i] = (ServerInfo *) Calloc((unsigned)1, sizeof(ServerInfo));
447: hostPtr->servers[i]->name = server[i].name;
448:
449:
450: hostPtr->servers[i]->domains = (char **)
451: Calloc((unsigned)server[i].numDomains+1,sizeof(char *));
452: for (j = 0; j < server[i].numDomains; j++) {
453: hostPtr->servers[i]->domains[j] = server[i].domain[j];
454: }
455: hostPtr->servers[i]->domains[j] = NULL;
456:
457:
458: hostPtr->servers[i]->addrList = (char **)
459: Calloc((unsigned)server[i].numAddresses+1,sizeof(char *));
460: for (j = 0; j < server[i].numAddresses; j++) {
461: hostPtr->servers[i]->addrList[j] = server[i].address[j];
462: }
463: hostPtr->servers[i]->addrList[j] = NULL;
464:
465: }
466: hostPtr->servers[i] = NULL;
467: }
468:
469:
470: if (queryType != T_A) {
471: return(SUCCESS);
472: } else {
473: return(NONAUTH);
474: }
475: }
476:
477: /*
478: *******************************************************************************
479: *
480: * GetHostInfo --
481: *
482: * Retrieves host name, address and alias information
483: * for a domain.
484: *
485: * Results:
486: * ERROR - res_mkquery failed.
487: * + return values from GetAnswer()
488: *
489: *******************************************************************************
490: */
491:
492: int
493: GetHostInfo(nsAddrPtr, queryClass, queryType, name, hostPtr, isserver)
494: struct in_addr *nsAddrPtr;
495: int queryClass;
496: int queryType;
497: char *name;
498: HostInfo *hostPtr;
499: int isserver;
500: {
501: int n;
502: int result;
503: register char *cp, **domain;
504: querybuf buf;
505: extern char *Calloc(), *hostalias();
506:
507: /* catch explicit addresses */
508: if (isdigit(*name) && (queryType == T_A)) {
509: long ina;
510:
511: ina = inet_addr(name);
512:
513: if (ina == -1)
514: return(ERROR);
515:
516: hostPtr->name = Calloc((unsigned)strlen(name)+3,1);
517: (void)sprintf(hostPtr->name,"[%s]",name);
518: hostPtr->aliases = 0;
519: hostPtr->servers = 0;
520: hostPtr->addrType = AF_INET;
521: hostPtr->addrLen = 4;
522: hostPtr->addrList = (char **)Calloc((unsigned)2,sizeof(char *));
523: hostPtr->addrList[0] = Calloc(sizeof(long),sizeof(char));
524: bcopy((char *)&ina,hostPtr->addrList[0],sizeof(ina));
525: hostPtr->addrList[1] = 0;
526:
527: return(SUCCESS);
528: }
529:
530: for (cp = name, n = 0; *cp; cp++)
531: if (*cp == '.')
532: n++;
533: if ((n && *--cp == '.') ||
534: (isserver == 0 && (_res.options & RES_DEFNAMES) == 0)) {
535: int defflag = _res.options & RES_DEFNAMES;
536:
537: _res.options &= ~RES_DEFNAMES;
538: if (n && *cp == '.')
539: *cp = 0;
540: result = GetHostDomain(nsAddrPtr, queryClass, queryType,
541: name, (char *)NULL, hostPtr, isserver);
542: if (n && *cp == 0)
543: *cp = '.';
544: if (defflag)
545: _res.options |= RES_DEFNAMES;
546: return (result);
547: }
548: if (n == 0 && (cp = hostalias(name)))
549: return (GetHostDomain(nsAddrPtr, queryClass, queryType,
550: cp, (char *)NULL, hostPtr, isserver));
551: for (domain = _res.dnsrch; *domain; domain++) {
552: result = GetHostDomain(nsAddrPtr, queryClass, queryType,
553: name, *domain, hostPtr, isserver);
554: if ((result != NXDOMAIN && result != NO_INFO) ||
555: (_res.options & RES_DNSRCH) == 0)
556: return (result);
557: }
558: if (n)
559: return (GetHostDomain(nsAddrPtr, queryClass, queryType,
560: name, (char *)NULL, hostPtr, isserver));
561: return (result);
562: }
563:
564: GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isserver)
565: struct in_addr *nsAddrPtr;
566: int queryClass;
567: int queryType;
568: char *name, *domain;
569: HostInfo *hostPtr;
570: int isserver;
571: {
572: querybuf buf;
573: char nbuf[2*MAXDNAME+2];
574: int n;
575:
576: if (domain) {
577: (void)sprintf(nbuf, "%.*s.%.*s",
578: MAXDNAME, name, MAXDNAME, domain);
579: name = nbuf;
580: }
581: n = res_mkquery(QUERY, name, queryClass, queryType,
582: (char *)0, 0, (char *)0, (char *) &buf, sizeof(buf));
583: if (n < 0) {
584: if (_res.options & RES_DEBUG) {
585: printf("Res_mkquery failed\n");
586: }
587: return (ERROR);
588: }
589:
590: n = GetAnswer(nsAddrPtr, queryType, (char *) &buf, n, 0, hostPtr,
591: isserver);
592:
593: /*
594: * GetAnswer didn't find a name, so set it to the specified one.
595: */
596: if (n == NONAUTH) {
597: if (hostPtr->name == NULL) {
598: int len = strlen(name) + 1;
599: hostPtr->name = Calloc((unsigned)len, sizeof(char));
600: bcopy(name, hostPtr->name, len);
601: }
602: }
603: return(n);
604: }
605:
606:
607: /*
608: *******************************************************************************
609: *
610: * FindHostInfo --
611: *
612: * Performs an inverse query to find the host name
613: * that corresponds to the given address.
614: *
615: * Results:
616: * ERROR - res_mkquery failed.
617: * + return values from GetAnswer()
618: *
619: *******************************************************************************
620: */
621:
622: int
623: FindHostInfo(nsAddrPtr, address, len, hostPtr)
624: struct in_addr *nsAddrPtr;
625: struct in_addr *address;
626: int len;
627: HostInfo *hostPtr;
628: {
629: int n;
630: querybuf buf;
631:
632: n = res_mkquery(IQUERY, (char *)0, C_IN, T_A,
633: (char *)address, len, (char *)0, (char *) &buf, sizeof(buf));
634: if (n < 0) {
635: if (_res.options & RES_DEBUG) {
636: printf("Res_mkquery failed\n");
637: }
638: return (ERROR);
639: }
640: return(GetAnswer(nsAddrPtr, T_A, (char *) &buf, n, 1, hostPtr, 1));
641: }
642:
643: /*
644: *******************************************************************************
645: *
646: * FreeHostInfoPtr --
647: *
648: * Deallocates all the calloc'd areas for a HostInfo
649: * variable.
650: *
651: *******************************************************************************
652: */
653:
654: void
655: FreeHostInfoPtr(hostPtr)
656: HostInfo *hostPtr;
657: {
658: int i, j;
659:
660: if (hostPtr->name != NULL) {
661: free(hostPtr->name);
662: hostPtr->name = NULL;
663: }
664:
665: if (hostPtr->aliases != NULL) {
666: i = 0;
667: while (hostPtr->aliases[i] != NULL) {
668: free(hostPtr->aliases[i]);
669: i++;
670: }
671: free((char *)hostPtr->aliases);
672: hostPtr->aliases = NULL;
673: }
674:
675: if (hostPtr->addrList != NULL) {
676: i = 0;
677: while (hostPtr->addrList[i] != NULL) {
678: free(hostPtr->addrList[i]);
679: i++;
680: }
681: free((char *)hostPtr->addrList);
682: hostPtr->addrList = NULL;
683: }
684:
685: if (hostPtr->servers != NULL) {
686: i = 0;
687: while (hostPtr->servers[i] != NULL) {
688:
689: if (hostPtr->servers[i]->name != NULL) {
690: free(hostPtr->servers[i]->name);
691: }
692:
693: if (hostPtr->servers[i]->domains != NULL) {
694: j = 0;
695: while (hostPtr->servers[i]->domains[j] != NULL) {
696: free(hostPtr->servers[i]->domains[j]);
697: j++;
698: }
699: free((char *)hostPtr->servers[i]->domains);
700: }
701:
702: if (hostPtr->servers[i]->addrList != NULL) {
703: j = 0;
704: while (hostPtr->servers[i]->addrList[j] != NULL) {
705: free(hostPtr->servers[i]->addrList[j]);
706: j++;
707: }
708: free((char *)hostPtr->servers[i]->addrList);
709: }
710: free((char *)hostPtr->servers[i]);
711: i++;
712: }
713: free((char *)hostPtr->servers);
714: hostPtr->servers = NULL;
715: }
716: }
717:
718: /*
719: *******************************************************************************
720: *
721: * GetHostList --
722: *
723: * Performs a completion query when given an incomplete
724: * name.
725: *
726: * Still under development.
727: *
728: *******************************************************************************
729: */
730:
731: #if notdef
732:
733: int
734: GetHostList(nsAddrPtr, queryType, name, defaultName, hostPtr)
735: struct in_addr *nsAddrPtr;
736: int queryType;
737: char *name, *defaultName;
738: HostInfo *hostPtr;
739: {
740: int n;
741: querybuf buf;
742:
743: n = res_mkquery(CQUERYM, name, C_IN, T_A, defaultName, 0, (char *)0,
744: (char *) &buf, sizeof(buf));
745: if (n < 0) {
746: if (_res.options & RES_DEBUG)
747: printf("Res_mkquery failed\n");
748: return (ERROR);
749: }
750: return(GetAnswer(nsAddrPtr, queryType, (char *)&buf, n, 0, hostPtr, 1));
751: }
752: #endif notdef
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.