xref: /freebsd/lib/libc/net/gethostnamadr.c (revision 0c43d89a0d8e976ca494d4837f4c1f3734d2c300)
1 /*-
2  * Copyright (c) 1985, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  * -
33  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
34  *
35  * Permission to use, copy, modify, and distribute this software for any
36  * purpose with or without fee is hereby granted, provided that the above
37  * copyright notice and this permission notice appear in all copies, and that
38  * the name of Digital Equipment Corporation not be used in advertising or
39  * publicity pertaining to distribution of the document or software without
40  * specific, written prior permission.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
45  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49  * SOFTWARE.
50  * -
51  * --Copyright--
52  */
53 
54 #if defined(LIBC_SCCS) && !defined(lint)
55 static char sccsid[] = "From: @(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
56 /*static char rcsid[] = "From: Id: gethnamaddr.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel ";*/
57 static const char rcsid[] =
58   "$Id: gethostnamadr.c,v 1.2 1994/08/09 20:23:14 wollman Exp $";
59 #endif /* LIBC_SCCS and not lint */
60 
61 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 #include <arpa/nameser.h>
66 #include <netdb.h>
67 #include <resolv.h>
68 #include <stdio.h>
69 #include <ctype.h>
70 #include <errno.h>
71 #include <string.h>
72 
73 #define	MAXALIASES	35
74 #define	MAXADDRS	35
75 
76 #define _PATH_HOSTCONF	"/etc/host.conf"
77 
78 enum service_type {
79   SERVICE_NONE = 0,
80   SERVICE_BIND,
81   SERVICE_HOSTS,
82   SERVICE_NIS };
83 #define SERVICE_MAX	SERVICE_NIS
84 
85 static struct {
86   const char *name;
87   enum service_type type;
88 } service_names[] = {
89   { "hosts", SERVICE_HOSTS },
90   { "/etc/hosts", SERVICE_HOSTS },
91   { "hosttable", SERVICE_HOSTS },
92   { "htable", SERVICE_HOSTS },
93   { "bind", SERVICE_BIND },
94   { "dns", SERVICE_BIND },
95   { "domain", SERVICE_BIND },
96   { "yp", SERVICE_NIS },
97   { "yellowpages", SERVICE_NIS },
98   { "nis", SERVICE_NIS },
99   { 0, SERVICE_NONE }
100 };
101 
102 static enum service_type service_order[SERVICE_MAX + 1];
103 static int service_done = 0;
104 
105 static char *h_addr_ptrs[MAXADDRS + 1];
106 
107 static struct hostent host;
108 static char *host_aliases[MAXALIASES];
109 static char hostbuf[BUFSIZ+1];
110 static struct in_addr host_addr;
111 static FILE *hostf = NULL;
112 static char hostaddr[MAXADDRS];
113 static char *host_addrs[2];
114 static int stayopen = 0;
115 
116 #if PACKETSZ > 1024
117 #define	MAXPACKET	PACKETSZ
118 #else
119 #define	MAXPACKET	1024
120 #endif
121 
122 typedef union {
123     HEADER hdr;
124     u_char buf[MAXPACKET];
125 } querybuf;
126 
127 typedef union {
128     int32_t al;
129     char ac;
130 } align;
131 
132 extern int h_errno;
133 
134 static enum service_type
135 get_service_name(const char *name) {
136 	int i;
137 	for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
138 		if(!strcasecmp(name, service_names[i].name)) {
139 			return service_names[i].type;
140 		}
141 	}
142 	return SERVICE_NONE;
143 }
144 
145 static void
146 init_services()
147 {
148 	char *cp, buf[BUFSIZ];
149 	register int cc = 0;
150 	FILE *fd;
151 
152 	if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
153 				/* make some assumptions */
154 		service_order[0] = SERVICE_BIND;
155 		service_order[1] = SERVICE_HOSTS;
156 		service_order[2] = SERVICE_NONE;
157 	} else {
158 		while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
159 			if(buf[0] == '#')
160 				continue;
161 
162 			cp = strtok(buf, "\n \t,:;");
163 			do {
164 				if(!isalpha(cp[0])) continue;
165 				service_order[cc] = get_service_name(buf);
166 				if(service_order[cc] != SERVICE_NONE)
167 					cc++;
168 			} while((cp = strtok((char *)0, "\n \t,:;"))
169 				&& (cc < SERVICE_MAX));
170 		}
171 		service_order[cc] = SERVICE_NONE;
172 		fclose(fd);
173 	}
174 	service_done = 1;
175 }
176 
177 static struct hostent *
178 getanswer(answer, anslen, iquery)
179 	querybuf *answer;
180 	int anslen;
181 	int iquery;
182 {
183 	register HEADER *hp;
184 	register u_char *cp;
185 	register int n;
186 	u_char *eom;
187 	char *bp, **ap;
188 	int type, class, buflen, ancount, qdcount;
189 	int haveanswer, getclass = C_ANY;
190 	char **hap;
191 
192 	eom = answer->buf + anslen;
193 	/*
194 	 * find first satisfactory answer
195 	 */
196 	hp = &answer->hdr;
197 	ancount = ntohs(hp->ancount);
198 	qdcount = ntohs(hp->qdcount);
199 	bp = hostbuf;
200 	buflen = sizeof(hostbuf);
201 	cp = answer->buf + sizeof(HEADER);
202 	if (qdcount) {
203 		if (iquery) {
204 			if ((n = dn_expand((u_char *)answer->buf,
205 			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
206 			    buflen)) < 0) {
207 				h_errno = NO_RECOVERY;
208 				return ((struct hostent *) NULL);
209 			}
210 			cp += n + QFIXEDSZ;
211 			host.h_name = bp;
212 			n = strlen(bp) + 1;
213 			bp += n;
214 			buflen -= n;
215 		} else
216 			cp += __dn_skipname(cp, eom) + QFIXEDSZ;
217 		while (--qdcount > 0)
218 			cp += __dn_skipname(cp, eom) + QFIXEDSZ;
219 	} else if (iquery) {
220 		if (hp->aa)
221 			h_errno = HOST_NOT_FOUND;
222 		else
223 			h_errno = TRY_AGAIN;
224 		return ((struct hostent *) NULL);
225 	}
226 	ap = host_aliases;
227 	*ap = NULL;
228 	host.h_aliases = host_aliases;
229 	hap = h_addr_ptrs;
230 	*hap = NULL;
231 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
232 	host.h_addr_list = h_addr_ptrs;
233 #endif
234 	haveanswer = 0;
235 	while (--ancount >= 0 && cp < eom) {
236 		if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
237 		    (u_char *)cp, (u_char *)bp, buflen)) < 0)
238 			break;
239 		cp += n;
240 		type = _getshort(cp);
241  		cp += sizeof(u_int16_t);
242 		class = _getshort(cp);
243  		cp += sizeof(u_int16_t) + sizeof(u_int32_t);
244 		n = _getshort(cp);
245 		cp += sizeof(u_int16_t);
246 		if (type == T_CNAME) {
247 			cp += n;
248 			if (ap >= &host_aliases[MAXALIASES-1])
249 				continue;
250 			*ap++ = bp;
251 			n = strlen(bp) + 1;
252 			bp += n;
253 			buflen -= n;
254 			continue;
255 		}
256 		if (iquery && type == T_PTR) {
257 			if ((n = dn_expand((u_char *)answer->buf,
258 			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
259 			    buflen)) < 0)
260 				break;
261 			cp += n;
262 			host.h_name = bp;
263 			return(&host);
264 		}
265 		if (iquery || type != T_A)  {
266 #ifdef DEBUG
267 			if (_res.options & RES_DEBUG)
268 				printf("unexpected answer type %d, size %d\n",
269 					type, n);
270 #endif
271 			cp += n;
272 			continue;
273 		}
274 		if (haveanswer) {
275 			if (n != host.h_length) {
276 				cp += n;
277 				continue;
278 			}
279 			if (class != getclass) {
280 				cp += n;
281 				continue;
282 			}
283 		} else {
284 			host.h_length = n;
285 			getclass = class;
286 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
287 			if (!iquery) {
288 				host.h_name = bp;
289 				bp += strlen(bp) + 1;
290 			}
291 		}
292 
293 		bp += sizeof(align) - ((u_int32_t)bp % sizeof(align));
294 
295 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
296 #ifdef DEBUG
297 			if (_res.options & RES_DEBUG)
298 				printf("size (%d) too big\n", n);
299 #endif
300 			break;
301 		}
302 		bcopy(cp, *hap++ = bp, n);
303 		bp +=n;
304 		cp += n;
305 		haveanswer++;
306 	}
307 	if (haveanswer) {
308 		*ap = NULL;
309 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
310 		*hap = NULL;
311 #else
312 		host.h_addr = h_addr_ptrs[0];
313 #endif
314 		return (&host);
315 	} else {
316 		h_errno = TRY_AGAIN;
317 		return ((struct hostent *) NULL);
318 	}
319 }
320 
321 struct hostent *
322 _getdnsbyname(name)
323 	const char *name;
324 {
325 	querybuf buf;
326 	register const char *cp;
327 	int n;
328 	extern struct hostent *_gethtbyname();
329 
330 	/*
331 	 * disallow names consisting only of digits/dots, unless
332 	 * they end in a dot.
333 	 */
334 	if (isdigit(name[0]))
335 		for (cp = name;; ++cp) {
336 			if (!*cp) {
337 				if (*--cp == '.')
338 					break;
339 				/*
340 				 * All-numeric, no dot at the end.
341 				 * Fake up a hostent as if we'd actually
342 				 * done a lookup.
343 				 */
344 				if (!inet_aton(name, &host_addr)) {
345 					h_errno = HOST_NOT_FOUND;
346 					return((struct hostent *) NULL);
347 				}
348 				host.h_name = (char *)name;
349 				host.h_aliases = host_aliases;
350 				host_aliases[0] = NULL;
351 				host.h_addrtype = AF_INET;
352 				host.h_length = sizeof(u_int32_t);
353 				h_addr_ptrs[0] = (char *)&host_addr;
354 				h_addr_ptrs[1] = (char *)0;
355 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
356 				host.h_addr_list = h_addr_ptrs;
357 #else
358 				host.h_addr = h_addr_ptrs[0];
359 #endif
360 				return (&host);
361 			}
362 			if (!isdigit(*cp) && *cp != '.')
363 				break;
364 		}
365 
366 	if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
367 #ifdef DEBUG
368 		if (_res.options & RES_DEBUG)
369 			printf("res_search failed\n");
370 #endif
371 		return ((struct hostent *) NULL);
372 	}
373 	return (getanswer(&buf, n, 0));
374 }
375 
376 struct hostent *
377 _getdnsbyaddr(addr, len, type)
378 	const char *addr;
379 	int len, type;
380 {
381 	int n;
382 	querybuf buf;
383 	register struct hostent *hp;
384 	char qbuf[MAXDNAME];
385 	extern struct hostent *_gethtbyaddr();
386 
387 	if (type != AF_INET)
388 		return ((struct hostent *) NULL);
389 	(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
390 		((unsigned)addr[3] & 0xff),
391 		((unsigned)addr[2] & 0xff),
392 		((unsigned)addr[1] & 0xff),
393 		((unsigned)addr[0] & 0xff));
394 	n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf));
395 	if (n < 0) {
396 #ifdef DEBUG
397 		if (_res.options & RES_DEBUG)
398 			printf("res_query failed\n");
399 #endif
400 		return ((struct hostent *) NULL);
401 	}
402 	hp = getanswer(&buf, n, 1);
403 	if (hp == NULL)
404 		return ((struct hostent *) NULL);
405 	hp->h_addrtype = type;
406 	hp->h_length = len;
407 	h_addr_ptrs[0] = (char *)&host_addr;
408 	h_addr_ptrs[1] = (char *)0;
409 	host_addr = *(struct in_addr *)addr;
410 #if BSD < 43 && !defined(h_addr)	/* new-style hostent structure */
411 	hp->h_addr = h_addr_ptrs[0];
412 #endif
413 	return(hp);
414 }
415 
416 void
417 _sethtent(f)
418 	int f;
419 {
420 	if (hostf == NULL)
421 		hostf = fopen(_PATH_HOSTS, "r" );
422 	else
423 		rewind(hostf);
424 	stayopen |= f;
425 }
426 
427 void
428 _endhtent()
429 {
430 	if (hostf && !stayopen) {
431 		(void) fclose(hostf);
432 		hostf = NULL;
433 	}
434 }
435 
436 struct hostent *
437 _gethtent()
438 {
439 	char *p;
440 	register char *cp, **q;
441 
442 	if (hostf == NULL && (hostf = fopen(_PATH_HOSTS, "r" )) == NULL)
443 		return (NULL);
444 again:
445 	if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
446 		return (NULL);
447 	if (*p == '#')
448 		goto again;
449 	cp = strpbrk(p, "#\n");
450 	if (cp == NULL)
451 		goto again;
452 	*cp = '\0';
453 	cp = strpbrk(p, " \t");
454 	if (cp == NULL)
455 		goto again;
456 	*cp++ = '\0';
457 	/* THIS STUFF IS INTERNET SPECIFIC */
458 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
459 	host.h_addr_list = host_addrs;
460 #endif
461 	host.h_addr = hostaddr;
462 	*((u_int32_t *)host.h_addr) = inet_addr(p);
463 	host.h_length = sizeof (u_int32_t);
464 	host.h_addrtype = AF_INET;
465 	while (*cp == ' ' || *cp == '\t')
466 		cp++;
467 	host.h_name = cp;
468 	q = host.h_aliases = host_aliases;
469 	cp = strpbrk(cp, " \t");
470 	if (cp != NULL)
471 		*cp++ = '\0';
472 	while (cp && *cp) {
473 		if (*cp == ' ' || *cp == '\t') {
474 			cp++;
475 			continue;
476 		}
477 		if (q < &host_aliases[MAXALIASES - 1])
478 			*q++ = cp;
479 		cp = strpbrk(cp, " \t");
480 		if (cp != NULL)
481 			*cp++ = '\0';
482 	}
483 	*q = NULL;
484 	return (&host);
485 }
486 
487 struct hostent *
488 _gethtbyname(name)
489 	char *name;
490 {
491 	register struct hostent *p;
492 	register char **cp;
493 
494 	_sethtent(0);
495 	while (p = _gethtent()) {
496 		if (strcasecmp(p->h_name, name) == 0)
497 			break;
498 		for (cp = p->h_aliases; *cp != 0; cp++)
499 			if (strcasecmp(*cp, name) == 0)
500 				goto found;
501 	}
502 found:
503 	_endhtent();
504 	return (p);
505 }
506 
507 struct hostent *
508 _gethtbyaddr(addr, len, type)
509 	const char *addr;
510 	int len, type;
511 {
512 	register struct hostent *p;
513 
514 	_sethtent(0);
515 	while (p = _gethtent())
516 		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
517 			break;
518 	_endhtent();
519 	return (p);
520 }
521 
522 
523 #ifdef YP
524 struct hostent *
525 _getnishost(name, map)
526 	char *name, *map;
527 {
528 	register char *cp, *dp, **q;
529 	char *result;
530 	int resultlen;
531 	static struct hostent h;
532 	static char *domain = (char *)NULL;
533 
534 	if (domain == (char *)NULL)
535 		if (yp_get_default_domain (&domain))
536 			return ((struct hostent *)NULL);
537 
538 	if (yp_match(domain, map, name, strlen(name), &result, &resultlen))
539 		return ((struct hostent *)NULL);
540 
541 	if (cp = index(result, '\n'))
542 		*cp = '\0';
543 
544 	cp = strpbrk(result, " \t");
545 	*cp++ = '\0';
546 #if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
547 	h.h_addr_list = host_addrs;
548 #endif
549 	h.h_addr = hostaddr;
550 	*((u_long *)h.h_addr) = inet_addr(result);
551 	h.h_length = sizeof(u_long);
552 	h.h_addrtype = AF_INET;
553 	while (*cp == ' ' || *cp == '\t')
554 		cp++;
555 	h.h_name = cp;
556 	q = h.h_aliases = host_aliases;
557 	cp = strpbrk(cp, " \t");
558 	if (cp != NULL)
559 		*cp++ = '\0';
560 	while (cp && *cp) {
561 		if (*cp == ' ' || *cp == '\t') {
562 			cp++;
563 			continue;
564 		}
565 		if (q < &host_aliases[MAXALIASES - 1])
566 			*q++ = cp;
567 		cp = strpbrk(cp, " \t");
568 		if (cp != NULL)
569 			*cp++ = '\0';
570 	}
571 	*q = NULL;
572 	return (&h);
573 }
574 #endif /* YP */
575 
576 struct hostent *
577 gethostbyname(const char *name)
578 {
579 	struct hostent *hp = 0;
580 	int nserv = 0;
581 
582 	if(!service_done) {
583 		init_services();
584 	}
585 
586 	while(!hp) {
587 		switch(service_order[nserv]) {
588 		      case SERVICE_NONE:
589 			return 0;
590 		      case SERVICE_HOSTS:
591 			hp = _gethtbyname(name);
592 			break;
593 		      case SERVICE_BIND:
594 			hp = _getdnsbyname(name);
595 			break;
596 		      case SERVICE_NIS:
597 #ifdef YP
598 			hp = _getnishost(name, "hosts.byname");
599 #endif
600 			break;
601 		}
602 		nserv++;
603 	}
604 	return hp;
605 }
606 
607 struct hostent *
608 gethostbyaddr(const char *addr, int len, int type)
609 {
610 	struct hostent *hp = 0;
611 	int nserv = 0;
612 
613 	if(!service_done) {
614 		init_services();
615 	}
616 
617 	while(!hp) {
618 		switch(service_order[nserv]) {
619 		      case SERVICE_NONE:
620 			return 0;
621 		      case SERVICE_HOSTS:
622 			hp = _gethtbyaddr(addr, len, type);
623 			break;
624 		      case SERVICE_BIND:
625 			hp = _getdnsbyname(addr, len, type);
626 			break;
627 		      case SERVICE_NIS:
628 #ifdef YP
629 			hp = _getnishost(addr, "hosts.byaddr");
630 #endif
631 			break;
632 		}
633 		nserv++;
634 	}
635 	return hp;
636 }
637 
638