xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 33735)
1 /*
2  * Copyright (c) 1985, 1988 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 #if defined(LIBC_SCCS) && !defined(lint)
14 static char sccsid[] = "@(#)gethostnamadr.c	6.31 (Berkeley) 03/14/88";
15 #endif /* LIBC_SCCS and not lint */
16 
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <ctype.h>
21 #include <netdb.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <arpa/inet.h>
25 #include <arpa/nameser.h>
26 #include <resolv.h>
27 
28 #define	MAXALIASES	35
29 #define	MAXADDRS	35
30 
31 static char *h_addr_ptrs[MAXADDRS + 1];
32 
33 static struct hostent host;
34 static char *host_aliases[MAXALIASES];
35 static char hostbuf[BUFSIZ+1];
36 static struct in_addr host_addr;
37 static char HOSTDB[] = "/etc/hosts";
38 static FILE *hostf = NULL;
39 static char hostaddr[MAXADDRS];
40 static char *host_addrs[2];
41 static int stayopen = 0;
42 static char *any();
43 
44 #if PACKETSZ > 1024
45 #define	MAXPACKET	PACKETSZ
46 #else
47 #define	MAXPACKET	1024
48 #endif
49 
50 typedef union {
51     HEADER hdr;
52     u_char buf[MAXPACKET];
53 } querybuf;
54 
55 static union {
56     long al;
57     char ac;
58 } align;
59 
60 
61 int h_errno;
62 extern errno;
63 
64 static struct hostent *
65 getanswer(answer, anslen, iquery)
66 	querybuf *answer;
67 	int anslen;
68 	int iquery;
69 {
70 	register HEADER *hp;
71 	register u_char *cp;
72 	register int n;
73 	u_char *eom;
74 	char *bp, **ap;
75 	int type, class, buflen, ancount, qdcount;
76 	int haveanswer, getclass = C_ANY;
77 	char **hap;
78 
79 	eom = answer->buf + anslen;
80 	/*
81 	 * find first satisfactory answer
82 	 */
83 	hp = &answer->hdr;
84 	ancount = ntohs(hp->ancount);
85 	qdcount = ntohs(hp->qdcount);
86 	bp = hostbuf;
87 	buflen = sizeof(hostbuf);
88 	cp = answer->buf + sizeof(HEADER);
89 	if (qdcount) {
90 		if (iquery) {
91 			if ((n = dn_expand((char *)answer->buf, eom,
92 			     cp, bp, buflen)) < 0) {
93 				h_errno = NO_RECOVERY;
94 				return ((struct hostent *) NULL);
95 			}
96 			cp += n + QFIXEDSZ;
97 			host.h_name = bp;
98 			n = strlen(bp) + 1;
99 			bp += n;
100 			buflen -= n;
101 		} else
102 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
103 		while (--qdcount > 0)
104 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
105 	} else if (iquery) {
106 		if (hp->aa)
107 			h_errno = HOST_NOT_FOUND;
108 		else
109 			h_errno = TRY_AGAIN;
110 		return ((struct hostent *) NULL);
111 	}
112 	ap = host_aliases;
113 	host.h_aliases = host_aliases;
114 	hap = h_addr_ptrs;
115 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
116 	host.h_addr_list = h_addr_ptrs;
117 #endif
118 	haveanswer = 0;
119 	while (--ancount >= 0 && cp < eom) {
120 		if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0)
121 			break;
122 		cp += n;
123 		type = _getshort(cp);
124  		cp += sizeof(u_short);
125 		class = _getshort(cp);
126  		cp += sizeof(u_short) + sizeof(u_long);
127 		n = _getshort(cp);
128 		cp += sizeof(u_short);
129 		if (type == T_CNAME) {
130 			cp += n;
131 			if (ap >= &host_aliases[MAXALIASES-1])
132 				continue;
133 			*ap++ = bp;
134 			n = strlen(bp) + 1;
135 			bp += n;
136 			buflen -= n;
137 			continue;
138 		}
139 		if (iquery && type == T_PTR) {
140 			if ((n = dn_expand((char *)answer->buf, eom,
141 			    cp, bp, buflen)) < 0) {
142 				cp += n;
143 				continue;
144 			}
145 			cp += n;
146 			host.h_name = bp;
147 			return(&host);
148 		}
149 		if (iquery || type != T_A)  {
150 #ifdef DEBUG
151 			if (_res.options & RES_DEBUG)
152 				printf("unexpected answer type %d, size %d\n",
153 					type, n);
154 #endif
155 			cp += n;
156 			continue;
157 		}
158 		if (haveanswer) {
159 			if (n != host.h_length) {
160 				cp += n;
161 				continue;
162 			}
163 			if (class != getclass) {
164 				cp += n;
165 				continue;
166 			}
167 		} else {
168 			host.h_length = n;
169 			getclass = class;
170 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
171 			if (!iquery) {
172 				host.h_name = bp;
173 				bp += strlen(bp) + 1;
174 			}
175 		}
176 
177 		bp += sizeof(align) - ((u_long)bp % sizeof(align));
178 
179 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
180 #ifdef DEBUG
181 			if (_res.options & RES_DEBUG)
182 				printf("size (%d) too big\n", n);
183 #endif
184 			break;
185 		}
186 		bcopy(cp, *hap++ = bp, n);
187 		bp +=n;
188 		cp += n;
189 		haveanswer++;
190 	}
191 	if (haveanswer) {
192 		*ap = NULL;
193 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
194 		*hap = NULL;
195 #else
196 		host.h_addr = h_addr_ptrs[0];
197 #endif
198 		return (&host);
199 	} else {
200 		h_errno = TRY_AGAIN;
201 		return ((struct hostent *) NULL);
202 	}
203 }
204 
205 struct hostent *
206 gethostbyname(name)
207 	char *name;
208 {
209 	querybuf buf;
210 	register char *cp;
211 	int n;
212 	struct hostent *hp, *gethostdomain();
213 	extern struct hostent *_gethtbyname();
214 
215 	/*
216 	 * disallow names consisting only of digits/dots, unless
217 	 * they end in a dot.
218 	 */
219 	if (isdigit(name[0]))
220 		for (cp = name;; ++cp) {
221 			if (!*cp) {
222 				if (*--cp == '.')
223 					break;
224 				h_errno = HOST_NOT_FOUND;
225 				return ((struct hostent *) NULL);
226 			}
227 			if (!isdigit(*cp) && *cp != '.')
228 				break;
229 		}
230 
231 	if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
232 #ifdef DEBUG
233 		if (_res.options & RES_DEBUG)
234 			printf("res_search failed\n");
235 #endif
236 		if (errno == ECONNREFUSED)
237 			return (_gethtbyname(name));
238 		else
239 			return ((struct hostent *) NULL);
240 	}
241 	return (getanswer(&buf, n, 0));
242 }
243 
244 struct hostent *
245 gethostbyaddr(addr, len, type)
246 	char *addr;
247 	int len, type;
248 {
249 	int n;
250 	querybuf buf;
251 	register struct hostent *hp;
252 	char qbuf[MAXDNAME];
253 	extern struct hostent *_gethtbyaddr();
254 
255 	if (type != AF_INET)
256 		return ((struct hostent *) NULL);
257 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
258 		((unsigned)addr[3] & 0xff),
259 		((unsigned)addr[2] & 0xff),
260 		((unsigned)addr[1] & 0xff),
261 		((unsigned)addr[0] & 0xff));
262 	n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf));
263 	if (n < 0) {
264 #ifdef DEBUG
265 		if (_res.options & RES_DEBUG)
266 			printf("res_query failed\n");
267 #endif
268 		if (errno == ECONNREFUSED)
269 			hp = _gethtbyaddr(addr, len, type);
270 		return ((struct hostent *) NULL);
271 	}
272 	hp = getanswer(&buf, n, 1);
273 	if (hp == NULL)
274 		return ((struct hostent *) NULL);
275 	hp->h_addrtype = type;
276 	hp->h_length = len;
277 	h_addr_ptrs[0] = (char *)&host_addr;
278 	h_addr_ptrs[1] = (char *)0;
279 	host_addr = *(struct in_addr *)addr;
280 	return(hp);
281 }
282 
283 _sethtent(f)
284 	int f;
285 {
286 	if (hostf == NULL)
287 		hostf = fopen(HOSTDB, "r" );
288 	else
289 		rewind(hostf);
290 	stayopen |= f;
291 }
292 
293 _endhtent()
294 {
295 	if (hostf && !stayopen) {
296 		(void) fclose(hostf);
297 		hostf = NULL;
298 	}
299 }
300 
301 struct hostent *
302 _gethtent()
303 {
304 	char *p;
305 	register char *cp, **q;
306 
307 	if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
308 		return (NULL);
309 again:
310 	if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
311 		return (NULL);
312 	if (*p == '#')
313 		goto again;
314 	cp = any(p, "#\n");
315 	if (cp == NULL)
316 		goto again;
317 	*cp = '\0';
318 	cp = any(p, " \t");
319 	if (cp == NULL)
320 		goto again;
321 	*cp++ = '\0';
322 	/* THIS STUFF IS INTERNET SPECIFIC */
323 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
324 	host.h_addr_list = host_addrs;
325 #endif
326 	host.h_addr = hostaddr;
327 	*((u_long *)host.h_addr) = inet_addr(p);
328 	host.h_length = sizeof (u_long);
329 	host.h_addrtype = AF_INET;
330 	while (*cp == ' ' || *cp == '\t')
331 		cp++;
332 	host.h_name = cp;
333 	q = host.h_aliases = host_aliases;
334 	cp = any(cp, " \t");
335 	if (cp != NULL)
336 		*cp++ = '\0';
337 	while (cp && *cp) {
338 		if (*cp == ' ' || *cp == '\t') {
339 			cp++;
340 			continue;
341 		}
342 		if (q < &host_aliases[MAXALIASES - 1])
343 			*q++ = cp;
344 		cp = any(cp, " \t");
345 		if (cp != NULL)
346 			*cp++ = '\0';
347 	}
348 	*q = NULL;
349 	return (&host);
350 }
351 
352 static char *
353 any(cp, match)
354 	register char *cp;
355 	char *match;
356 {
357 	register char *mp, c;
358 
359 	while (c = *cp) {
360 		for (mp = match; *mp; mp++)
361 			if (*mp == c)
362 				return (cp);
363 		cp++;
364 	}
365 	return ((char *)0);
366 }
367 
368 struct hostent *
369 _gethtbyname(name)
370 	char *name;
371 {
372 	register struct hostent *p;
373 	register char **cp;
374 
375 	_sethtent(0);
376 	while (p = _gethtent()) {
377 		if (strcasecmp(p->h_name, name) == 0)
378 			break;
379 		for (cp = p->h_aliases; *cp != 0; cp++)
380 			if (strcasecmp(*cp, name) == 0)
381 				goto found;
382 	}
383 found:
384 	_endhtent();
385 	return (p);
386 }
387 
388 struct hostent *
389 _gethtbyaddr(addr, len, type)
390 	char *addr;
391 	int len, type;
392 {
393 	register struct hostent *p;
394 
395 	_sethtent(0);
396 	while (p = _gethtent())
397 		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
398 			break;
399 	_endhtent();
400 	return (p);
401 }
402