gethostbydns.c revision 11661
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: gethostbydns.c,v 1.6 1995/08/21 09:15:32 bde Exp $";
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
65#include <stdio.h>
66#include <unistd.h>
67#include <string.h>
68#include <netdb.h>
69#include <resolv.h>
70#include <ctype.h>
71#include <errno.h>
72#include <syslog.h>
73
74#include "res_config.h"
75
76#define	MAXALIASES	35
77#define	MAXADDRS	35
78
79#define	MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
80
81static const char AskedForGot[] =
82		  "gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
83
84static char *h_addr_ptrs[MAXADDRS + 1];
85
86static struct hostent host;
87static char *host_aliases[MAXALIASES];
88static char hostbuf[8*1024];
89static struct in_addr host_addr;
90static FILE *hostf = NULL;
91static int stayopen = 0;
92
93#if PACKETSZ > 1024
94#define	MAXPACKET	PACKETSZ
95#else
96#define	MAXPACKET	1024
97#endif
98
99typedef union {
100    HEADER hdr;
101    u_char buf[MAXPACKET];
102} querybuf;
103
104typedef union {
105    int32_t al;
106    char ac;
107} align;
108
109extern int h_errno;
110
111#ifdef DEBUG
112static void
113dprintf(msg, num)
114	char *msg;
115	int num;
116{
117	if (_res.options & RES_DEBUG) {
118		int save = errno;
119
120		printf(msg, num);
121		errno = save;
122	}
123}
124#else
125# define dprintf(msg, num) /*nada*/
126#endif
127
128
129#ifdef RESOLVSORT
130static void
131addrsort(ap, num)
132	char **ap;
133	int num;
134{
135	int i, j;
136	char **p;
137	short aval[MAXADDRS];
138	int needsort = 0;
139
140	p = ap;
141	for (i = 0; i < num; i++, p++) {
142	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
143		if (_res.sort_list[j].addr.s_addr ==
144		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
145			break;
146	    aval[i] = j;
147	    if (needsort == 0 && i > 0 && j < aval[i-1])
148		needsort = i;
149	}
150	if (!needsort)
151	    return;
152
153	while (needsort < num) {
154	    for (j = needsort - 1; j >= 0; j--) {
155		if (aval[j] > aval[j+1]) {
156		    char *hp;
157
158		    i = aval[j];
159		    aval[j] = aval[j+1];
160		    aval[j+1] = i;
161
162		    hp = ap[j];
163		    ap[j] = ap[j+1];
164		    ap[j+1] = hp;
165
166		} else
167		    break;
168	    }
169	    needsort++;
170	}
171}
172#endif
173
174static struct hostent *
175gethostanswer(answer, anslen, qname, qclass, qtype)
176	const querybuf *answer;
177	int anslen;
178	const char *qname;
179	int qclass, qtype;
180{
181	register const HEADER *hp;
182	register const u_char *cp;
183	register int n;
184	const u_char *eom;
185	char *bp, **ap, **hap;
186	int type, class, buflen, ancount, qdcount;
187	int haveanswer, had_error;
188	int toobig = 0;
189	char tbuf[MAXDNAME+1];
190
191	host.h_name = NULL;
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 + HFIXEDSZ;
202	if (qdcount != 1) {
203		h_errno = NO_RECOVERY;
204		return (NULL);
205	}
206	if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) {
207		h_errno = NO_RECOVERY;
208		return (NULL);
209	}
210	cp += n + QFIXEDSZ;
211	if (qtype == T_A) {
212		/* res_send() has already verified that the query name is the
213		 * same as the one we sent; this just gets the expanded name
214		 * (i.e., with the succeeding search-domain tacked on).
215		 */
216		n = strlen(bp) + 1;		/* for the \0 */
217		host.h_name = bp;
218		bp += n;
219		buflen -= n;
220		/* The qname can be abbreviated, but h_name is now absolute. */
221		qname = host.h_name;
222	}
223	ap = host_aliases;
224	*ap = NULL;
225	host.h_aliases = host_aliases;
226	hap = h_addr_ptrs;
227	*hap = NULL;
228	host.h_addr_list = h_addr_ptrs;
229	haveanswer = 0;
230	had_error = 0;
231	while (ancount-- > 0 && cp < eom && !had_error) {
232		n = dn_expand(answer->buf, eom, cp, bp, buflen);
233		if (n < 0) {
234			had_error++;
235			continue;
236		}
237		cp += n;			/* name */
238		type = _getshort(cp);
239 		cp += INT16SZ;			/* type */
240		class = _getshort(cp);
241 		cp += INT16SZ + INT32SZ;	/* class, TTL */
242		n = _getshort(cp);
243		cp += INT16SZ;			/* len */
244		if (class != qclass) {
245			/* XXX - debug? syslog? */
246			cp += n;
247			continue;		/* XXX - had_error++ ? */
248		}
249		if (qtype == T_A && type == T_CNAME) {
250			if (ap >= &host_aliases[MAXALIASES-1])
251				continue;
252			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
253			if (n < 0) {
254				had_error++;
255				continue;
256			}
257			cp += n;
258			if (host.h_name && strcasecmp(host.h_name, bp) != 0) {
259				syslog(LOG_NOTICE|LOG_AUTH,
260		"gethostby*.gethostanswer: asked for \"%s\", got CNAME for \"%s\"",
261				       host.h_name, bp);
262				continue;	/* XXX - had_error++ ? */
263			}
264			/* Store alias. */
265			*ap++ = bp;
266			n = strlen(bp) + 1;	/* for the \0 */
267			bp += n;
268			buflen -= n;
269			/* Get canonical name. */
270			n = strlen(tbuf) + 1;	/* for the \0 */
271			if (n > buflen) {
272				had_error++;
273				continue;
274			}
275			strcpy(bp, tbuf);
276			host.h_name = bp;
277			bp += n;
278			buflen -= n;
279			continue;
280		}
281		if (type != qtype) {
282			/* CNAME->PTR should not cause a log message. */
283			if (!(qtype == T_PTR && type == T_CNAME))
284			syslog(LOG_NOTICE|LOG_AUTH,
285	       "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
286				       qname, p_class(qclass), p_type(qtype),
287				       p_type(type));
288			cp += n;
289			continue;		/* XXX - had_error++ ? */
290		}
291		switch (type) {
292		case T_PTR:
293			if (strcasecmp(qname, bp) != 0) {
294				syslog(LOG_NOTICE|LOG_AUTH,
295				       AskedForGot, qname, bp);
296				cp += n;
297				continue;	/* XXX - had_error++ ? */
298			}
299			n = dn_expand(answer->buf, eom, cp, bp, buflen);
300			if (n < 0) {
301				had_error++;
302				break;
303			}
304#if MULTI_PTRS_ARE_ALIASES
305			cp += n;
306			if (!haveanswer)
307				host.h_name = bp;
308			else if (ap < &host_aliases[MAXALIASES-1])
309				*ap++ = bp;
310			else
311				n = -1;
312			if (n != -1) {
313				n = strlen(bp) + 1;	/* for the \0 */
314				bp += n;
315				buflen -= n;
316			}
317			break;
318#else
319			host.h_name = bp;
320			h_errno = NETDB_SUCCESS;
321			return (&host);
322#endif
323		case T_A:
324			if (strcasecmp(host.h_name, bp) != 0) {
325				syslog(LOG_NOTICE|LOG_AUTH,
326				       AskedForGot, host.h_name, bp);
327				cp += n;
328				continue;	/* XXX - had_error++ ? */
329			}
330			if (haveanswer) {
331				if (n != host.h_length) {
332					cp += n;
333					continue;
334				}
335			} else {
336				register int nn;
337
338				host.h_length = n;
339				host.h_addrtype = (class == C_IN)
340						  ? AF_INET
341						  : AF_UNSPEC;
342				host.h_name = bp;
343				nn = strlen(bp) + 1;	/* for the \0 */
344				bp += nn;
345				buflen -= nn;
346			}
347
348			bp += sizeof(align) - ((u_long)bp % sizeof(align));
349
350			if (bp + n >= &hostbuf[sizeof hostbuf]) {
351				dprintf("size (%d) too big\n", n);
352				had_error++;
353				continue;
354			}
355			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
356				if (!toobig++)
357					dprintf("Too many addresses (%d)\n",
358					       MAXADDRS);
359				cp += n;
360				continue;
361			}
362			bcopy(cp, *hap++ = bp, n);
363			bp += n;
364			cp += n;
365			break;
366		default:
367			dprintf("Impossible condition (type=%d)\n", type);
368			h_errno = NO_RECOVERY;
369			return (NULL);
370		} /*switch*/
371		if (!had_error)
372			haveanswer++;
373	} /*while*/
374	if (haveanswer) {
375		*ap = NULL;
376		*hap = NULL;
377# if defined(RESOLVSORT)
378		/*
379		 * Note: we sort even if host can take only one address
380		 * in its return structures - should give it the "best"
381		 * address in that case, not some random one
382		 */
383		if (_res.nsort && haveanswer > 1 &&
384		    qclass == C_IN && qtype == T_A)
385			addrsort(h_addr_ptrs, haveanswer);
386# endif /*RESOLVSORT*/
387		if (!host.h_name) {
388			n = strlen(qname) + 1;	/* for the \0 */
389			strcpy(bp, qname);
390			host.h_name = bp;
391		}
392		h_errno = NETDB_SUCCESS;
393		return (&host);
394	} else {
395		h_errno = TRY_AGAIN;
396		return (NULL);
397	}
398}
399
400struct hostent *
401_gethostbydnsname(name)
402	const char *name;
403{
404	querybuf buf;
405	register const char *cp;
406	int n;
407
408	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
409		h_errno = NETDB_INTERNAL;
410		return (NULL);
411	}
412
413	/*
414	 * if there aren't any dots, it could be a user-level alias.
415	 * this is also done in res_query() since we are not the only
416	 * function that looks up host names.
417	 */
418	if (!strchr(name, '.') && (cp = __hostalias(name)))
419		name = cp;
420
421	/*
422	 * disallow names consisting only of digits/dots, unless
423	 * they end in a dot.
424	 */
425	if (isdigit(name[0]))
426		for (cp = name;; ++cp) {
427			if (!*cp) {
428				if (*--cp == '.')
429					break;
430				/*
431				 * All-numeric, no dot at the end.
432				 * Fake up a hostent as if we'd actually
433				 * done a lookup.
434				 */
435				if (!inet_aton(name, &host_addr)) {
436					h_errno = HOST_NOT_FOUND;
437					return (NULL);
438				}
439				strncpy(hostbuf, name, MAXDNAME);
440				hostbuf[MAXDNAME] = '\0';
441				host.h_name = hostbuf;
442				host.h_aliases = host_aliases;
443				host_aliases[0] = NULL;
444				host.h_addrtype = AF_INET;
445				host.h_length = INT32SZ;
446				h_addr_ptrs[0] = (char *)&host_addr;
447				h_addr_ptrs[1] = NULL;
448				host.h_addr_list = h_addr_ptrs;
449				return (&host);
450			}
451			if (!isdigit(*cp) && *cp != '.')
452				break;
453		}
454
455	if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
456		dprintf("res_search failed (%d)\n", n);
457		return (NULL);
458	}
459	return (gethostanswer(&buf, n, name, C_IN, T_A));
460}
461
462struct hostent *
463_gethostbydnsaddr(addr, len, type)
464	const char *addr;
465	int len, type;
466{
467	int n;
468	querybuf buf;
469	register struct hostent *hp;
470	char qbuf[MAXDNAME+1];
471#ifdef SUNSECURITY
472	register struct hostent *rhp;
473	char **haddr;
474	u_long old_options;
475	char hname2[MAXDNAME+1];
476#endif /*SUNSECURITY*/
477
478	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
479		h_errno = NETDB_INTERNAL;
480		return (NULL);
481	}
482	if (type != AF_INET) {
483		errno = EAFNOSUPPORT;
484		h_errno = NETDB_INTERNAL;
485		return (NULL);
486	}
487	(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
488		((unsigned)addr[3] & 0xff),
489		((unsigned)addr[2] & 0xff),
490		((unsigned)addr[1] & 0xff),
491		((unsigned)addr[0] & 0xff));
492	n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
493	if (n < 0) {
494		dprintf("res_query failed (%d)\n", n);
495		return (NULL);
496	}
497	if (!(hp = gethostanswer(&buf, n, qbuf, C_IN, T_PTR)))
498		return (NULL);	/* h_errno was set by gethostanswer() */
499#ifdef SUNSECURITY
500	/*
501	 * turn off search as the name should be absolute,
502	 * 'localhost' should be matched by defnames
503	 */
504	strncpy(hname2, hp->h_name, MAXDNAME);
505	hname2[MAXDNAME] = '\0';
506	old_options = _res.options;
507	_res.options &= ~RES_DNSRCH;
508	_res.options |= RES_DEFNAMES;
509	if (!(rhp = gethostbyname(hname2))) {
510		syslog(LOG_NOTICE|LOG_AUTH,
511		       "gethostbyaddr: No A record for %s (verifying [%s])",
512		       hname2, inet_ntoa(*((struct in_addr *)addr)));
513		_res.options = old_options;
514		h_errno = HOST_NOT_FOUND;
515		return (NULL);
516	}
517	_res.options = old_options;
518	for (haddr = rhp->h_addr_list; *haddr; haddr++)
519		if (!memcmp(*haddr, addr, INADDRSZ))
520			break;
521	if (!*haddr) {
522		syslog(LOG_NOTICE|LOG_AUTH,
523		       "gethostbyaddr: A record of %s != PTR record [%s]",
524		       hname2, inet_ntoa(*((struct in_addr *)addr)));
525		h_errno = HOST_NOT_FOUND;
526		return (NULL);
527	}
528#endif /*SUNSECURITY*/
529	hp->h_addrtype = type;
530	hp->h_length = len;
531	h_addr_ptrs[0] = (char *)&host_addr;
532	h_addr_ptrs[1] = NULL;
533	host_addr = *(struct in_addr *)addr;
534	h_errno = NETDB_SUCCESS;
535	return (hp);
536}
537
538void
539_sethostdnsent(stayopen)
540	int stayopen;
541{
542	if (stayopen)
543		_res.options |= RES_STAYOPEN | RES_USEVC;
544}
545
546void
547_endhostdnsent()
548{
549	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
550	_res_close();
551}
552