xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 24508)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)gethostnamadr.c	5.2 (Berkeley) 09/03/85";
9 #endif not lint
10 
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <netdb.h>
15 #include <stdio.h>
16 #include <arpa/nameser.h>
17 #include <arpa/resolv.h>
18 
19 #define	MAXALIASES	35
20 
21 static struct hostent host;
22 static char *host_aliases[MAXALIASES];
23 static char hostbuf[BUFSIZ+1];
24 
25 static struct hostent *
26 getanswer(msg, msglen, iquery)
27 	char *msg;
28 	int msglen, iquery;
29 {
30 	register HEADER *hp;
31 	register char *cp;
32 	register int n;
33 	char answer[PACKETSZ];
34 	char *eom, *bp, **ap;
35 	int type, class, ancount, buflen;
36 
37 	n = res_send(msg, msglen, answer, sizeof(answer));
38 	if (n < 0) {
39 		if (_res.options & RES_DEBUG)
40 			printf("res_send failed\n");
41 		return (NULL);
42 	}
43 	eom = answer + n;
44 	/*
45 	 * find first satisfactory answer
46 	 */
47 	hp = (HEADER *) answer;
48 	ancount = ntohs(hp->ancount);
49 	if (hp->rcode != NOERROR || ancount == 0) {
50 		if (_res.options & RES_DEBUG)
51 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
52 		return (NULL);
53 	}
54 	bp = hostbuf;
55 	buflen = sizeof(hostbuf);
56 	ap = host_aliases;
57 	cp = answer + sizeof(HEADER);
58 	if (hp->qdcount) {
59 		if (iquery) {
60 			if ((n = dn_expand(answer, cp, bp, buflen)) < 0)
61 				return (NULL);
62 			cp += n + QFIXEDSZ;
63 			host.h_name = bp;
64 			n = strlen(bp) + 1;
65 			bp += n;
66 			buflen -= n;
67 		} else
68 			cp += dn_skip(cp) + QFIXEDSZ;
69 	} else if (iquery)
70 		return (NULL);
71 	while (--ancount >= 0 && cp < eom) {
72 		if ((n = dn_expand(answer, cp, bp, buflen)) < 0)
73 			return (NULL);
74 		cp += n;
75 		type = getshort(cp);
76  		cp += sizeof(u_short);
77 		class = getshort(cp);
78  		cp += sizeof(u_short) + sizeof(u_long);
79 		n = getshort(cp);
80 		cp += sizeof(u_short);
81 		if (type == T_CNAME) {
82 			cp += n;
83 			if (ap >= &host_aliases[MAXALIASES-1])
84 				continue;
85 			*ap++ = bp;
86 			n = strlen(bp) + 1;
87 			bp += n;
88 			buflen -= n;
89 			continue;
90 		}
91 		if (type != T_A || n != 4) {
92 			if (_res.options & RES_DEBUG)
93 				printf("unexpected answer type %d, size %d\n",
94 					type, n);
95 			continue;
96 		}
97 		if (!iquery) {
98 			host.h_name = bp;
99 			bp += strlen(bp) + 1;
100 		}
101 		*ap = NULL;
102 		host.h_aliases = host_aliases;
103 		host.h_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
104 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
105 			if (_res.options & RES_DEBUG)
106 				printf("size (%d) too big\n", n);
107 			return (NULL);
108 		}
109 		bcopy(cp, host.h_addr = bp, host.h_length = n);
110 		return (&host);
111 	}
112 	return (NULL);
113 }
114 
115 struct hostent *
116 gethostbyname(name)
117 	char *name;
118 {
119 	int n;
120 
121 	n = res_mkquery(QUERY, name, C_ANY, T_A, NULL, 0, NULL,
122 		hostbuf, sizeof(hostbuf));
123 	if (n < 0) {
124 		if (_res.options & RES_DEBUG)
125 			printf("res_mkquery failed\n");
126 		return (NULL);
127 	}
128 	return (getanswer(hostbuf, n, 0));
129 }
130 
131 struct hostent *
132 gethostbyaddr(addr, len, type)
133 	char *addr;
134 	int len, type;
135 {
136 	int n;
137 
138 	if (type != AF_INET)
139 		return (NULL);
140 	n = res_mkquery(IQUERY, NULL, C_IN, T_A, addr, len, NULL,
141 		hostbuf, sizeof(hostbuf));
142 	if (n < 0) {
143 		if (_res.options & RES_DEBUG)
144 			printf("res_mkquery failed\n");
145 		return (NULL);
146 	}
147 	return (getanswer(hostbuf, n, 1));
148 }
149