gethostnamadr.c revision 1573
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[] = "@(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
56static char rcsid[] = "$Id: gethnamaddr.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
57#endif /* LIBC_SCCS and not lint */
58
59#include <sys/param.h>
60#include <sys/socket.h>
61#include <netinet/in.h>
62#include <arpa/inet.h>
63#include <arpa/nameser.h>
64#include <netdb.h>
65#include <resolv.h>
66#include <stdio.h>
67#include <ctype.h>
68#include <errno.h>
69#include <string.h>
70
71#define	MAXALIASES	35
72#define	MAXADDRS	35
73
74static char *h_addr_ptrs[MAXADDRS + 1];
75
76static struct hostent host;
77static char *host_aliases[MAXALIASES];
78static char hostbuf[BUFSIZ+1];
79static struct in_addr host_addr;
80static FILE *hostf = NULL;
81static char hostaddr[MAXADDRS];
82static char *host_addrs[2];
83static int stayopen = 0;
84char *strpbrk();
85
86#if PACKETSZ > 1024
87#define	MAXPACKET	PACKETSZ
88#else
89#define	MAXPACKET	1024
90#endif
91
92typedef union {
93    HEADER hdr;
94    u_char buf[MAXPACKET];
95} querybuf;
96
97typedef union {
98    int32_t al;
99    char ac;
100} align;
101
102extern int h_errno;
103
104static struct hostent *
105getanswer(answer, anslen, iquery)
106	querybuf *answer;
107	int anslen;
108	int iquery;
109{
110	register HEADER *hp;
111	register u_char *cp;
112	register int n;
113	u_char *eom;
114	char *bp, **ap;
115	int type, class, buflen, ancount, qdcount;
116	int haveanswer, getclass = C_ANY;
117	char **hap;
118
119	eom = answer->buf + anslen;
120	/*
121	 * find first satisfactory answer
122	 */
123	hp = &answer->hdr;
124	ancount = ntohs(hp->ancount);
125	qdcount = ntohs(hp->qdcount);
126	bp = hostbuf;
127	buflen = sizeof(hostbuf);
128	cp = answer->buf + sizeof(HEADER);
129	if (qdcount) {
130		if (iquery) {
131			if ((n = dn_expand((u_char *)answer->buf,
132			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
133			    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	*ap = NULL;
155	host.h_aliases = host_aliases;
156	hap = h_addr_ptrs;
157	*hap = NULL;
158#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
159	host.h_addr_list = h_addr_ptrs;
160#endif
161	haveanswer = 0;
162	while (--ancount >= 0 && cp < eom) {
163		if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
164		    (u_char *)cp, (u_char *)bp, buflen)) < 0)
165			break;
166		cp += n;
167		type = _getshort(cp);
168 		cp += sizeof(u_int16_t);
169		class = _getshort(cp);
170 		cp += sizeof(u_int16_t) + sizeof(u_int32_t);
171		n = _getshort(cp);
172		cp += sizeof(u_int16_t);
173		if (type == T_CNAME) {
174			cp += n;
175			if (ap >= &host_aliases[MAXALIASES-1])
176				continue;
177			*ap++ = bp;
178			n = strlen(bp) + 1;
179			bp += n;
180			buflen -= n;
181			continue;
182		}
183		if (iquery && type == T_PTR) {
184			if ((n = dn_expand((u_char *)answer->buf,
185			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
186			    buflen)) < 0)
187				break;
188			cp += n;
189			host.h_name = bp;
190			return(&host);
191		}
192		if (iquery || type != T_A)  {
193#ifdef DEBUG
194			if (_res.options & RES_DEBUG)
195				printf("unexpected answer type %d, size %d\n",
196					type, n);
197#endif
198			cp += n;
199			continue;
200		}
201		if (haveanswer) {
202			if (n != host.h_length) {
203				cp += n;
204				continue;
205			}
206			if (class != getclass) {
207				cp += n;
208				continue;
209			}
210		} else {
211			host.h_length = n;
212			getclass = class;
213			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
214			if (!iquery) {
215				host.h_name = bp;
216				bp += strlen(bp) + 1;
217			}
218		}
219
220		bp += sizeof(align) - ((u_int32_t)bp % sizeof(align));
221
222		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
223#ifdef DEBUG
224			if (_res.options & RES_DEBUG)
225				printf("size (%d) too big\n", n);
226#endif
227			break;
228		}
229		bcopy(cp, *hap++ = bp, n);
230		bp +=n;
231		cp += n;
232		haveanswer++;
233	}
234	if (haveanswer) {
235		*ap = NULL;
236#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
237		*hap = NULL;
238#else
239		host.h_addr = h_addr_ptrs[0];
240#endif
241		return (&host);
242	} else {
243		h_errno = TRY_AGAIN;
244		return ((struct hostent *) NULL);
245	}
246}
247
248struct hostent *
249gethostbyname(name)
250	const char *name;
251{
252	querybuf buf;
253	register const char *cp;
254	int n;
255	extern struct hostent *_gethtbyname();
256
257	/*
258	 * disallow names consisting only of digits/dots, unless
259	 * they end in a dot.
260	 */
261	if (isdigit(name[0]))
262		for (cp = name;; ++cp) {
263			if (!*cp) {
264				if (*--cp == '.')
265					break;
266				/*
267				 * All-numeric, no dot at the end.
268				 * Fake up a hostent as if we'd actually
269				 * done a lookup.
270				 */
271				if (!inet_aton(name, &host_addr)) {
272					h_errno = HOST_NOT_FOUND;
273					return((struct hostent *) NULL);
274				}
275				host.h_name = (char *)name;
276				host.h_aliases = host_aliases;
277				host_aliases[0] = NULL;
278				host.h_addrtype = AF_INET;
279				host.h_length = sizeof(u_int32_t);
280				h_addr_ptrs[0] = (char *)&host_addr;
281				h_addr_ptrs[1] = (char *)0;
282#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
283				host.h_addr_list = h_addr_ptrs;
284#else
285				host.h_addr = h_addr_ptrs[0];
286#endif
287				return (&host);
288			}
289			if (!isdigit(*cp) && *cp != '.')
290				break;
291		}
292
293	if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
294#ifdef DEBUG
295		if (_res.options & RES_DEBUG)
296			printf("res_search failed\n");
297#endif
298		if (errno == ECONNREFUSED)
299			return (_gethtbyname(name));
300		else
301			return ((struct hostent *) NULL);
302	}
303	return (getanswer(&buf, n, 0));
304}
305
306struct hostent *
307gethostbyaddr(addr, len, type)
308	const char *addr;
309	int len, type;
310{
311	int n;
312	querybuf buf;
313	register struct hostent *hp;
314	char qbuf[MAXDNAME];
315	extern struct hostent *_gethtbyaddr();
316
317	if (type != AF_INET)
318		return ((struct hostent *) NULL);
319	(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
320		((unsigned)addr[3] & 0xff),
321		((unsigned)addr[2] & 0xff),
322		((unsigned)addr[1] & 0xff),
323		((unsigned)addr[0] & 0xff));
324	n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf));
325	if (n < 0) {
326#ifdef DEBUG
327		if (_res.options & RES_DEBUG)
328			printf("res_query failed\n");
329#endif
330		if (errno == ECONNREFUSED)
331			return (_gethtbyaddr(addr, len, type));
332		return ((struct hostent *) NULL);
333	}
334	hp = getanswer(&buf, n, 1);
335	if (hp == NULL)
336		return ((struct hostent *) NULL);
337	hp->h_addrtype = type;
338	hp->h_length = len;
339	h_addr_ptrs[0] = (char *)&host_addr;
340	h_addr_ptrs[1] = (char *)0;
341	host_addr = *(struct in_addr *)addr;
342#if BSD < 43 && !defined(h_addr)	/* new-style hostent structure */
343	hp->h_addr = h_addr_ptrs[0];
344#endif
345	return(hp);
346}
347
348void
349_sethtent(f)
350	int f;
351{
352	if (hostf == NULL)
353		hostf = fopen(_PATH_HOSTS, "r" );
354	else
355		rewind(hostf);
356	stayopen |= f;
357}
358
359void
360_endhtent()
361{
362	if (hostf && !stayopen) {
363		(void) fclose(hostf);
364		hostf = NULL;
365	}
366}
367
368struct hostent *
369_gethtent()
370{
371	char *p;
372	register char *cp, **q;
373
374	if (hostf == NULL && (hostf = fopen(_PATH_HOSTS, "r" )) == NULL)
375		return (NULL);
376again:
377	if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
378		return (NULL);
379	if (*p == '#')
380		goto again;
381	cp = strpbrk(p, "#\n");
382	if (cp == NULL)
383		goto again;
384	*cp = '\0';
385	cp = strpbrk(p, " \t");
386	if (cp == NULL)
387		goto again;
388	*cp++ = '\0';
389	/* THIS STUFF IS INTERNET SPECIFIC */
390#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
391	host.h_addr_list = host_addrs;
392#endif
393	host.h_addr = hostaddr;
394	*((u_int32_t *)host.h_addr) = inet_addr(p);
395	host.h_length = sizeof (u_int32_t);
396	host.h_addrtype = AF_INET;
397	while (*cp == ' ' || *cp == '\t')
398		cp++;
399	host.h_name = cp;
400	q = host.h_aliases = host_aliases;
401	cp = strpbrk(cp, " \t");
402	if (cp != NULL)
403		*cp++ = '\0';
404	while (cp && *cp) {
405		if (*cp == ' ' || *cp == '\t') {
406			cp++;
407			continue;
408		}
409		if (q < &host_aliases[MAXALIASES - 1])
410			*q++ = cp;
411		cp = strpbrk(cp, " \t");
412		if (cp != NULL)
413			*cp++ = '\0';
414	}
415	*q = NULL;
416	return (&host);
417}
418
419struct hostent *
420_gethtbyname(name)
421	char *name;
422{
423	register struct hostent *p;
424	register char **cp;
425
426	_sethtent(0);
427	while (p = _gethtent()) {
428		if (strcasecmp(p->h_name, name) == 0)
429			break;
430		for (cp = p->h_aliases; *cp != 0; cp++)
431			if (strcasecmp(*cp, name) == 0)
432				goto found;
433	}
434found:
435	_endhtent();
436	return (p);
437}
438
439struct hostent *
440_gethtbyaddr(addr, len, type)
441	const char *addr;
442	int len, type;
443{
444	register struct hostent *p;
445
446	_sethtent(0);
447	while (p = _gethtent())
448		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
449			break;
450	_endhtent();
451	return (p);
452}
453