gethostnamadr.c revision 1573
1261287Sdes/*-
2261287Sdes * Copyright (c) 1985, 1988, 1993
3261287Sdes *	The Regents of the University of California.  All rights reserved.
4261287Sdes *
5261287Sdes * Redistribution and use in source and binary forms, with or without
6261287Sdes * modification, are permitted provided that the following conditions
7261287Sdes * are met:
8261287Sdes * 1. Redistributions of source code must retain the above copyright
9261287Sdes *    notice, this list of conditions and the following disclaimer.
10261287Sdes * 2. Redistributions in binary form must reproduce the above copyright
11261287Sdes *    notice, this list of conditions and the following disclaimer in the
12261287Sdes *    documentation and/or other materials provided with the distribution.
13261287Sdes * 3. All advertising materials mentioning features or use of this software
14261287Sdes *    must display the following acknowledgement:
15261287Sdes *	This product includes software developed by the University of
16261287Sdes *	California, Berkeley and its contributors.
17261287Sdes * 4. Neither the name of the University nor the names of its contributors
18261287Sdes *    may be used to endorse or promote products derived from this software
19261287Sdes *    without specific prior written permission.
20261287Sdes *
21261287Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22261287Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23261287Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24261287Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25261287Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26261287Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27261287Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28261287Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29261287Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30261287Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31261287Sdes * SUCH DAMAGE.
32261287Sdes * -
33261287Sdes * Portions Copyright (c) 1993 by Digital Equipment Corporation.
34261287Sdes *
35261287Sdes * Permission to use, copy, modify, and distribute this software for any
36261287Sdes * purpose with or without fee is hereby granted, provided that the above
37261287Sdes * copyright notice and this permission notice appear in all copies, and that
38261287Sdes * the name of Digital Equipment Corporation not be used in advertising or
39261287Sdes * publicity pertaining to distribution of the document or software without
40261287Sdes * specific, written prior permission.
41261287Sdes *
42261287Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43261287Sdes * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44261287Sdes * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
45261287Sdes * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46261287Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47261287Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48261287Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49261287Sdes * SOFTWARE.
50261287Sdes * -
51261287Sdes * --Copyright--
52261287Sdes */
53261287Sdes
54261287Sdes#if defined(LIBC_SCCS) && !defined(lint)
55261287Sdesstatic char sccsid[] = "@(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
56261287Sdesstatic char rcsid[] = "$Id: gethnamaddr.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
57261287Sdes#endif /* LIBC_SCCS and not lint */
58261287Sdes
59261287Sdes#include <sys/param.h>
60261287Sdes#include <sys/socket.h>
61261287Sdes#include <netinet/in.h>
62261287Sdes#include <arpa/inet.h>
63261287Sdes#include <arpa/nameser.h>
64261287Sdes#include <netdb.h>
65261287Sdes#include <resolv.h>
66261287Sdes#include <stdio.h>
67261287Sdes#include <ctype.h>
68261287Sdes#include <errno.h>
69261287Sdes#include <string.h>
70261287Sdes
71261287Sdes#define	MAXALIASES	35
72261287Sdes#define	MAXADDRS	35
73261287Sdes
74261287Sdesstatic char *h_addr_ptrs[MAXADDRS + 1];
75261287Sdes
76261287Sdesstatic struct hostent host;
77261287Sdesstatic char *host_aliases[MAXALIASES];
78261287Sdesstatic char hostbuf[BUFSIZ+1];
79261287Sdesstatic struct in_addr host_addr;
80261287Sdesstatic FILE *hostf = NULL;
81261287Sdesstatic char hostaddr[MAXADDRS];
82261287Sdesstatic char *host_addrs[2];
83261287Sdesstatic int stayopen = 0;
84261287Sdeschar *strpbrk();
85261287Sdes
86261287Sdes#if PACKETSZ > 1024
87261287Sdes#define	MAXPACKET	PACKETSZ
88261287Sdes#else
89261287Sdes#define	MAXPACKET	1024
90261287Sdes#endif
91261287Sdes
92261287Sdestypedef union {
93261287Sdes    HEADER hdr;
94261287Sdes    u_char buf[MAXPACKET];
95261287Sdes} querybuf;
96261287Sdes
97261287Sdestypedef union {
98261287Sdes    int32_t al;
99261287Sdes    char ac;
100261287Sdes} align;
101261287Sdes
102261287Sdesextern int h_errno;
103261287Sdes
104261287Sdesstatic struct hostent *
105261287Sdesgetanswer(answer, anslen, iquery)
106261287Sdes	querybuf *answer;
107261287Sdes	int anslen;
108261287Sdes	int iquery;
109261287Sdes{
110261287Sdes	register HEADER *hp;
111261287Sdes	register u_char *cp;
112261287Sdes	register int n;
113261287Sdes	u_char *eom;
114261287Sdes	char *bp, **ap;
115261287Sdes	int type, class, buflen, ancount, qdcount;
116261287Sdes	int haveanswer, getclass = C_ANY;
117261287Sdes	char **hap;
118261287Sdes
119261287Sdes	eom = answer->buf + anslen;
120261287Sdes	/*
121261287Sdes	 * find first satisfactory answer
122261287Sdes	 */
123261287Sdes	hp = &answer->hdr;
124261287Sdes	ancount = ntohs(hp->ancount);
125261287Sdes	qdcount = ntohs(hp->qdcount);
126261287Sdes	bp = hostbuf;
127261287Sdes	buflen = sizeof(hostbuf);
128261287Sdes	cp = answer->buf + sizeof(HEADER);
129261287Sdes	if (qdcount) {
130261287Sdes		if (iquery) {
131261287Sdes			if ((n = dn_expand((u_char *)answer->buf,
132261287Sdes			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
133261287Sdes			    buflen)) < 0) {
134261287Sdes				h_errno = NO_RECOVERY;
135261287Sdes				return ((struct hostent *) NULL);
136261287Sdes			}
137261287Sdes			cp += n + QFIXEDSZ;
138261287Sdes			host.h_name = bp;
139261287Sdes			n = strlen(bp) + 1;
140261287Sdes			bp += n;
141261287Sdes			buflen -= n;
142261287Sdes		} else
143261287Sdes			cp += __dn_skipname(cp, eom) + QFIXEDSZ;
144261287Sdes		while (--qdcount > 0)
145261287Sdes			cp += __dn_skipname(cp, eom) + QFIXEDSZ;
146261287Sdes	} else if (iquery) {
147261287Sdes		if (hp->aa)
148261287Sdes			h_errno = HOST_NOT_FOUND;
149261287Sdes		else
150261287Sdes			h_errno = TRY_AGAIN;
151261287Sdes		return ((struct hostent *) NULL);
152261287Sdes	}
153261287Sdes	ap = host_aliases;
154261287Sdes	*ap = NULL;
155261287Sdes	host.h_aliases = host_aliases;
156261287Sdes	hap = h_addr_ptrs;
157261287Sdes	*hap = NULL;
158261287Sdes#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
159261287Sdes	host.h_addr_list = h_addr_ptrs;
160261287Sdes#endif
161261287Sdes	haveanswer = 0;
162261287Sdes	while (--ancount >= 0 && cp < eom) {
163261287Sdes		if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
164261287Sdes		    (u_char *)cp, (u_char *)bp, buflen)) < 0)
165261287Sdes			break;
166261287Sdes		cp += n;
167261287Sdes		type = _getshort(cp);
168261287Sdes 		cp += sizeof(u_int16_t);
169261287Sdes		class = _getshort(cp);
170261287Sdes 		cp += sizeof(u_int16_t) + sizeof(u_int32_t);
171261287Sdes		n = _getshort(cp);
172261287Sdes		cp += sizeof(u_int16_t);
173261287Sdes		if (type == T_CNAME) {
174261287Sdes			cp += n;
175261287Sdes			if (ap >= &host_aliases[MAXALIASES-1])
176261287Sdes				continue;
177261287Sdes			*ap++ = bp;
178261287Sdes			n = strlen(bp) + 1;
179261287Sdes			bp += n;
180261287Sdes			buflen -= n;
181261287Sdes			continue;
182261287Sdes		}
183261287Sdes		if (iquery && type == T_PTR) {
184261287Sdes			if ((n = dn_expand((u_char *)answer->buf,
185261287Sdes			    (u_char *)eom, (u_char *)cp, (u_char *)bp,
186261287Sdes			    buflen)) < 0)
187261287Sdes				break;
188261287Sdes			cp += n;
189261287Sdes			host.h_name = bp;
190261287Sdes			return(&host);
191261287Sdes		}
192261287Sdes		if (iquery || type != T_A)  {
193261287Sdes#ifdef DEBUG
194261287Sdes			if (_res.options & RES_DEBUG)
195261287Sdes				printf("unexpected answer type %d, size %d\n",
196261287Sdes					type, n);
197261287Sdes#endif
198261287Sdes			cp += n;
199261287Sdes			continue;
200261287Sdes		}
201261287Sdes		if (haveanswer) {
202261287Sdes			if (n != host.h_length) {
203261287Sdes				cp += n;
204261287Sdes				continue;
205261287Sdes			}
206261287Sdes			if (class != getclass) {
207261287Sdes				cp += n;
208261287Sdes				continue;
209261287Sdes			}
210261287Sdes		} else {
211261287Sdes			host.h_length = n;
212261287Sdes			getclass = class;
213261287Sdes			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
214261287Sdes			if (!iquery) {
215261287Sdes				host.h_name = bp;
216261287Sdes				bp += strlen(bp) + 1;
217261287Sdes			}
218261287Sdes		}
219261287Sdes
220261287Sdes		bp += sizeof(align) - ((u_int32_t)bp % sizeof(align));
221261287Sdes
222261287Sdes		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
223261287Sdes#ifdef DEBUG
224261287Sdes			if (_res.options & RES_DEBUG)
225261287Sdes				printf("size (%d) too big\n", n);
226261287Sdes#endif
227261287Sdes			break;
228261287Sdes		}
229261287Sdes		bcopy(cp, *hap++ = bp, n);
230261287Sdes		bp +=n;
231261287Sdes		cp += n;
232261287Sdes		haveanswer++;
233261287Sdes	}
234261287Sdes	if (haveanswer) {
235261287Sdes		*ap = NULL;
236261287Sdes#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
237261287Sdes		*hap = NULL;
238261287Sdes#else
239261287Sdes		host.h_addr = h_addr_ptrs[0];
240261287Sdes#endif
241261287Sdes		return (&host);
242261287Sdes	} else {
243261287Sdes		h_errno = TRY_AGAIN;
244261287Sdes		return ((struct hostent *) NULL);
245261287Sdes	}
246261287Sdes}
247261287Sdes
248261287Sdesstruct hostent *
249261287Sdesgethostbyname(name)
250261287Sdes	const char *name;
251261287Sdes{
252261287Sdes	querybuf buf;
253261287Sdes	register const char *cp;
254261287Sdes	int n;
255261287Sdes	extern struct hostent *_gethtbyname();
256261287Sdes
257261287Sdes	/*
258261287Sdes	 * disallow names consisting only of digits/dots, unless
259261287Sdes	 * they end in a dot.
260261287Sdes	 */
261261287Sdes	if (isdigit(name[0]))
262261287Sdes		for (cp = name;; ++cp) {
263261287Sdes			if (!*cp) {
264261287Sdes				if (*--cp == '.')
265261287Sdes					break;
266261287Sdes				/*
267261287Sdes				 * All-numeric, no dot at the end.
268261287Sdes				 * Fake up a hostent as if we'd actually
269261287Sdes				 * 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