gethostnamadr.c revision 145602
1/*-
2 * Copyright (c) 1994, Garrett Wollman
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/lib/libc/net/gethostnamadr.c 145602 2005-04-27 19:12:57Z ume $");
28
29#include "namespace.h"
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <ctype.h>
37#include <errno.h>
38#include <string.h>
39#include <stdarg.h>
40#include <nsswitch.h>
41#include <arpa/nameser.h>		/* XXX hack for _res */
42#include <resolv.h>			/* XXX hack for _res */
43#include "un-namespace.h"
44#include "netdb_private.h"
45
46extern int _ht_gethostbyname(void *, void *, va_list);
47extern int _dns_gethostbyname(void *, void *, va_list);
48extern int _nis_gethostbyname(void *, void *, va_list);
49extern int _ht_gethostbyaddr(void *, void *, va_list);
50extern int _dns_gethostbyaddr(void *, void *, va_list);
51extern int _nis_gethostbyaddr(void *, void *, va_list);
52extern const char *_res_hostalias(const char *, char *, size_t);
53
54static struct hostent *gethostbyname_internal(const char *, int);
55
56/* Host lookup order if nsswitch.conf is broken or nonexistant */
57static const ns_src default_src[] = {
58	{ NSSRC_FILES, NS_SUCCESS },
59	{ NSSRC_DNS, NS_SUCCESS },
60	{ 0 }
61};
62
63struct hostent *
64gethostbyname(const char *name)
65{
66	struct hostent *hp;
67
68	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
69		h_errno = NETDB_INTERNAL;
70		return NULL;
71	}
72	if (_res.options & RES_USE_INET6) {
73		hp = gethostbyname_internal(name, AF_INET6);
74		if (hp)
75			return hp;
76	}
77	return gethostbyname_internal(name, AF_INET);
78}
79
80struct hostent *
81gethostbyname2(const char *name, int af)
82{
83	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
84		h_errno = NETDB_INTERNAL;
85		return NULL;
86	}
87	return gethostbyname_internal(name, af);
88}
89
90static struct hostent *
91gethostbyname_internal(const char *name, int af)
92{
93	const char *cp;
94	char *bp, *ep;
95	struct hostent *hp = 0;
96	int size, rval;
97	char abuf[MAXDNAME];
98
99	static struct hostent host;
100	static char *h_addr_ptrs[2];
101	static char *host_aliases[1];
102	static char hostbuf[MAXDNAME + IN6ADDRSZ + sizeof(uint32_t)];
103	static uint32_t host_addr[4];	/* IPv4 or IPv6 */
104	static const ns_dtab dtab[] = {
105		NS_FILES_CB(_ht_gethostbyname, NULL)
106		{ NSSRC_DNS, _dns_gethostbyname, NULL },
107		NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
108		{ 0 }
109	};
110
111	switch (af) {
112	case AF_INET:
113		size = INADDRSZ;
114		break;
115	case AF_INET6:
116		size = IN6ADDRSZ;
117		break;
118	default:
119		h_errno = NETDB_INTERNAL;
120		errno = EAFNOSUPPORT;
121		return NULL;
122	}
123
124	host.h_addrtype = af;
125	host.h_length = size;
126
127	/*
128	 * if there aren't any dots, it could be a user-level alias.
129	 * this is also done in res_query() since we are not the only
130	 * function that looks up host names.
131	 */
132	if (!strchr(name, '.') &&
133	    (cp = _res_hostalias(name, abuf, sizeof abuf)))
134		name = cp;
135
136	/*
137	 * disallow names consisting only of digits/dots, unless
138	 * they end in a dot.
139	 */
140	if (isdigit((u_char)name[0]))
141		for (cp = name;; ++cp) {
142			if (!*cp) {
143				if (*--cp == '.')
144					break;
145				/*
146				 * All-numeric, no dot at the end.
147				 * Fake up a hostent as if we'd actually
148				 * done a lookup.
149				 */
150				if (inet_pton(af, name, host_addr) <= 0) {
151					h_errno = HOST_NOT_FOUND;
152					return NULL;
153				}
154				strncpy(hostbuf, name, MAXDNAME);
155				hostbuf[MAXDNAME] = '\0';
156				bp = hostbuf + MAXDNAME;
157				ep = hostbuf + sizeof hostbuf;
158				host.h_name = hostbuf;
159				host.h_aliases = host_aliases;
160				host_aliases[0] = NULL;
161				h_addr_ptrs[0] = (char *)host_addr;
162				h_addr_ptrs[1] = NULL;
163				host.h_addr_list = h_addr_ptrs;
164				if (_res.options & RES_USE_INET6)
165					_map_v4v6_hostent(&host, &bp, &ep);
166				h_errno = NETDB_SUCCESS;
167				return &host;
168			}
169			if (!isdigit((u_char)*cp) && *cp != '.')
170				break;
171		}
172	if ((isxdigit((u_char)name[0]) && strchr(name, ':') != NULL) ||
173	    name[0] == ':')
174		for (cp = name;; ++cp) {
175			if (!*cp) {
176				if (*--cp == '.')
177					break;
178				/*
179				 * All-IPv6-legal, no dot at the end.
180				 * Fake up a hostent as if we'd actually
181				 * done a lookup.
182				 */
183				if (inet_pton(af, name, host_addr) <= 0) {
184					h_errno = HOST_NOT_FOUND;
185					return NULL;
186				}
187				strncpy(hostbuf, name, MAXDNAME);
188				hostbuf[MAXDNAME] = '\0';
189				host.h_name = hostbuf;
190				host.h_aliases = host_aliases;
191				host_aliases[0] = NULL;
192				h_addr_ptrs[0] = (char *)host_addr;
193				h_addr_ptrs[1] = NULL;
194				host.h_addr_list = h_addr_ptrs;
195				h_errno = NETDB_SUCCESS;
196				return &host;
197			}
198			if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.')
199				break;
200		}
201
202	rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname",
203	    default_src, name, af);
204
205	if (rval != NS_SUCCESS)
206		return NULL;
207	else
208		return hp;
209}
210
211struct hostent *
212gethostbyaddr(const char *addr, int len, int type)
213{
214	struct hostent *hp = 0;
215	int rval;
216
217	static const ns_dtab dtab[] = {
218		NS_FILES_CB(_ht_gethostbyaddr, NULL)
219		{ NSSRC_DNS, _dns_gethostbyaddr, NULL },
220		NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
221		{ 0 }
222	};
223
224	rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
225			  default_src, addr, len, type);
226
227	if (rval != NS_SUCCESS)
228		return NULL;
229	else
230		return hp;
231}
232
233void
234sethostent(stayopen)
235	int stayopen;
236{
237	_sethosthtent(stayopen);
238	_sethostdnsent(stayopen);
239}
240
241void
242endhostent()
243{
244	_endhosthtent();
245	_endhostdnsent();
246}
247