gethostnamadr.c revision 1991
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)
55static 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 ";*/
57static const char rcsid[] =
58  "$Id$";
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
78enum service_type {
79  SERVICE_NONE = 0,
80  SERVICE_BIND,
81  SERVICE_HOSTS,
82  SERVICE_NIS };
83#define SERVICE_MAX	SERVICE_NIS
84
85static 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
102static enum service_type service_order[SERVICE_MAX + 1];
103static int service_done = 0;
104
105static char *h_addr_ptrs[MAXADDRS + 1];
106
107static struct hostent host;
108static char *host_aliases[MAXALIASES];
109static char hostbuf[BUFSIZ+1];
110static struct in_addr host_addr;
111static FILE *hostf = NULL;
112static char hostaddr[MAXADDRS];
113static char *host_addrs[2];
114static int stayopen = 0;
115
116#if PACKETSZ > 1024
117#define	MAXPACKET	PACKETSZ
118#else
119#define	MAXPACKET	1024
120#endif
121
122typedef union {
123    HEADER hdr;
124    u_char buf[MAXPACKET];
125} querybuf;
126
127typedef union {
128    int32_t al;
129    char ac;
130} align;
131
132extern int h_errno;
133
134static enum service_type
135get_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
145static void
146init_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
177static struct hostent *
178getanswer(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
321struct 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
376struct 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
416void
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
427void
428_endhtent()
429{
430	if (hostf && !stayopen) {
431		(void) fclose(hostf);
432		hostf = NULL;
433	}
434}
435
436struct 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);
444again:
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
487struct 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	}
502found:
503	_endhtent();
504	return (p);
505}
506
507struct 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
524struct 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
576struct hostent *
577gethostbyname(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
607struct hostent *
608gethostbyaddr(const char *addr, int len, int type)
609{
610	struct hostent *hp = 0;
611	int nserv = 0;
612
613	if(!service_done) {
614		init_service();
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