gethostnamadr.c revision 145512
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 145512 2005-04-25 17:36:28Z 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
45extern int _ht_gethostbyname(void *, void *, va_list);
46extern int _dns_gethostbyname(void *, void *, va_list);
47extern int _nis_gethostbyname(void *, void *, va_list);
48extern int _ht_gethostbyaddr(void *, void *, va_list);
49extern int _dns_gethostbyaddr(void *, void *, va_list);
50extern int _nis_gethostbyaddr(void *, void *, va_list);
51extern const char *_res_hostalias(const char *, char *, size_t);
52
53static struct hostent *gethostbyname_internal(const char *, int);
54
55/* Host lookup order if nsswitch.conf is broken or nonexistant */
56static const ns_src default_src[] = {
57	{ NSSRC_FILES, NS_SUCCESS },
58	{ NSSRC_DNS, NS_SUCCESS },
59	{ 0 }
60};
61
62struct hostent *
63gethostbyname(const char *name)
64{
65	struct hostent *hp;
66
67	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
68		h_errno = NETDB_INTERNAL;
69		return NULL;
70	}
71	if (_res.options & RES_USE_INET6) {
72		hp = gethostbyname_internal(name, AF_INET6);
73		if (hp)
74			return hp;
75	}
76	return gethostbyname_internal(name, AF_INET);
77}
78
79struct hostent *
80gethostbyname2(const char *name, int af)
81{
82	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
83		h_errno = NETDB_INTERNAL;
84		return NULL;
85	}
86	return gethostbyname_internal(name, af);
87}
88
89static struct hostent *
90gethostbyname_internal(const char *name, int af)
91{
92	const char *cp;
93	char *bp, *ep;
94	struct hostent *hp = 0;
95	int size, rval;
96	char abuf[MAXDNAME];
97
98	static struct hostent host;
99	static char *h_addr_ptrs[2];
100	static char *host_aliases[1];
101	static char hostbuf[MAXDNAME + IN6ADDRSZ + sizeof(uint32_t)];
102	static uint32_t host_addr[4];	/* IPv4 or IPv6 */
103	static const ns_dtab dtab[] = {
104		NS_FILES_CB(_ht_gethostbyname, NULL)
105		{ NSSRC_DNS, _dns_gethostbyname, NULL },
106		NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
107		{ 0 }
108	};
109
110	switch (af) {
111	case AF_INET:
112		size = INADDRSZ;
113		break;
114	case AF_INET6:
115		size = IN6ADDRSZ;
116		break;
117	default:
118		h_errno = NETDB_INTERNAL;
119		errno = EAFNOSUPPORT;
120		return NULL;
121	}
122
123	host.h_addrtype = af;
124	host.h_length = size;
125
126	/*
127	 * if there aren't any dots, it could be a user-level alias.
128	 * this is also done in res_query() since we are not the only
129	 * function that looks up host names.
130	 */
131	if (!strchr(name, '.') &&
132	    (cp = _res_hostalias(name, abuf, sizeof abuf)))
133		name = cp;
134
135	/*
136	 * disallow names consisting only of digits/dots, unless
137	 * they end in a dot.
138	 */
139	if (isdigit((u_char)name[0]))
140		for (cp = name;; ++cp) {
141			if (!*cp) {
142				if (*--cp == '.')
143					break;
144				/*
145				 * All-numeric, no dot at the end.
146				 * Fake up a hostent as if we'd actually
147				 * done a lookup.
148				 */
149				if (inet_pton(af, name, host_addr) <= 0) {
150					h_errno = HOST_NOT_FOUND;
151					return NULL;
152				}
153				strncpy(hostbuf, name, MAXDNAME);
154				hostbuf[MAXDNAME] = '\0';
155				bp = hostbuf + MAXDNAME;
156				ep = hostbuf + sizeof hostbuf;
157				host.h_name = hostbuf;
158				host.h_aliases = host_aliases;
159				host_aliases[0] = NULL;
160				h_addr_ptrs[0] = (char *)host_addr;
161				h_addr_ptrs[1] = NULL;
162				host.h_addr_list = h_addr_ptrs;
163				if (_res.options & RES_USE_INET6)
164					_map_v4v6_hostent(&host, &bp, &ep);
165				h_errno = NETDB_SUCCESS;
166				return &host;
167			}
168			if (!isdigit((u_char)*cp) && *cp != '.')
169				break;
170		}
171	if ((isxdigit((u_char)name[0]) && strchr(name, ':') != NULL) ||
172	    name[0] == ':')
173		for (cp = name;; ++cp) {
174			if (!*cp) {
175				if (*--cp == '.')
176					break;
177				/*
178				 * All-IPv6-legal, no dot at the end.
179				 * Fake up a hostent as if we'd actually
180				 * done a lookup.
181				 */
182				if (inet_pton(af, name, host_addr) <= 0) {
183					h_errno = HOST_NOT_FOUND;
184					return NULL;
185				}
186				strncpy(hostbuf, name, MAXDNAME);
187				hostbuf[MAXDNAME] = '\0';
188				host.h_name = hostbuf;
189				host.h_aliases = host_aliases;
190				host_aliases[0] = NULL;
191				h_addr_ptrs[0] = (char *)host_addr;
192				h_addr_ptrs[1] = NULL;
193				host.h_addr_list = h_addr_ptrs;
194				h_errno = NETDB_SUCCESS;
195				return &host;
196			}
197			if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.')
198				break;
199		}
200
201	rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname",
202	    default_src, name, af);
203
204	if (rval != NS_SUCCESS)
205		return NULL;
206	else
207		return hp;
208}
209
210struct hostent *
211gethostbyaddr(const char *addr, int len, int type)
212{
213	struct hostent *hp = 0;
214	int rval;
215
216	static const ns_dtab dtab[] = {
217		NS_FILES_CB(_ht_gethostbyaddr, NULL)
218		{ NSSRC_DNS, _dns_gethostbyaddr, NULL },
219		NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
220		{ 0 }
221	};
222
223	rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
224			  default_src, addr, len, type);
225
226	if (rval != NS_SUCCESS)
227		return NULL;
228	else
229		return hp;
230}
231
232void
233sethostent(stayopen)
234	int stayopen;
235{
236	_sethosthtent(stayopen);
237	_sethostdnsent(stayopen);
238}
239
240void
241endhostent()
242{
243	_endhosthtent();
244	_endhostdnsent();
245}
246