name6.c revision 55163
1/*
2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
3 * 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. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/lib/libc/net/name6.c 55163 1999-12-28 02:37:14Z shin $
30 */
31/* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
32/*
33 *	Atsushi Onoe <onoe@sm.sony.co.jp>
34 */
35
36/*
37 * TODO for thread safe
38 *	use mutex for _hostconf, _hostconf_init.
39 *	rewrite resolvers to be thread safe
40 */
41
42#include <sys/param.h>
43#include <sys/socket.h>
44#include <sys/time.h>
45#include <netinet/in.h>
46
47#include <arpa/inet.h>
48#include <arpa/nameser.h>
49
50#include <netdb.h>
51#include <resolv.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
57#ifndef _PATH_HOSTS
58#define	_PATH_HOSTS	"/etc/hosts"
59#endif
60
61#ifndef MAXALIASES
62#define	MAXALIASES	10
63#endif
64#ifndef	MAXADDRS
65#define	MAXADDRS	20
66#endif
67#ifndef MAXDNAME
68#define	MAXDNAME	1025
69#endif
70
71#ifdef INET6
72#define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
73					    sizeof(struct in_addr))
74#else
75#define	ADDRLEN(af)	sizeof(struct in_addr)
76#endif
77
78#define	MAPADDR(ab, ina) \
79do {									\
80	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
81	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
82	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
83} while (0)
84#define	MAPADDRENABLED(flags) \
85	(((flags) & AI_V4MAPPED) || \
86	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
87
88union inx_addr {
89	struct in_addr	in_addr;
90#ifdef INET6
91	struct in6_addr	in6_addr;
92#endif
93	struct {
94		u_char	mau_zero[10];
95		u_char	mau_one[2];
96		struct in_addr mau_inaddr;
97	}		map_addr_un;
98#define	map_zero	map_addr_un.mau_zero
99#define	map_one		map_addr_un.mau_one
100#define	map_inaddr	map_addr_un.mau_inaddr
101};
102
103static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
104static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
105static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
106#ifdef INET6
107static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
108#endif
109static struct	 hostent *_hpsort(struct hostent *hp);
110static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
111static char	*_hgetword(char **pp);
112static int	 _mapped_addr_enabled(void);
113
114static FILE	*_files_open(int *errp);
115static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
116static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
117static void	 _files_shent(int stayopen);
118static void	 _files_ehent(void);
119static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
120static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
121static void	 _dns_shent(int stayopen);
122static void	 _dns_ehent(void);
123#ifdef ICMPNL
124static struct	 hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125#endif /* ICMPNL */
126
127/*
128 * Select order host function.
129 */
130#define	MAXHOSTCONF	4
131
132#ifndef HOSTCONF
133#  define	HOSTCONF	"/etc/host.conf"
134#endif /* !HOSTCONF */
135
136struct _hostconf {
137	struct hostent *(*byname)(const char *name, int af, int *errp);
138	struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
139};
140
141/* default order */
142static struct _hostconf _hostconf[MAXHOSTCONF] = {
143	{ _dns_ghbyname,	_dns_ghbyaddr },
144	{ _files_ghbyname,	_files_ghbyaddr },
145#ifdef ICMPNL
146	{ NULL,			_icmp_ghbyaddr },
147#endif /* ICMPNL */
148};
149
150static int	_hostconf_init_done;
151static void	_hostconf_init(void);
152
153/*
154 * Initialize hostconf structure.
155 */
156
157static void
158_hostconf_init(void)
159{
160	FILE *fp;
161	int n;
162	char *p, *line;
163	char buf[BUFSIZ];
164
165	_hostconf_init_done = 1;
166	n = 0;
167	p = HOSTCONF;
168	if ((fp = fopen(p, "r")) == NULL)
169		return;
170	while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
171		line = buf;
172		if ((p = _hgetword(&line)) == NULL)
173			continue;
174		do {
175			if (strcmp(p, "hosts") == 0
176			||  strcmp(p, "local") == 0
177			||  strcmp(p, "file") == 0
178			||  strcmp(p, "files") == 0) {
179				_hostconf[n].byname = _files_ghbyname;
180				_hostconf[n].byaddr = _files_ghbyaddr;
181				n++;
182			}
183			else if (strcmp(p, "dns") == 0
184			     ||  strcmp(p, "bind") == 0) {
185				_hostconf[n].byname = _dns_ghbyname;
186				_hostconf[n].byaddr = _dns_ghbyaddr;
187				n++;
188			}
189#ifdef ICMPNL
190			else if (strcmp(p, "icmp") == 0) {
191				_hostconf[n].byname = NULL;
192				_hostconf[n].byaddr = _icmp_ghbyaddr;
193				n++;
194			}
195#endif /* ICMPNL */
196		} while ((p = _hgetword(&line)) != NULL);
197	}
198	fclose(fp);
199	if (n < 0) {
200		/* no keyword found. do not change default configuration */
201		return;
202	}
203	for (; n < MAXHOSTCONF; n++) {
204		_hostconf[n].byname = NULL;
205		_hostconf[n].byaddr = NULL;
206	}
207}
208
209/*
210 * Check if kernel supports mapped address.
211 *	implementation dependent
212 */
213#ifdef __KAME__
214#include <sys/sysctl.h>
215#endif /* __KAME__ */
216
217static int
218_mapped_addr_enabled(void)
219{
220	/* implementation dependent check */
221#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
222	int mib[4];
223	size_t len;
224	int val;
225
226	mib[0] = CTL_NET;
227	mib[1] = PF_INET6;
228	mib[2] = IPPROTO_IPV6;
229	mib[3] = IPV6CTL_MAPPED_ADDR;
230	len = sizeof(val);
231	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
232		return 1;
233#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
234	return 0;
235}
236
237/*
238 * Functions defined in RFC2553
239 *	getipnodebyname, getipnodebyadr, freehostent
240 */
241
242static struct hostent *
243_ghbyname(const char *name, int af, int flags, int *errp)
244{
245	struct hostent *hp;
246	int i;
247
248	if (flags & AI_ADDRCONFIG) {
249		int s;
250
251		if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
252			return NULL;
253		/*
254		 * TODO:
255		 * Note that implementation dependent test for address
256		 * configuration should be done everytime called
257		 * (or apropriate interval),
258		 * because addresses will be dynamically assigned or deleted.
259		 */
260		close(s);
261	}
262
263	for (i = 0; i < MAXHOSTCONF; i++) {
264		if (_hostconf[i].byname
265		&&  (hp = (*_hostconf[i].byname)(name, af, errp))
266		    != NULL)
267			return hp;
268	}
269
270	return NULL;
271}
272
273struct hostent *
274getipnodebyname(const char *name, int af, int flags, int *errp)
275{
276	struct hostent *hp;
277	union inx_addr addrbuf;
278
279	if (af != AF_INET
280#ifdef INET6
281	    && af != AF_INET6
282#endif
283		)
284	{
285		*errp = NO_RECOVERY;
286		return NULL;
287	}
288
289#ifdef INET6
290	/* special case for literal address */
291	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
292		if (af != AF_INET6) {
293			*errp = HOST_NOT_FOUND;
294			return NULL;
295		}
296		return _hpaddr(af, name, &addrbuf, errp);
297	}
298#endif
299	if (inet_pton(AF_INET, name, &addrbuf) == 1) {
300		if (af != AF_INET) {
301			if (MAPADDRENABLED(flags)) {
302				MAPADDR(&addrbuf, &addrbuf.in_addr);
303			} else {
304				*errp = HOST_NOT_FOUND;
305				return NULL;
306			}
307		}
308		return _hpaddr(af, name, &addrbuf, errp);
309	}
310
311	if (!_hostconf_init_done)
312		_hostconf_init();
313
314	*errp = HOST_NOT_FOUND;
315	hp = _ghbyname(name, af, flags, errp);
316
317#ifdef INET6
318	if (af == AF_INET6
319	&&  ((flags & AI_ALL) || hp == NULL)
320	&&  (MAPADDRENABLED(flags))) {
321		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
322		if (hp == NULL)
323			hp = _hpmapv6(hp2, errp);
324		else {
325			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
326				freehostent(hp2);
327				hp2 = NULL;
328			}
329			hp = _hpmerge(hp, hp2, errp);
330		}
331	}
332#endif
333	return _hpsort(hp);
334}
335
336struct hostent *
337getipnodebyaddr(const void *src, size_t len, int af, int *errp)
338{
339	struct hostent *hp;
340	int i;
341#ifdef INET6
342	struct in6_addr addrbuf;
343#else
344	struct in_addr addrbuf;
345#endif
346
347	*errp = HOST_NOT_FOUND;
348
349	switch (af) {
350	case AF_INET:
351		if (len != sizeof(struct in_addr)) {
352			*errp = NO_RECOVERY;
353			return NULL;
354		}
355		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
356			memcpy(&addrbuf, src, len);
357			src = &addrbuf;
358		}
359		if (((struct in_addr *)src)->s_addr == 0)
360			return NULL;
361		break;
362#ifdef INET6
363	case AF_INET6:
364		if (len != sizeof(struct in6_addr)) {
365			*errp = NO_RECOVERY;
366			return NULL;
367		}
368		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
369			memcpy(&addrbuf, src, len);
370			src = &addrbuf;
371		}
372		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
373		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
374			src = (char *)src +
375			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
376			af = AF_INET;
377			len = sizeof(struct in_addr);
378		}
379		break;
380#endif
381	default:
382		*errp = NO_RECOVERY;
383		return NULL;
384	}
385
386	if (!_hostconf_init_done)
387		_hostconf_init();
388	for (i = 0; i < MAXHOSTCONF; i++) {
389		if (_hostconf[i].byaddr
390		&&  (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
391			return hp;
392	}
393
394	return NULL;
395}
396
397void
398freehostent(struct hostent *ptr)
399{
400	free(ptr);
401}
402
403#if 0
404
405/* XXX: should be deprecated */
406struct hostent *
407getnodebyname(const char *name, int af, int flags)
408{
409	return getipnodebyname(name, af, flags, &h_errno);
410}
411
412#ifdef __warn_references
413__warn_references(getnodebyname,
414	"warning: getnodebyname() deprecated, "
415	"should use getaddrinfo() or getipnodebyname()");
416#endif
417
418struct hostent *
419getnodebyaddr(const void *src, size_t len, int af)
420{
421	return getipnodebyaddr(src, len, af, &h_errno);
422}
423
424#ifdef __warn_references
425__warn_references(getnodebyaddr,
426	"warning: getnodebyaddr() deprecated, "
427	"should use getnameinfo() or getipnodebyaddr()");
428#endif
429
430#endif
431
432/*
433 * Private utility functions
434 */
435
436/*
437 * _hpcopy: allocate and copy hostent structure
438 */
439static struct hostent *
440_hpcopy(struct hostent *hp, int *errp)
441{
442	struct hostent *nhp;
443	char *cp, **pp;
444	int size, addrsize;
445	int nalias = 0, naddr = 0;
446	int al_off;
447	int i;
448
449	if (hp == NULL)
450		return hp;
451
452	/* count size to be allocated */
453	size = sizeof(struct hostent);
454	if (hp->h_name != NULL && *hp->h_name != '\0')
455		size += strlen(hp->h_name) + 1;
456	if ((pp = hp->h_aliases) != NULL) {
457		for (i = 0; *pp != NULL; i++, pp++) {
458			if (**pp != '\0') {
459				size += strlen(*pp) + 1;
460				nalias++;
461			}
462		}
463	}
464	/* adjust alignment */
465	size = ALIGN(size);
466	al_off = size;
467	size += sizeof(char *) * (nalias + 1);
468	addrsize = ALIGN(hp->h_length);
469	if ((pp = hp->h_addr_list) != NULL) {
470		while (*pp++ != NULL)
471			naddr++;
472	}
473	size += addrsize * naddr;
474	size += sizeof(char *) * (naddr + 1);
475
476	/* copy */
477	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
478		*errp = TRY_AGAIN;
479		return NULL;
480	}
481	cp = (char *)&nhp[1];
482	if (hp->h_name != NULL && *hp->h_name != '\0') {
483		nhp->h_name = cp;
484		strcpy(cp, hp->h_name);
485		cp += strlen(cp) + 1;
486	} else
487		nhp->h_name = NULL;
488	nhp->h_aliases = (char **)((char *)nhp + al_off);
489	if ((pp = hp->h_aliases) != NULL) {
490		for (i = 0; *pp != NULL; pp++) {
491			if (**pp != '\0') {
492				nhp->h_aliases[i++] = cp;
493				strcpy(cp, *pp);
494				cp += strlen(cp) + 1;
495			}
496		}
497	}
498	nhp->h_aliases[nalias] = NULL;
499	cp = (char *)&nhp->h_aliases[nalias + 1];
500	nhp->h_addrtype = hp->h_addrtype;
501	nhp->h_length = hp->h_length;
502	nhp->h_addr_list = (char **)cp;
503	if ((pp = hp->h_addr_list) != NULL) {
504		cp = (char *)&nhp->h_addr_list[naddr + 1];
505		for (i = 0; *pp != NULL; pp++) {
506			nhp->h_addr_list[i++] = cp;
507			memcpy(cp, *pp, hp->h_length);
508			cp += addrsize;
509		}
510	}
511	nhp->h_addr_list[naddr] = NULL;
512	return nhp;
513}
514
515/*
516 * _hpaddr: construct hostent structure with one address
517 */
518static struct hostent *
519_hpaddr(int af, const char *name, void *addr, int *errp)
520{
521	struct hostent *hp, hpbuf;
522	char *addrs[2];
523
524	hp = &hpbuf;
525	hp->h_name = (char *)name;
526	hp->h_aliases = NULL;
527	hp->h_addrtype = af;
528	hp->h_length = ADDRLEN(af);
529	hp->h_addr_list = addrs;
530	addrs[0] = (char *)addr;
531	addrs[1] = NULL;
532	return _hpcopy(hp, errp);
533}
534
535/*
536 * _hpmerge: merge 2 hostent structure, arguments will be freed
537 */
538static struct hostent *
539_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
540{
541	int i, j;
542	int naddr, nalias;
543	char **pp;
544	struct hostent *hp, hpbuf;
545	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
546	union inx_addr addrbuf[MAXADDRS];
547
548	if (hp1 == NULL)
549		return hp2;
550	if (hp2 == NULL)
551		return hp1;
552
553#define	HP(i)	(i == 1 ? hp1 : hp2)
554	hp = &hpbuf;
555	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
556	hp->h_aliases = aliases;
557	nalias = 0;
558	for (i = 1; i <= 2; i++) {
559		if ((pp = HP(i)->h_aliases) == NULL)
560			continue;
561		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
562			/* check duplicates */
563			for (j = 0; j < nalias; j++)
564				if (strcasecmp(*pp, aliases[j]) == 0)
565					break;
566			if (j == nalias)
567				aliases[nalias++] = *pp;
568		}
569	}
570	aliases[nalias] = NULL;
571#ifdef INET6
572	if (hp1->h_length != hp2->h_length) {
573		hp->h_addrtype = AF_INET6;
574		hp->h_length = sizeof(struct in6_addr);
575	} else {
576#endif
577		hp->h_addrtype = hp1->h_addrtype;
578		hp->h_length = hp1->h_length;
579#ifdef INET6
580	}
581#endif
582	hp->h_addr_list = addrs;
583	naddr = 0;
584	for (i = 1; i <= 2; i++) {
585		if ((pp = HP(i)->h_addr_list) == NULL)
586			continue;
587		if (HP(i)->h_length == hp->h_length) {
588			while (naddr < MAXADDRS && *pp != NULL)
589				addrs[naddr++] = *pp++;
590		} else {
591			/* copy IPv4 addr as mapped IPv6 addr */
592			while (naddr < MAXADDRS && *pp != NULL) {
593				MAPADDR(&addrbuf[naddr], *pp++);
594				addrs[naddr] = (char *)&addrbuf[naddr];
595				naddr++;
596			}
597		}
598	}
599	addrs[naddr] = NULL;
600	hp = _hpcopy(hp, errp);
601	freehostent(hp1);
602	freehostent(hp2);
603	return hp;
604}
605
606/*
607 * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
608 */
609#ifdef INET6
610static struct hostent *
611_hpmapv6(struct hostent *hp, int *errp)
612{
613	struct hostent *hp6;
614
615	if (hp == NULL)
616		return NULL;
617	if (hp->h_addrtype == AF_INET6)
618		return hp;
619
620	/* make dummy hostent to convert IPv6 address */
621	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
622		*errp = TRY_AGAIN;
623		return NULL;
624	}
625	hp6->h_name = NULL;
626	hp6->h_aliases = NULL;
627	hp6->h_addrtype = AF_INET6;
628	hp6->h_length = sizeof(struct in6_addr);
629	hp6->h_addr_list = NULL;
630	return _hpmerge(hp6, hp, errp);
631}
632#endif
633
634/*
635 * _hpsort: sort address by sortlist
636 */
637static struct hostent *
638_hpsort(struct hostent *hp)
639{
640	int i, j, n;
641	u_char *ap, *sp, *mp, **pp;
642	char t;
643	char order[MAXADDRS];
644	int nsort = _res.nsort;
645
646	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
647		return hp;
648	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
649		for (j = 0; j < nsort; j++) {
650#ifdef INET6
651			if (_res_ext.sort_list[j].af != hp->h_addrtype)
652				continue;
653			sp = (u_char *)&_res_ext.sort_list[j].addr;
654			mp = (u_char *)&_res_ext.sort_list[j].mask;
655#else
656			sp = (u_char *)&_res.sort_list[j].addr;
657			mp = (u_char *)&_res.sort_list[j].mask;
658#endif
659			for (n = 0; n < hp->h_length; n++) {
660				if ((ap[n] & mp[n]) != sp[n])
661					break;
662			}
663			if (n == hp->h_length)
664				break;
665		}
666		order[i] = j;
667	}
668	n = i;
669	pp = (u_char **)hp->h_addr_list;
670	for (i = 0; i < n - 1; i++) {
671		for (j = i + 1; j < n; j++) {
672			if (order[i] > order[j]) {
673				ap = pp[i];
674				pp[i] = pp[j];
675				pp[j] = ap;
676				t = order[i];
677				order[i] = order[j];
678				order[j] = t;
679			}
680		}
681	}
682	return hp;
683}
684
685static char *
686_hgetword(char **pp)
687{
688	char c, *p, *ret;
689	const char *sp;
690	static const char sep[] = "# \t\n";
691
692	ret = NULL;
693	for (p = *pp; (c = *p) != '\0'; p++) {
694		for (sp = sep; *sp != '\0'; sp++) {
695			if (c == *sp)
696				break;
697		}
698		if (c == '#')
699			p[1] = '\0';	/* ignore rest of line */
700		if (ret == NULL) {
701			if (*sp == '\0')
702				ret = p;
703		} else {
704			if (*sp != '\0') {
705				*p++ = '\0';
706				break;
707			}
708		}
709	}
710	*pp = p;
711	if (ret == NULL || *ret == '\0')
712		return NULL;
713	return ret;
714}
715
716/*
717 * FILES (/etc/hosts)
718 */
719
720static FILE *
721_files_open(int *errp)
722{
723	FILE *fp;
724	fp = fopen(_PATH_HOSTS, "r");
725	if (fp == NULL)
726		*errp = NO_RECOVERY;
727	return fp;
728}
729
730static struct hostent *
731_files_ghbyname(const char *name, int af, int *errp)
732{
733	int match, nalias;
734	char *p, *line, *addrstr, *cname;
735	FILE *fp;
736	struct hostent *rethp, *hp, hpbuf;
737	char *aliases[MAXALIASES + 1], *addrs[2];
738	union inx_addr addrbuf;
739	char buf[BUFSIZ];
740
741	if ((fp = _files_open(errp)) == NULL)
742		return NULL;
743	rethp = hp = NULL;
744
745	while (fgets(buf, sizeof(buf), fp)) {
746		line = buf;
747		if ((addrstr = _hgetword(&line)) == NULL
748		||  (cname = _hgetword(&line)) == NULL)
749			continue;
750		match = (strcasecmp(cname, name) == 0);
751		nalias = 0;
752		while ((p = _hgetword(&line)) != NULL) {
753			if (!match)
754				match = (strcasecmp(p, name) == 0);
755			if (nalias < MAXALIASES)
756				aliases[nalias++] = p;
757		}
758		if (!match)
759			continue;
760		if (inet_pton(af, addrstr, &addrbuf) != 1) {
761			*errp = NO_DATA;	/* name found */
762			continue;
763		}
764		hp = &hpbuf;
765		hp->h_name = cname;
766		hp->h_aliases = aliases;
767		aliases[nalias] = NULL;
768		hp->h_addrtype = af;
769		hp->h_length = ADDRLEN(af);
770		hp->h_addr_list = addrs;
771		addrs[0] = (char *)&addrbuf;
772		addrs[1] = NULL;
773		hp = _hpcopy(hp, errp);
774		rethp = _hpmerge(rethp, hp, errp);
775	}
776	fclose(fp);
777	return rethp;
778}
779
780static struct hostent *
781_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
782{
783	int nalias;
784	char *p, *line;
785	FILE *fp;
786	struct hostent *hp, hpbuf;
787	char *aliases[MAXALIASES + 1], *addrs[2];
788	union inx_addr addrbuf;
789	char buf[BUFSIZ];
790
791	if ((fp = _files_open(errp)) == NULL)
792		return NULL;
793	hp = NULL;
794	while (fgets(buf, sizeof(buf), fp)) {
795		line = buf;
796		if ((p = _hgetword(&line)) == NULL
797		||  inet_pton(af, p, &addrbuf) != 1
798		||  memcmp(addr, &addrbuf, addrlen) != 0
799		||  (p = _hgetword(&line)) == NULL)
800			continue;
801		hp = &hpbuf;
802		hp->h_name = p;
803		hp->h_aliases = aliases;
804		nalias = 0;
805		while ((p = _hgetword(&line)) != NULL) {
806			if (nalias < MAXALIASES)
807				aliases[nalias++] = p;
808		}
809		aliases[nalias] = NULL;
810		hp->h_addrtype = af;
811		hp->h_length = addrlen;
812		hp->h_addr_list = addrs;
813		addrs[0] = (char *)&addrbuf;
814		addrs[1] = NULL;
815		hp = _hpcopy(hp, errp);
816		break;
817	}
818	fclose(fp);
819	return hp;
820}
821
822#ifdef DEBUG
823#define	DNS_ASSERT(X)	if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
824#else
825#define	DNS_ASSERT(X)	if (!(X)) { goto badanswer; }
826#endif
827
828static struct hostent *
829_dns_ghbyname(const char *name, int af, int *errp)
830{
831	int n;
832	u_char answer[BUFSIZ];
833	char tbuf[MAXDNAME+1];
834	HEADER *hp;
835	u_char *cp, *eom;
836	int qtype;
837	int type, class, ancount, qdcount;
838	u_long ttl;
839	char hostbuf[BUFSIZ];
840	char *bp;
841	char *alist[MAXALIASES];
842	char *hlist[MAXADDRS];
843	struct hostent hbuf;
844	int buflen;
845	int na, nh;
846
847	if ((_res.options & RES_INIT) == 0) {
848		if (res_init() < 0) {
849			*errp = h_errno;
850			return NULL;
851		}
852	}
853	hbuf.h_aliases = alist;
854	hbuf.h_addrtype = af;
855	hbuf.h_length = ADDRLEN(af);
856	hbuf.h_addr_list = hlist;
857	na = nh = 0;
858
859#ifdef INET6
860	qtype = (af == AF_INET6 ? T_AAAA : T_A);
861#else
862	qtype = T_A;
863#endif
864	n = res_search(name, C_IN, qtype, answer, sizeof(answer));
865	if (n < 0) {
866		*errp = h_errno;
867		return NULL;
868	}
869	hp = (HEADER *)answer;
870	eom = answer + n;
871	ancount = ntohs(hp->ancount);
872	qdcount = ntohs(hp->qdcount);
873	DNS_ASSERT(qdcount == 1);
874	cp = answer + sizeof(HEADER);
875	bp = hostbuf;
876	buflen = sizeof(hostbuf);
877
878	n = dn_expand(answer, eom, cp, bp, buflen);
879	DNS_ASSERT(n >= 0);
880	cp += n + QFIXEDSZ;
881	hbuf.h_name = bp;
882	n = strlen(bp) + 1;
883	bp += n;
884	buflen -= n;
885	while (ancount-- > 0 && cp < eom) {
886		n = dn_expand(answer, eom, cp, bp, buflen);
887		DNS_ASSERT(n >= 0);
888		cp += n;		/* name */
889		type = _getshort(cp);
890		cp += 2;		/* type */
891		class = _getshort(cp);
892		cp += 2;		/* class */
893		ttl = _getlong(cp);
894		cp += 4;		/* ttl */
895		n = _getshort(cp);
896		cp += 2;		/* len */
897		DNS_ASSERT(class == C_IN);
898		switch (type) {
899		case T_CNAME:
900			if (na >= MAXALIASES-1) {
901				cp += n;
902				break;
903			}
904			n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
905			DNS_ASSERT(n >= 0);
906			cp += n;
907			/* alias */
908			alist[na++] = bp;
909			n = strlen(bp) + 1;
910			bp += n;
911			buflen -= n;
912			/* canon */
913			n = strlen(tbuf) + 1;
914			DNS_ASSERT(n < buflen);
915			strcpy(bp, tbuf);
916			hbuf.h_name = bp;
917			bp += n;
918			buflen -= n;
919			break;
920		case T_A:
921#ifdef INET6
922		case T_AAAA:
923#endif
924			DNS_ASSERT(type == qtype);
925			bp = (char *)ALIGN(bp);
926			DNS_ASSERT(n == hbuf.h_length);
927			DNS_ASSERT(n < buflen);
928			if (nh < MAXADDRS-1) {
929				hlist[nh++] = bp;
930				memcpy(bp, cp, n);
931				bp += n;
932				buflen -= n;
933			}
934			cp += n;
935			break;
936		default:
937			DNS_ASSERT(0);
938			cp += n;
939			break;
940		}
941	}
942	if (nh == 0) {
943  badanswer:
944		*errp = NO_RECOVERY;
945		return NULL;
946	}
947	alist[na] = NULL;
948	hlist[nh] = NULL;
949	return _hpcopy(&hbuf, errp);
950}
951
952static struct hostent *
953_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
954{
955	int n;
956	u_char answer[BUFSIZ];
957	HEADER *hp;
958	u_char c, *cp, *eom;
959	int type, class, ancount, qdcount;
960	u_long ttl;
961	char hostbuf[BUFSIZ];
962	char *bp;
963	char *alist[MAXALIASES];
964	char *hlist[2];
965	struct hostent hbuf;
966	int buflen;
967	int na;
968#ifdef INET6
969	static const char hex[] = "0123456789abcdef";
970#endif
971
972#ifdef INET6
973	/* XXX */
974	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
975		return NULL;
976#endif
977
978	if ((_res.options & RES_INIT) == 0) {
979		if (res_init() < 0) {
980			*errp = h_errno;
981			return NULL;
982		}
983	}
984	hbuf.h_name = NULL;
985	hbuf.h_aliases = alist;
986	hbuf.h_addrtype = af;
987	hbuf.h_length = addrlen;
988	hbuf.h_addr_list = hlist;
989	hlist[0] = (char *)addr;
990	hlist[1] = NULL;
991	na = 0;
992
993	n = 0;
994	bp = hostbuf;
995	cp = (u_char *)addr+addrlen-1;
996	switch (af) {
997#ifdef INET6
998	case AF_INET6:
999		for (; n < addrlen; n++, cp--) {
1000			c = *cp;
1001			*bp++ = hex[c & 0xf];
1002			*bp++ = '.';
1003			*bp++ = hex[c >> 4];
1004			*bp++ = '.';
1005		}
1006		strcpy(bp, "ip6.int");
1007		break;
1008#endif
1009	default:
1010		for (; n < addrlen; n++, cp--) {
1011			c = *cp;
1012			if (c >= 100)
1013				*bp++ = '0' + c / 100;
1014			if (c >= 10)
1015				*bp++ = '0' + (c % 100) / 10;
1016			*bp++ = '0' + c % 10;
1017			*bp++ = '.';
1018		}
1019		strcpy(bp, "in-addr.arpa");
1020		break;
1021	}
1022
1023	n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
1024	if (n < 0) {
1025		*errp = h_errno;
1026		return NULL;
1027	}
1028	hp = (HEADER *)answer;
1029	eom = answer + n;
1030	ancount = ntohs(hp->ancount);
1031	qdcount = ntohs(hp->qdcount);
1032	DNS_ASSERT(qdcount == 1);
1033	cp = answer + sizeof(HEADER);
1034	bp = hostbuf;
1035	buflen = sizeof(hostbuf);
1036
1037	n = dn_expand(answer, eom, cp, bp, buflen);
1038	DNS_ASSERT(n >= 0);
1039	cp += n + QFIXEDSZ;
1040	while (ancount-- > 0 && cp < eom) {
1041		n = dn_expand(answer, eom, cp, bp, buflen);
1042		DNS_ASSERT(n >= 0);
1043		cp += n;		/* name */
1044		type = _getshort(cp);
1045		cp += 2;		/* type */
1046		class = _getshort(cp);
1047		cp += 2;		/* class */
1048		ttl = _getlong(cp);
1049		cp += 4;		/* ttl */
1050		n = _getshort(cp);
1051		cp += 2;		/* len */
1052		DNS_ASSERT(class == C_IN);
1053		switch (type) {
1054		case T_PTR:
1055			n = dn_expand(answer, eom, cp, bp, buflen);
1056			DNS_ASSERT(n >= 0);
1057			cp += n;
1058			if (na >= MAXALIASES-1)
1059				break;
1060			if (hbuf.h_name == NULL)
1061				hbuf.h_name = bp;
1062			else
1063				alist[na++] = bp;
1064			n = strlen(bp) + 1;
1065			bp += n;
1066			buflen -= n;
1067			break;
1068		case T_CNAME:
1069			cp += n;
1070			break;
1071		default:
1072  badanswer:
1073			*errp = NO_RECOVERY;
1074			return NULL;
1075		}
1076	}
1077	if (hbuf.h_name == NULL) {
1078		*errp = h_errno;
1079		return NULL;
1080	}
1081	alist[na] = NULL;
1082	return _hpcopy(&hbuf, errp);
1083}
1084
1085#ifdef ICMPNL
1086
1087/*
1088 * experimental:
1089 *	draft-ietf-ipngwg-icmp-namelookups-02.txt
1090 *	ifindex is assumed to be encoded in addr.
1091 */
1092#include <sys/uio.h>
1093#include <netinet/ip6.h>
1094#include <netinet/icmp6.h>
1095
1096struct _icmp_host_cache {
1097	struct _icmp_host_cache *hc_next;
1098	int hc_ifindex;
1099	struct in6_addr hc_addr;
1100	char *hc_name;
1101};
1102
1103static char *
1104_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1105{
1106	int s;
1107	struct icmp6_filter filter;
1108	struct msghdr msg;
1109	struct cmsghdr *cmsg;
1110	struct in6_pktinfo *pkt;
1111	char cbuf[256];
1112	char buf[1024];
1113	int cc;
1114	struct icmp6_fqdn_query *fq;
1115	struct icmp6_fqdn_reply *fr;
1116	struct _icmp_host_cache *hc;
1117	struct sockaddr_in6 sin6;
1118	struct iovec iov;
1119	fd_set s_fds, fds;
1120	struct timeval tout;
1121	int len;
1122	char *name;
1123	static int pid;
1124	static struct _icmp_host_cache *hc_head;
1125
1126	for (hc = hc_head; hc; hc = hc->hc_next) {
1127		if (hc->hc_ifindex == ifindex
1128		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1129			return hc->hc_name;
1130	}
1131
1132	if (pid == 0)
1133		pid = getpid();
1134
1135	ICMP6_FILTER_SETBLOCKALL(&filter);
1136	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1137
1138	FD_ZERO(&s_fds);
1139	tout.tv_sec = 0;
1140	tout.tv_usec = 200000;	/*XXX: 200ms*/
1141
1142	fq = (struct icmp6_fqdn_query *)buf;
1143	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1144	fq->icmp6_fqdn_code = 0;
1145	fq->icmp6_fqdn_cksum = 0;
1146	fq->icmp6_fqdn_id = (u_short)pid;
1147	fq->icmp6_fqdn_unused = 0;
1148	fq->icmp6_fqdn_cookie[0] = 0;
1149	fq->icmp6_fqdn_cookie[1] = 0;
1150
1151	memset(&sin6, 0, sizeof(sin6));
1152	sin6.sin6_family = AF_INET6;
1153	sin6.sin6_addr = *addr;
1154
1155	memset(&msg, 0, sizeof(msg));
1156	msg.msg_name = (caddr_t)&sin6;
1157	msg.msg_namelen = sizeof(sin6);
1158	msg.msg_iov = &iov;
1159	msg.msg_iovlen = 1;
1160	msg.msg_control = NULL;
1161	msg.msg_controllen = 0;
1162	iov.iov_base = (caddr_t)buf;
1163	iov.iov_len = sizeof(struct icmp6_fqdn_query);
1164
1165	if (ifindex) {
1166		msg.msg_control = cbuf;
1167		msg.msg_controllen = sizeof(cbuf);
1168		cmsg = CMSG_FIRSTHDR(&msg);
1169		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1170		cmsg->cmsg_level = IPPROTO_IPV6;
1171		cmsg->cmsg_type = IPV6_PKTINFO;
1172		pkt = (struct in6_pktinfo *)&cmsg[1];
1173		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1174		pkt->ipi6_ifindex = ifindex;
1175		cmsg = CMSG_NXTHDR(&msg, cmsg);
1176		msg.msg_controllen = (char *)cmsg - cbuf;
1177	}
1178
1179	if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1180		return NULL;
1181	(void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1182			 (char *)&filter, sizeof(filter));
1183	cc = sendmsg(s, &msg, 0);
1184	if (cc < 0) {
1185		close(s);
1186		return NULL;
1187	}
1188	FD_SET(s, &s_fds);
1189	for (;;) {
1190		fds = s_fds;
1191		if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1192			close(s);
1193			return NULL;
1194		}
1195		len = sizeof(sin6);
1196		cc = recvfrom(s, buf, sizeof(buf), 0,
1197			      (struct sockaddr *)&sin6, &len);
1198		if (cc <= 0) {
1199			close(s);
1200			return NULL;
1201		}
1202		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1203			continue;
1204		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1205			continue;
1206		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1207		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1208			break;
1209	}
1210	close(s);
1211	if (fr->icmp6_fqdn_cookie[1] != 0) {
1212		/* rfc1788 type */
1213		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1214		len = (buf + cc) - name;
1215	} else {
1216		len = fr->icmp6_fqdn_namelen;
1217		name = fr->icmp6_fqdn_name;
1218	}
1219	if (len <= 0)
1220		return NULL;
1221	name[len] = 0;
1222
1223	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1224		return NULL;
1225	/* XXX: limit number of cached entries */
1226	hc->hc_ifindex = ifindex;
1227	hc->hc_addr = *addr;
1228	hc->hc_name = strdup(name);
1229	hc->hc_next = hc_head;
1230	hc_head = hc;
1231	return hc->hc_name;
1232}
1233
1234static struct hostent *
1235_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1236{
1237	char *hname;
1238	int ifindex;
1239	struct in6_addr addr6;
1240
1241	if (af != AF_INET6) {
1242		/*
1243		 * Note: rfc1788 defines Who Are You for IPv4,
1244		 * but no one implements it.
1245		 */
1246		return NULL;
1247	}
1248
1249	memcpy(&addr6, addr, addrlen);
1250	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1251	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1252
1253	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1254		return NULL;	/*XXX*/
1255
1256	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1257		return NULL;
1258	return _hpaddr(af, hname, &addr6, errp);
1259}
1260#endif /* ICMPNL */
1261