xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 26066)
1 /*
2  * Copyright (c) 1985 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	6.4 (Berkeley) 02/04/86";
9 #endif not lint
10 
11 #include <sys/param.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 #define MAXADDRS	35
21 
22 static char *h_addr_ptrs[MAXADDRS + 1];
23 
24 static struct hostent host;
25 static char *host_aliases[MAXALIASES];
26 static char hostbuf[BUFSIZ+1];
27 static struct in_addr host_addr;
28 
29 typedef union {
30     HEADER qb1;
31     char qb2[PACKETSZ];
32 } querybuf;
33 
34 static union {
35     long al;
36     char ac;
37 } align;
38 
39 
40 int h_errno;
41 
42 static struct hostent *
43 getanswer(msg, msglen, iquery)
44 	char *msg;
45 	int msglen, iquery;
46 {
47 	register HEADER *hp;
48 	register char *cp;
49 	register int n;
50 	querybuf answer;
51 	char *eom, *bp, **ap;
52 	int type, class, ancount, qdcount, buflen;
53 	int haveanswer, getclass;
54 	char **hap;
55 
56 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
57 	if (n < 0) {
58 #ifdef DEBUG
59 		if (_res.options & RES_DEBUG)
60 			printf("res_send failed\n");
61 #endif
62 		h_errno = TRY_AGAIN;
63 		return (NULL);
64 	}
65 	eom = (char *)&answer + n;
66 	/*
67 	 * find first satisfactory answer
68 	 */
69 	hp = (HEADER *) &answer;
70 	ancount = ntohs(hp->ancount);
71 	qdcount = ntohs(hp->qdcount);
72 	if (hp->rcode != NOERROR || ancount == 0) {
73 #ifdef DEBUG
74 		if (_res.options & RES_DEBUG)
75 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
76 #endif
77 		switch (hp->rcode) {
78 			case NXDOMAIN:
79 				/* Check if it's an authoritive answer */
80 				if (hp->aa)
81 					h_errno = HOST_NOT_FOUND;
82 				else
83 					h_errno = TRY_AGAIN;
84 				break;
85 			case SERVFAIL:
86 				h_errno = TRY_AGAIN;
87 				break;
88 			case NOERROR:
89 				h_errno = NO_ADDRESS;
90 				break;
91 			case FORMERR:
92 			case NOTIMP:
93 			case REFUSED:
94 				h_errno = NO_RECOVERY;
95 		}
96 		return (NULL);
97 	}
98 	bp = hostbuf;
99 	buflen = sizeof(hostbuf);
100 	cp = (char *)&answer + sizeof(HEADER);
101 	if (qdcount) {
102 		if (iquery) {
103 			if ((n = dn_expand((char *)&answer, eom,
104 			     cp, bp, buflen)) < 0) {
105 				h_errno = NO_RECOVERY;
106 				return (NULL);
107 			}
108 			cp += n + QFIXEDSZ;
109 			host.h_name = bp;
110 			n = strlen(bp) + 1;
111 			bp += n;
112 			buflen -= n;
113 		} else
114 			cp += dn_skip(cp) + QFIXEDSZ;
115 		while (--qdcount > 0)
116 			cp += dn_skip(cp) + QFIXEDSZ;
117 	} else if (iquery) {
118 		if (hp->aa)
119 			h_errno = HOST_NOT_FOUND;
120 		else
121 			h_errno = TRY_AGAIN;
122 		return (NULL);
123 	}
124 	ap = host_aliases;
125 	host.h_aliases = host_aliases;
126 	hap = h_addr_ptrs;
127 	host.h_addr_list = h_addr_ptrs;
128 	haveanswer = 0;
129 	while (--ancount >= 0 && cp < eom) {
130 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
131 			break;
132 		cp += n;
133 		type = getshort(cp);
134  		cp += sizeof(u_short);
135 		class = getshort(cp);
136  		cp += sizeof(u_short) + sizeof(u_long);
137 		n = getshort(cp);
138 		cp += sizeof(u_short);
139 		if (type == T_CNAME) {
140 			cp += n;
141 			if (ap >= &host_aliases[MAXALIASES-1])
142 				continue;
143 			*ap++ = bp;
144 			n = strlen(bp) + 1;
145 			bp += n;
146 			buflen -= n;
147 			continue;
148 		}
149 		if (type == T_PTR) {
150 			if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) <
151 0) {
152 				cp += n;
153 				continue;
154 			}
155 			cp += n;
156 			host.h_name = bp;
157 			return(&host);
158 		}
159 		if (type != T_A)  {
160 #ifdef DEBUG
161 			if (_res.options & RES_DEBUG)
162 				printf("unexpected answer type %d, size %d\n",
163 					type, n);
164 #endif
165 			cp += n;
166 			continue;
167 		}
168 		if (haveanswer) {
169 			if (n != host.h_length) {
170 				cp += n;
171 				continue;
172 			}
173 			if (class != getclass) {
174 				cp += n;
175 				continue;
176 			}
177 		} else {
178 			host.h_length = n;
179 			getclass = class;
180 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
181 			if (!iquery) {
182 				host.h_name = bp;
183 				bp += strlen(bp) + 1;
184 			}
185 		}
186 
187 		bp += ((u_long)bp % sizeof(align));
188 
189 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
190 #ifdef DEBUG
191 			if (_res.options & RES_DEBUG)
192 				printf("size (%d) too big\n", n);
193 #endif
194 			break;
195 		}
196 		bcopy(cp, *hap++ = bp, n);
197 		bp +=n;
198 		cp += n;
199 		haveanswer++;
200 	}
201 	if (haveanswer) {
202 		*ap = NULL;
203 		*hap = NULL;
204 		return (&host);
205 	} else {
206 		h_errno = TRY_AGAIN;
207 		return (NULL);
208 	}
209 }
210 
211 struct hostent *
212 gethostbyname(name)
213 	char *name;
214 {
215 	int n;
216 	querybuf buf;
217 
218 	n = res_mkquery(QUERY, name, C_ANY, T_A, (char *)NULL, 0, NULL,
219 		(char *)&buf, sizeof(buf));
220 	if (n < 0) {
221 #ifdef DEBUG
222 		if (_res.options & RES_DEBUG)
223 			printf("res_mkquery failed\n");
224 #endif
225 		return (NULL);
226 	}
227 	return(getanswer((char *)&buf, n, 0));
228 }
229 
230 struct hostent *
231 gethostbyaddr(addr, len, type)
232 	char *addr;
233 	int len, type;
234 {
235 	int n;
236 	querybuf buf;
237 	register struct hostent *hp;
238 	char qbuf[MAXDNAME];
239 
240 	if (type != AF_INET)
241 		return (NULL);
242 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
243 		((unsigned)addr[3] & 0xff),
244 		((unsigned)addr[2] & 0xff),
245 		((unsigned)addr[1] & 0xff),
246 		((unsigned)addr[0] & 0xff));
247 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
248 		(char *)&buf, sizeof(buf));
249 	if (n < 0) {
250 #ifdef DEBUG
251 		if (_res.options & RES_DEBUG)
252 			printf("res_mkquery failed\n");
253 #endif
254 		return (NULL);
255 	}
256 	if ((hp = getanswer((char *)&buf, n, 1)) == NULL)
257 		return(NULL);
258 	hp->h_addrtype = type;
259 	hp->h_length = len;
260 	h_addr_ptrs[0] = (char *)&host_addr;
261 	h_addr_ptrs[1] = (char *)0;
262 	host_addr = *(struct in_addr *)addr;
263 	return(hp);
264 }
265 
266