gethostbydns.c revision 20892
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.13 1996/12/22 22:05:43 wpaul Exp $";
57#endif /* LIBC_SCCS and not lint */
58
59#include <sys/types.h>
60#include <sys/param.h>
61#include <sys/socket.h>
62#include <netinet/in.h>
63#include <arpa/inet.h>
64#include <arpa/nameser.h>
65
66#include <stdio.h>
67#include <unistd.h>
68#include <string.h>
69#include <netdb.h>
70#include <resolv.h>
71#include <ctype.h>
72#include <errno.h>
73#include <syslog.h>
74
75#include "res_config.h"
76
77extern void _res_close __P((void));
78
79#define SPRINTF(x) ((size_t)sprintf x)
80
81#define	MAXALIASES	35
82#define	MAXADDRS	35
83
84static const char AskedForGot[] =
85		"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
86
87static char *h_addr_ptrs[MAXADDRS + 1];
88static struct hostent *gethostbyname_ipv4 __P((const char *));
89
90static struct hostent host;
91static char *host_aliases[MAXALIASES];
92static char hostbuf[8*1024];
93static u_char host_addr[16];	/* IPv4 or IPv6 */
94
95#ifdef RESOLVSORT
96static void addrsort __P((char **, int));
97#endif
98
99#if PACKETSZ > 1024
100#define	MAXPACKET	PACKETSZ
101#else
102#define	MAXPACKET	1024
103#endif
104
105typedef union {
106    HEADER hdr;
107    u_char buf[MAXPACKET];
108} querybuf;
109
110typedef union {
111    int32_t al;
112    char ac;
113} align;
114
115extern int h_errno;
116int _dns_ttl_;
117
118#ifdef DEBUG
119static void
120dprintf(msg, num)
121	char *msg;
122	int num;
123{
124	if (_res.options & RES_DEBUG) {
125		int save = errno;
126
127		printf(msg, num);
128		errno = save;
129	}
130}
131#else
132# define dprintf(msg, num) /*nada*/
133#endif
134
135static struct hostent *
136gethostanswer(answer, anslen, qname, qtype)
137	const querybuf *answer;
138	int anslen;
139	const char *qname;
140	int qtype;
141{
142	register const HEADER *hp;
143	register const u_char *cp;
144	register int n;
145	const u_char *eom;
146	char *bp, **ap, **hap;
147	int type, class, buflen, ancount, qdcount;
148	int haveanswer, had_error;
149	int toobig = 0;
150	char tbuf[MAXDNAME+1];
151	const char *tname;
152	int (*name_ok) __P((const char *));
153
154	tname = qname;
155	host.h_name = NULL;
156	eom = answer->buf + anslen;
157	switch (qtype) {
158	case T_A:
159	case T_AAAA:
160		name_ok = res_hnok;
161		break;
162	case T_PTR:
163		name_ok = res_dnok;
164		break;
165	default:
166		h_errno = NO_RECOVERY;
167		return (NULL);	/* XXX should be abort(); */
168	}
169	/*
170	 * find first satisfactory answer
171	 */
172	hp = &answer->hdr;
173	ancount = ntohs(hp->ancount);
174	qdcount = ntohs(hp->qdcount);
175	bp = hostbuf;
176	buflen = sizeof hostbuf;
177	cp = answer->buf + HFIXEDSZ;
178	if (qdcount != 1) {
179		h_errno = NO_RECOVERY;
180		return (NULL);
181	}
182	n = dn_expand(answer->buf, eom, cp, bp, buflen);
183	if ((n < 0) || !(*name_ok)(bp)) {
184		h_errno = NO_RECOVERY;
185		return (NULL);
186	}
187	cp += n + QFIXEDSZ;
188	if (qtype == T_A || qtype == T_AAAA) {
189		/* res_send() has already verified that the query name is the
190		 * same as the one we sent; this just gets the expanded name
191		 * (i.e., with the succeeding search-domain tacked on).
192		 */
193		n = strlen(bp) + 1;		/* for the \0 */
194		host.h_name = bp;
195		bp += n;
196		buflen -= n;
197		/* The qname can be abbreviated, but h_name is now absolute. */
198		qname = host.h_name;
199	}
200	ap = host_aliases;
201	*ap = NULL;
202	host.h_aliases = host_aliases;
203	hap = h_addr_ptrs;
204	*hap = NULL;
205	host.h_addr_list = h_addr_ptrs;
206	haveanswer = 0;
207	had_error = 0;
208	_dns_ttl_ = -1;
209	while (ancount-- > 0 && cp < eom && !had_error) {
210		n = dn_expand(answer->buf, eom, cp, bp, buflen);
211		if ((n < 0) || !(*name_ok)(bp)) {
212			had_error++;
213			continue;
214		}
215		cp += n;			/* name */
216		type = _getshort(cp);
217 		cp += INT16SZ;			/* type */
218		class = _getshort(cp);
219 		cp += INT16SZ;			/* class */
220		if (qtype == T_A  && type == T_A)
221			_dns_ttl_ = _getlong(cp);
222		cp += INT32SZ;			/* TTL */
223		n = _getshort(cp);
224		cp += INT16SZ;			/* len */
225		if (class != C_IN) {
226			/* XXX - debug? syslog? */
227			cp += n;
228			continue;		/* XXX - had_error++ ? */
229		}
230		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
231			if (ap >= &host_aliases[MAXALIASES-1])
232				continue;
233			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
234			if ((n < 0) || !(*name_ok)(tbuf)) {
235				had_error++;
236				continue;
237			}
238			cp += n;
239			/* Store alias. */
240			*ap++ = bp;
241			n = strlen(bp) + 1;	/* for the \0 */
242			bp += n;
243			buflen -= n;
244			/* Get canonical name. */
245			n = strlen(tbuf) + 1;	/* for the \0 */
246			if (n > buflen) {
247				had_error++;
248				continue;
249			}
250			strcpy(bp, tbuf);
251			host.h_name = bp;
252			bp += n;
253			buflen -= n;
254			continue;
255		}
256		if (qtype == T_PTR && type == T_CNAME) {
257			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
258			if ((n < 0) || !res_hnok(tbuf)) {
259				had_error++;
260				continue;
261			}
262			cp += n;
263			/* Get canonical name. */
264			n = strlen(tbuf) + 1;	/* for the \0 */
265			if (n > buflen) {
266				had_error++;
267				continue;
268			}
269			strcpy(bp, tbuf);
270			tname = bp;
271			bp += n;
272			buflen -= n;
273			continue;
274		}
275		if (type != qtype) {
276			syslog(LOG_NOTICE|LOG_AUTH,
277       "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
278			       qname, p_class(C_IN), p_type(qtype),
279			       p_type(type));
280			cp += n;
281			continue;		/* XXX - had_error++ ? */
282		}
283		switch (type) {
284		case T_PTR:
285			if (strcasecmp(tname, bp) != 0) {
286				syslog(LOG_NOTICE|LOG_AUTH,
287				       AskedForGot, qname, bp);
288				cp += n;
289				continue;	/* XXX - had_error++ ? */
290			}
291			n = dn_expand(answer->buf, eom, cp, bp, buflen);
292			if ((n < 0) || !res_hnok(bp)) {
293				had_error++;
294				break;
295			}
296#if MULTI_PTRS_ARE_ALIASES
297			cp += n;
298			if (!haveanswer)
299				host.h_name = bp;
300			else if (ap < &host_aliases[MAXALIASES-1])
301				*ap++ = bp;
302			else
303				n = -1;
304			if (n != -1) {
305				n = strlen(bp) + 1;	/* for the \0 */
306				bp += n;
307				buflen -= n;
308			}
309			break;
310#else
311			host.h_name = bp;
312			if (_res.options & RES_USE_INET6) {
313				n = strlen(bp) + 1;	/* for the \0 */
314				bp += n;
315				buflen -= n;
316				_map_v4v6_hostent(&host, &bp, &buflen);
317			}
318			h_errno = NETDB_SUCCESS;
319			return (&host);
320#endif
321		case T_A:
322		case T_AAAA:
323			if (strcasecmp(host.h_name, bp) != 0) {
324				syslog(LOG_NOTICE|LOG_AUTH,
325				       AskedForGot, host.h_name, bp);
326				cp += n;
327				continue;	/* XXX - had_error++ ? */
328			}
329			if (n != host.h_length) {
330				cp += n;
331				continue;
332			}
333			if (!haveanswer) {
334				register int nn;
335
336				host.h_name = bp;
337				nn = strlen(bp) + 1;	/* for the \0 */
338				bp += nn;
339				buflen -= nn;
340			}
341
342			bp += sizeof(align) - ((u_long)bp % sizeof(align));
343
344			if (bp + n >= &hostbuf[sizeof hostbuf]) {
345				dprintf("size (%d) too big\n", n);
346				had_error++;
347				continue;
348			}
349			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
350				if (!toobig++)
351					dprintf("Too many addresses (%d)\n",
352						MAXADDRS);
353				cp += n;
354				continue;
355			}
356			bcopy(cp, *hap++ = bp, n);
357			bp += n;
358			buflen -= n;
359			cp += n;
360			break;
361		default:
362			dprintf("Impossible condition (type=%d)\n", type);
363			h_errno = NO_RECOVERY;
364			return (NULL);
365		} /*switch*/
366		if (!had_error)
367			haveanswer++;
368	} /*while*/
369	if (haveanswer) {
370		*ap = NULL;
371		*hap = NULL;
372# if defined(RESOLVSORT)
373		/*
374		 * Note: we sort even if host can take only one address
375		 * in its return structures - should give it the "best"
376		 * address in that case, not some random one
377		 */
378		if (_res.nsort && haveanswer > 1 && qtype == T_A)
379			addrsort(h_addr_ptrs, haveanswer);
380# endif /*RESOLVSORT*/
381		if (!host.h_name) {
382			n = strlen(qname) + 1;	/* for the \0 */
383			if (n > buflen)
384				goto try_again;
385			strcpy(bp, qname);
386			host.h_name = bp;
387			bp += n;
388			buflen -= n;
389		}
390		if (_res.options & RES_USE_INET6)
391			_map_v4v6_hostent(&host, &bp, &buflen);
392		h_errno = NETDB_SUCCESS;
393		return (&host);
394	}
395 try_again:
396	h_errno = TRY_AGAIN;
397	return (NULL);
398}
399
400struct hostent *
401__dns_getanswer(answer, anslen, qname, qtype)
402	const char *answer;
403	int anslen;
404	const char *qname;
405	int qtype;
406{
407	switch(qtype) {
408	case T_AAAA:
409		host.h_addrtype = AF_INET6;
410		host.h_length = IN6ADDRSZ;
411		break;
412	case T_A:
413	default:
414		host.h_addrtype = AF_INET;
415		host.h_length = INADDRSZ;
416		break;
417		return(NULL);
418	}
419
420	return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
421}
422
423struct hostent *
424_gethostbydnsname(name, af)
425	const char *name;
426	int af;
427{
428	querybuf buf;
429	register const char *cp;
430	char *bp;
431	int n, size, type, len;
432
433	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
434		h_errno = NETDB_INTERNAL;
435		return (NULL);
436	}
437
438	switch (af) {
439	case AF_INET:
440		size = INADDRSZ;
441		type = T_A;
442		break;
443	case AF_INET6:
444		size = IN6ADDRSZ;
445		type = T_AAAA;
446		break;
447	default:
448		h_errno = NETDB_INTERNAL;
449		errno = EAFNOSUPPORT;
450		return (NULL);
451	}
452
453	host.h_addrtype = af;
454	host.h_length = size;
455
456	/*
457	 * if there aren't any dots, it could be a user-level alias.
458	 * this is also done in res_query() since we are not the only
459	 * function that looks up host names.
460	 */
461	if (!strchr(name, '.') && (cp = __hostalias(name)))
462		name = cp;
463
464	/*
465	 * disallow names consisting only of digits/dots, unless
466	 * they end in a dot.
467	 */
468	if (isdigit(name[0]))
469		for (cp = name;; ++cp) {
470			if (!*cp) {
471				if (*--cp == '.')
472					break;
473				/*
474				 * All-numeric, no dot at the end.
475				 * Fake up a hostent as if we'd actually
476				 * done a lookup.
477				 */
478				if (inet_pton(af, name, host_addr) <= 0) {
479					h_errno = HOST_NOT_FOUND;
480					return (NULL);
481				}
482				strncpy(hostbuf, name, MAXDNAME);
483				hostbuf[MAXDNAME] = '\0';
484				bp = hostbuf + MAXDNAME;
485				len = sizeof hostbuf - MAXDNAME;
486				host.h_name = hostbuf;
487				host.h_aliases = host_aliases;
488				host_aliases[0] = NULL;
489				h_addr_ptrs[0] = (char *)host_addr;
490				h_addr_ptrs[1] = NULL;
491				host.h_addr_list = h_addr_ptrs;
492				if (_res.options & RES_USE_INET6)
493					_map_v4v6_hostent(&host, &bp, &len);
494				h_errno = NETDB_SUCCESS;
495				return (&host);
496			}
497			if (!isdigit(*cp) && *cp != '.')
498				break;
499		}
500
501	if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
502		dprintf("res_search failed (%d)\n", n);
503		return (NULL);
504	}
505	return (gethostanswer(&buf, n, name, type));
506}
507
508struct hostent *
509_gethostbydnsaddr(addr, len, af)
510	const char *addr;	/* XXX should have been def'd as u_char! */
511	int len, af;
512{
513	const u_char *uaddr = (const u_char *)addr;
514	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
515	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
516	int n, size;
517	querybuf buf;
518	register struct hostent *hp;
519	char qbuf[MAXDNAME+1], *qp;
520#ifdef SUNSECURITY
521	register struct hostent *rhp;
522	char **haddr;
523	u_long old_options;
524	char hname2[MAXDNAME+1];
525#endif /*SUNSECURITY*/
526
527	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
528		h_errno = NETDB_INTERNAL;
529		return (NULL);
530	}
531	if (af == AF_INET6 && len == IN6ADDRSZ &&
532	    (!bcmp(uaddr, mapped, sizeof mapped) ||
533	     !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
534		/* Unmap. */
535		addr += sizeof mapped;
536		uaddr += sizeof mapped;
537		af = AF_INET;
538		len = INADDRSZ;
539	}
540	switch (af) {
541	case AF_INET:
542		size = INADDRSZ;
543		break;
544	case AF_INET6:
545		size = IN6ADDRSZ;
546		break;
547	default:
548		errno = EAFNOSUPPORT;
549		h_errno = NETDB_INTERNAL;
550		return (NULL);
551	}
552	if (size != len) {
553		errno = EINVAL;
554		h_errno = NETDB_INTERNAL;
555		return (NULL);
556	}
557	switch (af) {
558	case AF_INET:
559		(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
560			       (uaddr[3] & 0xff),
561			       (uaddr[2] & 0xff),
562			       (uaddr[1] & 0xff),
563			       (uaddr[0] & 0xff));
564		break;
565	case AF_INET6:
566		qp = qbuf;
567		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
568			qp += SPRINTF((qp, "%x.%x.",
569				       uaddr[n] & 0xf,
570				       (uaddr[n] >> 4) & 0xf));
571		}
572		strcpy(qp, "ip6.int");
573		break;
574	default:
575		abort();
576	}
577	n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
578	if (n < 0) {
579		dprintf("res_query failed (%d)\n", n);
580		return (NULL);
581	}
582	if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
583		return (NULL);	/* h_errno was set by gethostanswer() */
584#ifdef SUNSECURITY
585	if (af == AF_INET) {
586	    /*
587	     * turn off search as the name should be absolute,
588	     * 'localhost' should be matched by defnames
589	     */
590	    strncpy(hname2, hp->h_name, MAXDNAME);
591	    hname2[MAXDNAME] = '\0';
592	    old_options = _res.options;
593	    _res.options &= ~RES_DNSRCH;
594	    _res.options |= RES_DEFNAMES;
595	    if (!(rhp = gethostbyname(hname2))) {
596		syslog(LOG_NOTICE|LOG_AUTH,
597		       "gethostbyaddr: No A record for %s (verifying [%s])",
598		       hname2, inet_ntoa(*((struct in_addr *)addr)));
599		_res.options = old_options;
600		h_errno = HOST_NOT_FOUND;
601		return (NULL);
602	    }
603	    _res.options = old_options;
604	    for (haddr = rhp->h_addr_list; *haddr; haddr++)
605		if (!memcmp(*haddr, addr, INADDRSZ))
606			break;
607	    if (!*haddr) {
608		syslog(LOG_NOTICE|LOG_AUTH,
609		       "gethostbyaddr: A record of %s != PTR record [%s]",
610		       hname2, inet_ntoa(*((struct in_addr *)addr)));
611		h_errno = HOST_NOT_FOUND;
612		return (NULL);
613	    }
614	}
615#endif /*SUNSECURITY*/
616	hp->h_addrtype = af;
617	hp->h_length = len;
618	bcopy(addr, host_addr, len);
619	h_addr_ptrs[0] = (char *)host_addr;
620	h_addr_ptrs[1] = NULL;
621	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
622		_map_v4v6_address((char*)host_addr, (char*)host_addr);
623		hp->h_addrtype = AF_INET6;
624		hp->h_length = IN6ADDRSZ;
625	}
626	h_errno = NETDB_SUCCESS;
627	return (hp);
628}
629
630#ifdef RESOLVSORT
631static void
632addrsort(ap, num)
633	char **ap;
634	int num;
635{
636	int i, j;
637	char **p;
638	short aval[MAXADDRS];
639	int needsort = 0;
640
641	p = ap;
642	for (i = 0; i < num; i++, p++) {
643	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
644		if (_res.sort_list[j].addr.s_addr ==
645		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
646			break;
647	    aval[i] = j;
648	    if (needsort == 0 && i > 0 && j < aval[i-1])
649		needsort = i;
650	}
651	if (!needsort)
652	    return;
653
654	while (needsort < num) {
655	    for (j = needsort - 1; j >= 0; j--) {
656		if (aval[j] > aval[j+1]) {
657		    char *hp;
658
659		    i = aval[j];
660		    aval[j] = aval[j+1];
661		    aval[j+1] = i;
662
663		    hp = ap[j];
664		    ap[j] = ap[j+1];
665		    ap[j+1] = hp;
666
667		} else
668		    break;
669	    }
670	    needsort++;
671	}
672}
673#endif
674void
675_sethostdnsent(stayopen)
676	int stayopen;
677{
678	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
679		return;
680	if (stayopen)
681		_res.options |= RES_STAYOPEN | RES_USEVC;
682}
683
684void
685_endhostdnsent()
686{
687	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
688	_res_close();
689}
690