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