xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 33734)
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.30 (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 line[BUFSIZ+1];
40 static char hostaddr[MAXADDRS];
41 static char *host_addrs[2];
42 static int stayopen = 0;
43 static char *any();
44 
45 #if PACKETSZ > 1024
46 #define MAXPACKET	PACKETSZ
47 #else
48 #define MAXPACKET	1024
49 #endif
50 
51 typedef union {
52     HEADER qb1;
53     char qb2[MAXPACKET];
54 } querybuf;
55 
56 static union {
57     long al;
58     char ac;
59 } align;
60 
61 
62 int h_errno;
63 extern errno;
64 
65 static struct hostent *
66 getanswer(msg, msglen, iquery)
67 	char *msg;
68 	int msglen, iquery;
69 {
70 	register HEADER *hp;
71 	register char *cp;
72 	register int n;
73 	querybuf answer;
74 	char *eom, *bp, **ap;
75 	int type, class, buflen, ancount, qdcount;
76 	int haveanswer, getclass = C_ANY;
77 	char **hap;
78 
79 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
80 	if (n < 0) {
81 #ifdef DEBUG
82 		int terrno;
83 		terrno = errno;
84 		if (_res.options & RES_DEBUG)
85 			printf("res_send failed\n");
86 		errno = terrno;
87 #endif
88 		h_errno = TRY_AGAIN;
89 		return ((struct hostent *) NULL);
90 	}
91 	eom = (char *)&answer + n;
92 	/*
93 	 * find first satisfactory answer
94 	 */
95 	hp = (HEADER *) &answer;
96 	ancount = ntohs(hp->ancount);
97 	qdcount = ntohs(hp->qdcount);
98 	if (hp->rcode != NOERROR || ancount == 0) {
99 #ifdef DEBUG
100 		if (_res.options & RES_DEBUG)
101 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
102 #endif
103 		switch (hp->rcode) {
104 			case NXDOMAIN:
105 				/* Check if it's an authoritive answer */
106 				if (hp->aa)
107 					h_errno = HOST_NOT_FOUND;
108 				else
109 					h_errno = TRY_AGAIN;
110 				break;
111 			case SERVFAIL:
112 				h_errno = TRY_AGAIN;
113 				break;
114 			case NOERROR:
115 				if (hp->aa)
116 					h_errno = NO_ADDRESS;
117 				else
118 					h_errno = TRY_AGAIN;
119 				break;
120 			case FORMERR:
121 			case NOTIMP:
122 			case REFUSED:
123 				h_errno = NO_RECOVERY;
124 		}
125 		return ((struct hostent *) NULL);
126 	}
127 	bp = hostbuf;
128 	buflen = sizeof(hostbuf);
129 	cp = (char *)&answer + sizeof(HEADER);
130 	if (qdcount) {
131 		if (iquery) {
132 			if ((n = dn_expand((char *)&answer, eom,
133 			     cp, bp, buflen)) < 0) {
134 				h_errno = NO_RECOVERY;
135 				return ((struct hostent *) NULL);
136 			}
137 			cp += n + QFIXEDSZ;
138 			host.h_name = bp;
139 			n = strlen(bp) + 1;
140 			bp += n;
141 			buflen -= n;
142 		} else
143 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
144 		while (--qdcount > 0)
145 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
146 	} else if (iquery) {
147 		if (hp->aa)
148 			h_errno = HOST_NOT_FOUND;
149 		else
150 			h_errno = TRY_AGAIN;
151 		return ((struct hostent *) NULL);
152 	}
153 	ap = host_aliases;
154 	host.h_aliases = host_aliases;
155 	hap = h_addr_ptrs;
156 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
157 	host.h_addr_list = h_addr_ptrs;
158 #endif
159 	haveanswer = 0;
160 	while (--ancount >= 0 && cp < eom) {
161 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
162 			break;
163 		cp += n;
164 		type = _getshort(cp);
165  		cp += sizeof(u_short);
166 		class = _getshort(cp);
167  		cp += sizeof(u_short) + sizeof(u_long);
168 		n = _getshort(cp);
169 		cp += sizeof(u_short);
170 		if (type == T_CNAME) {
171 			cp += n;
172 			if (ap >= &host_aliases[MAXALIASES-1])
173 				continue;
174 			*ap++ = bp;
175 			n = strlen(bp) + 1;
176 			bp += n;
177 			buflen -= n;
178 			continue;
179 		}
180 		if (type == T_PTR) {
181 			if ((n = dn_expand((char *)&answer, eom,
182 			    cp, bp, buflen)) < 0) {
183 				cp += n;
184 				continue;
185 			}
186 			cp += n;
187 			host.h_name = bp;
188 			return(&host);
189 		}
190 		if (type != T_A)  {
191 #ifdef DEBUG
192 			if (_res.options & RES_DEBUG)
193 				printf("unexpected answer type %d, size %d\n",
194 					type, n);
195 #endif
196 			cp += n;
197 			continue;
198 		}
199 		if (haveanswer) {
200 			if (n != host.h_length) {
201 				cp += n;
202 				continue;
203 			}
204 			if (class != getclass) {
205 				cp += n;
206 				continue;
207 			}
208 		} else {
209 			host.h_length = n;
210 			getclass = class;
211 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
212 			if (!iquery) {
213 				host.h_name = bp;
214 				bp += strlen(bp) + 1;
215 			}
216 		}
217 
218 		bp += sizeof(align) - ((u_long)bp % sizeof(align));
219 
220 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
221 #ifdef DEBUG
222 			if (_res.options & RES_DEBUG)
223 				printf("size (%d) too big\n", n);
224 #endif
225 			break;
226 		}
227 		bcopy(cp, *hap++ = bp, n);
228 		bp +=n;
229 		cp += n;
230 		haveanswer++;
231 	}
232 	if (haveanswer) {
233 		*ap = NULL;
234 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
235 		*hap = NULL;
236 #else
237 		host.h_addr = h_addr_ptrs[0];
238 #endif
239 		return (&host);
240 	} else {
241 		h_errno = TRY_AGAIN;
242 		return ((struct hostent *) NULL);
243 	}
244 }
245 
246 struct hostent *
247 gethostbyname(name)
248 	char *name;
249 {
250 	register char *cp, **domain;
251 	int n;
252 	struct hostent *hp, *gethostdomain();
253 	char *hostalias();
254 	extern struct hostent *_gethtbyname();
255 
256 	if (!(_res.options & RES_INIT) && res_init() == -1)
257 		return ((struct hostent *) NULL);
258 	/*
259 	 * disallow names consisting only of digits/dots, unless
260 	 * they end in a dot.
261 	 */
262 	if (isdigit(name[0]))
263 		for (cp = name;; ++cp) {
264 			if (!*cp) {
265 				if (*--cp == '.')
266 					break;
267 				h_errno = HOST_NOT_FOUND;
268 				return ((struct hostent *) NULL);
269 			}
270 			if (!isdigit(*cp) && *cp != '.')
271 				break;
272 		}
273 	errno = 0;
274 	for (cp = name, n = 0; *cp; cp++)
275 		if (*cp == '.')
276 			n++;
277 	if (n == 0 && (cp = hostalias(name)))
278 		return (gethostdomain(cp, (char *)NULL));
279 	if ((n == 0 || *--cp != '.') && (_res.options & RES_DEFNAMES))
280 	    for (domain = _res.dnsrch; *domain; domain++) {
281 		hp = gethostdomain(name, *domain);
282 		if (hp)
283 			return (hp);
284 		/*
285 		 * If no server present, use host table.
286 		 * If host isn't found in this domain,
287 		 * keep trying higher domains in the search list
288 		 * (if that's enabled).
289 		 * On a NO_ADDRESS error, keep trying, otherwise
290 		 * a wildcard MX entry could keep us from finding
291 		 * host entries higher in the domain.
292 		 * If we get some other error (non-authoritative negative
293 		 * answer or server failure), then stop searching up,
294 		 * but try the input name below in case it's fully-qualified.
295 		 */
296 		if (errno == ECONNREFUSED)
297 			return (_gethtbyname(name));
298 		if ((h_errno != HOST_NOT_FOUND && h_errno != NO_ADDRESS) ||
299 		    (_res.options & RES_DNSRCH) == 0)
300 			break;
301 		h_errno = 0;
302 	}
303 	/*
304 	 * If the search/default failed, try the name as fully-qualified,
305 	 * but only if it contained at least one dot (even trailing).
306 	 */
307 	if (n)
308 		return (gethostdomain(name, (char *)NULL));
309 	return ((struct hostent *) NULL);
310 }
311 
312 static struct hostent *
313 gethostdomain(name, domain)
314 	char *name, *domain;
315 {
316 	querybuf buf;
317 	char nbuf[2*MAXDNAME+2];
318 	char *longname = nbuf;
319 	int n;
320 
321 	if (domain == NULL) {
322 		/*
323 		 * Check for trailing '.';
324 		 * copy without '.' if present.
325 		 */
326 		n = strlen(name) - 1;
327 		if (name[n] == '.' && n < sizeof(nbuf) - 1) {
328 			bcopy(name, nbuf, n);
329 			nbuf[n] = '\0';
330 		} else
331 			longname = name;
332 	} else
333 		(void)sprintf(nbuf, "%.*s.%.*s",
334 		    MAXDNAME, name, MAXDNAME, domain);
335 	n = res_mkquery(QUERY, longname, C_IN, T_A, (char *)NULL, 0, NULL,
336 		(char *)&buf, sizeof(buf));
337 	if (n < 0) {
338 #ifdef DEBUG
339 		if (_res.options & RES_DEBUG)
340 			printf("res_mkquery failed\n");
341 #endif
342 		return ((struct hostent *) NULL);
343 	}
344 	return (getanswer((char *)&buf, n, 0));
345 }
346 
347 struct hostent *
348 gethostbyaddr(addr, len, type)
349 	char *addr;
350 	int len, type;
351 {
352 	int n;
353 	querybuf buf;
354 	register struct hostent *hp;
355 	char qbuf[MAXDNAME];
356 	extern struct hostent *_gethtbyaddr();
357 
358 	if (type != AF_INET)
359 		return ((struct hostent *) NULL);
360 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
361 		((unsigned)addr[3] & 0xff),
362 		((unsigned)addr[2] & 0xff),
363 		((unsigned)addr[1] & 0xff),
364 		((unsigned)addr[0] & 0xff));
365 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, (char *)NULL, 0, NULL,
366 		(char *)&buf, sizeof(buf));
367 	if (n < 0) {
368 #ifdef DEBUG
369 		if (_res.options & RES_DEBUG)
370 			printf("res_mkquery failed\n");
371 #endif
372 		return ((struct hostent *) NULL);
373 	}
374 	hp = getanswer((char *)&buf, n, 1);
375 	if (hp == NULL && errno == ECONNREFUSED)
376 		hp = _gethtbyaddr(addr, len, type);
377 	if (hp == NULL)
378 		return ((struct hostent *) NULL);
379 	hp->h_addrtype = type;
380 	hp->h_length = len;
381 	h_addr_ptrs[0] = (char *)&host_addr;
382 	h_addr_ptrs[1] = (char *)0;
383 	host_addr = *(struct in_addr *)addr;
384 	return(hp);
385 }
386 
387 char *
388 hostalias(name)
389 	register char *name;
390 {
391 	register char *C1, *C2;
392 	FILE *fp;
393 	char *file, *getenv(), *strcpy(), *strncpy();
394 	char buf[BUFSIZ];
395 	static char abuf[MAXDNAME];
396 
397 	file = getenv("HOSTALIASES");
398 	if (file == NULL || (fp = fopen(file, "r")) == NULL)
399 		return (NULL);
400 	buf[sizeof(buf) - 1] = '\0';
401 	while (fgets(buf, sizeof(buf), fp)) {
402 		for (C1 = buf; *C1 && !isspace(*C1); ++C1);
403 		if (!*C1)
404 			break;
405 		*C1 = '\0';
406 		if (!strcasecmp(buf, name)) {
407 			while (isspace(*++C1));
408 			if (!*C1)
409 				break;
410 			for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
411 			abuf[sizeof(abuf) - 1] = *C2 = '\0';
412 			(void)strncpy(abuf, C1, sizeof(abuf) - 1);
413 			fclose(fp);
414 			return (abuf);
415 		}
416 	}
417 	fclose(fp);
418 	return (NULL);
419 }
420 
421 _sethtent(f)
422 	int f;
423 {
424 	if (hostf == NULL)
425 		hostf = fopen(HOSTDB, "r" );
426 	else
427 		rewind(hostf);
428 	stayopen |= f;
429 }
430 
431 _endhtent()
432 {
433 	if (hostf && !stayopen) {
434 		(void) fclose(hostf);
435 		hostf = NULL;
436 	}
437 }
438 
439 struct hostent *
440 _gethtent()
441 {
442 	char *p;
443 	register char *cp, **q;
444 
445 	if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
446 		return (NULL);
447 again:
448 	if ((p = fgets(line, BUFSIZ, hostf)) == NULL)
449 		return (NULL);
450 	if (*p == '#')
451 		goto again;
452 	cp = any(p, "#\n");
453 	if (cp == NULL)
454 		goto again;
455 	*cp = '\0';
456 	cp = any(p, " \t");
457 	if (cp == NULL)
458 		goto again;
459 	*cp++ = '\0';
460 	/* THIS STUFF IS INTERNET SPECIFIC */
461 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
462 	host.h_addr_list = host_addrs;
463 #endif
464 	host.h_addr = hostaddr;
465 	*((u_long *)host.h_addr) = inet_addr(p);
466 	host.h_length = sizeof (u_long);
467 	host.h_addrtype = AF_INET;
468 	while (*cp == ' ' || *cp == '\t')
469 		cp++;
470 	host.h_name = cp;
471 	q = host.h_aliases = host_aliases;
472 	cp = any(cp, " \t");
473 	if (cp != NULL)
474 		*cp++ = '\0';
475 	while (cp && *cp) {
476 		if (*cp == ' ' || *cp == '\t') {
477 			cp++;
478 			continue;
479 		}
480 		if (q < &host_aliases[MAXALIASES - 1])
481 			*q++ = cp;
482 		cp = any(cp, " \t");
483 		if (cp != NULL)
484 			*cp++ = '\0';
485 	}
486 	*q = NULL;
487 	return (&host);
488 }
489 
490 static char *
491 any(cp, match)
492 	register char *cp;
493 	char *match;
494 {
495 	register char *mp, c;
496 
497 	while (c = *cp) {
498 		for (mp = match; *mp; mp++)
499 			if (*mp == c)
500 				return (cp);
501 		cp++;
502 	}
503 	return ((char *)0);
504 }
505 
506 struct hostent *
507 _gethtbyname(name)
508 	char *name;
509 {
510 	register struct hostent *p;
511 	register char **cp;
512 
513 	_sethtent(0);
514 	while (p = _gethtent()) {
515 		if (strcasecmp(p->h_name, name) == 0)
516 			break;
517 		for (cp = p->h_aliases; *cp != 0; cp++)
518 			if (strcasecmp(*cp, name) == 0)
519 				goto found;
520 	}
521 found:
522 	_endhtent();
523 	return (p);
524 }
525 
526 struct hostent *
527 _gethtbyaddr(addr, len, type)
528 	char *addr;
529 	int len, type;
530 {
531 	register struct hostent *p;
532 
533 	_sethtent(0);
534 	while (p = _gethtent())
535 		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
536 			break;
537 	_endhtent();
538 	return (p);
539 }
540