gethostnamadr.c revision 145633
11573Srgrimes/*-
23070Spst * Copyright (c) 1994, Garrett Wollman
31573Srgrimes *
41573Srgrimes * Redistribution and use in source and binary forms, with or without
51573Srgrimes * modification, are permitted provided that the following conditions
61573Srgrimes * are met:
71573Srgrimes * 1. Redistributions of source code must retain the above copyright
81573Srgrimes *    notice, this list of conditions and the following disclaimer.
91573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
101573Srgrimes *    notice, this list of conditions and the following disclaimer in the
111573Srgrimes *    documentation and/or other materials provided with the distribution.
121573Srgrimes *
133070Spst * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
141573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
171573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231573Srgrimes * SUCH DAMAGE.
241573Srgrimes */
251573Srgrimes
2692986Sobrien#include <sys/cdefs.h>
2792986Sobrien__FBSDID("$FreeBSD: head/lib/libc/net/gethostnamadr.c 145633 2005-04-28 18:03:43Z ume $");
281573Srgrimes
29113977Snectar#include "namespace.h"
30145633Sume#include "reentrant.h"
311573Srgrimes#include <sys/param.h>
321573Srgrimes#include <sys/socket.h>
331573Srgrimes#include <netinet/in.h>
341573Srgrimes#include <arpa/inet.h>
351573Srgrimes#include <netdb.h>
361573Srgrimes#include <stdio.h>
371573Srgrimes#include <ctype.h>
38145512Sume#include <errno.h>
39145633Sume#include <stdlib.h>
401573Srgrimes#include <string.h>
4165532Snectar#include <stdarg.h>
4265532Snectar#include <nsswitch.h>
4317903Speter#include <arpa/nameser.h>		/* XXX hack for _res */
4417903Speter#include <resolv.h>			/* XXX hack for _res */
45113977Snectar#include "un-namespace.h"
46145602Sume#include "netdb_private.h"
471573Srgrimes
4865532Snectarextern int _ht_gethostbyname(void *, void *, va_list);
4965532Snectarextern int _dns_gethostbyname(void *, void *, va_list);
5065532Snectarextern int _nis_gethostbyname(void *, void *, va_list);
5165532Snectarextern int _ht_gethostbyaddr(void *, void *, va_list);
5265532Snectarextern int _dns_gethostbyaddr(void *, void *, va_list);
5365532Snectarextern int _nis_gethostbyaddr(void *, void *, va_list);
54145512Sumeextern const char *_res_hostalias(const char *, char *, size_t);
551991Swollman
56145633Sumestatic int gethostbyname_internal(const char *, int, struct hostent *,
57145633Sume    struct hostent_data *);
58145512Sume
5965532Snectar/* Host lookup order if nsswitch.conf is broken or nonexistant */
60145512Sumestatic const ns_src default_src[] = {
6165532Snectar	{ NSSRC_FILES, NS_SUCCESS },
6265532Snectar	{ NSSRC_DNS, NS_SUCCESS },
6365532Snectar	{ 0 }
641991Swollman};
651991Swollman
66145633Sumestatic struct hostdata hostdata;
67145633Sumestatic thread_key_t hostdata_key;
68145633Sumestatic once_t hostdata_init_once = ONCE_INITIALIZER;
69145633Sumestatic int hostdata_thr_keycreated = 0;
70145633Sume
71145633Sumestatic void
72145633Sumehostdata_free(void *ptr)
731991Swollman{
74145633Sume	struct hostdata *hd = ptr;
7517903Speter
76145633Sume	if (hd == NULL)
77145633Sume		return;
78145633Sume	hd->data.stayopen = 0;
79145633Sume	_endhosthtent(&hd->data);
80145633Sume	free(hd);
81145633Sume}
82145633Sume
83145633Sumestatic void
84145633Sumehostdata_keycreate(void)
85145633Sume{
86145633Sume	hostdata_thr_keycreated =
87145633Sume	    (thr_keycreate(&hostdata_key, hostdata_free) == 0);
88145633Sume}
89145633Sume
90145633Sumestruct hostdata *
91145633Sume__hostdata_init(void)
92145633Sume{
93145633Sume	struct hostdata *hd;
94145633Sume
95145633Sume	if (thr_main() != 0)
96145633Sume		return &hostdata;
97145633Sume	if (thr_once(&hostdata_init_once, hostdata_keycreate) != 0 ||
98145633Sume	    !hostdata_thr_keycreated)
99145633Sume		return NULL;
100145633Sume	if ((hd = thr_getspecific(hostdata_key)) != NULL)
101145633Sume		return hd;
102145633Sume	if ((hd = calloc(1, sizeof(*hd))) == NULL)
103145633Sume		return NULL;
104145633Sume	if (thr_setspecific(hostdata_key, hd) == 0)
105145633Sume		return hd;
106145633Sume	free(hd);
107145633Sume	return NULL;
108145633Sume}
109145633Sume
110145633Sumeint
111145633Sumegethostbyname_r(const char *name, struct hostent *he, struct hostent_data *hed)
112145633Sume{
113145633Sume	int error;
114145633Sume
11567709Sume	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
11667709Sume		h_errno = NETDB_INTERNAL;
117145633Sume		return -1;
11867709Sume	}
119145512Sume	if (_res.options & RES_USE_INET6) {
120145633Sume		error = gethostbyname_internal(name, AF_INET6, he, hed);
121145633Sume		if (error == 0)
122145633Sume			return 0;
123145512Sume	}
124145633Sume	return gethostbyname_internal(name, AF_INET, he, hed);
12517903Speter}
12617903Speter
127145633Sumeint
128145633Sumegethostbyname2_r(const char *name, int af, struct hostent *he,
129145633Sume    struct hostent_data *hed)
13017903Speter{
131145512Sume	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
132145512Sume		h_errno = NETDB_INTERNAL;
133145633Sume		return -1;
134145512Sume	}
135145633Sume	return gethostbyname_internal(name, af, he, hed);
136145512Sume}
137145512Sume
138145633Sumestatic int
139145633Sumegethostbyname_internal(const char *name, int af, struct hostent *he,
140145633Sume    struct hostent_data *hed)
141145512Sume{
142145512Sume	const char *cp;
143145512Sume	char *bp, *ep;
144145512Sume	int size, rval;
145145512Sume	char abuf[MAXDNAME];
1461991Swollman
14765532Snectar	static const ns_dtab dtab[] = {
14865532Snectar		NS_FILES_CB(_ht_gethostbyname, NULL)
14965532Snectar		{ NSSRC_DNS, _dns_gethostbyname, NULL },
15065532Snectar		NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
15165532Snectar		{ 0 }
152145512Sume	};
153145512Sume
154145512Sume	switch (af) {
155145512Sume	case AF_INET:
156145512Sume		size = INADDRSZ;
157145512Sume		break;
158145512Sume	case AF_INET6:
159145512Sume		size = IN6ADDRSZ;
160145512Sume		break;
161145512Sume	default:
162145512Sume		h_errno = NETDB_INTERNAL;
163145512Sume		errno = EAFNOSUPPORT;
164145633Sume		return -1;
165145512Sume	}
166145512Sume
167145633Sume	he->h_addrtype = af;
168145633Sume	he->h_length = size;
169145512Sume
170145512Sume	/*
171145512Sume	 * if there aren't any dots, it could be a user-level alias.
172145512Sume	 * this is also done in res_query() since we are not the only
173145512Sume	 * function that looks up host names.
174145512Sume	 */
175145512Sume	if (!strchr(name, '.') &&
176145512Sume	    (cp = _res_hostalias(name, abuf, sizeof abuf)))
177145512Sume		name = cp;
178145512Sume
179145512Sume	/*
180145512Sume	 * disallow names consisting only of digits/dots, unless
181145512Sume	 * they end in a dot.
182145512Sume	 */
183145512Sume	if (isdigit((u_char)name[0]))
184145512Sume		for (cp = name;; ++cp) {
185145512Sume			if (!*cp) {
186145512Sume				if (*--cp == '.')
187145512Sume					break;
188145512Sume				/*
189145512Sume				 * All-numeric, no dot at the end.
190145512Sume				 * Fake up a hostent as if we'd actually
191145512Sume				 * done a lookup.
192145512Sume				 */
193145633Sume				if (inet_pton(af, name, hed->host_addr) <= 0) {
194145512Sume					h_errno = HOST_NOT_FOUND;
195145633Sume					return -1;
196145512Sume				}
197145633Sume				strncpy(hed->hostbuf, name, MAXDNAME);
198145633Sume				hed->hostbuf[MAXDNAME] = '\0';
199145633Sume				bp = hed->hostbuf + MAXDNAME + 1;
200145633Sume				ep = hed->hostbuf + sizeof hed->hostbuf;
201145633Sume				he->h_name = hed->hostbuf;
202145633Sume				he->h_aliases = hed->host_aliases;
203145633Sume				hed->host_aliases[0] = NULL;
204145633Sume				hed->h_addr_ptrs[0] = (char *)hed->host_addr;
205145633Sume				hed->h_addr_ptrs[1] = NULL;
206145633Sume				he->h_addr_list = hed->h_addr_ptrs;
207145512Sume				if (_res.options & RES_USE_INET6)
208145633Sume					_map_v4v6_hostent(he, &bp, &ep);
209145512Sume				h_errno = NETDB_SUCCESS;
210145633Sume				return 0;
211145512Sume			}
212145512Sume			if (!isdigit((u_char)*cp) && *cp != '.')
213145512Sume				break;
214145512Sume		}
215145512Sume	if ((isxdigit((u_char)name[0]) && strchr(name, ':') != NULL) ||
216145512Sume	    name[0] == ':')
217145512Sume		for (cp = name;; ++cp) {
218145512Sume			if (!*cp) {
219145512Sume				if (*--cp == '.')
220145512Sume					break;
221145512Sume				/*
222145512Sume				 * All-IPv6-legal, no dot at the end.
223145512Sume				 * Fake up a hostent as if we'd actually
224145512Sume				 * done a lookup.
225145512Sume				 */
226145633Sume				if (inet_pton(af, name, hed->host_addr) <= 0) {
227145512Sume					h_errno = HOST_NOT_FOUND;
228145633Sume					return -1;
229145512Sume				}
230145633Sume				strncpy(hed->hostbuf, name, MAXDNAME);
231145633Sume				hed->hostbuf[MAXDNAME] = '\0';
232145633Sume				he->h_name = hed->hostbuf;
233145633Sume				he->h_aliases = hed->host_aliases;
234145633Sume				hed->host_aliases[0] = NULL;
235145633Sume				hed->h_addr_ptrs[0] = (char *)hed->host_addr;
236145633Sume				hed->h_addr_ptrs[1] = NULL;
237145633Sume				he->h_addr_list = hed->h_addr_ptrs;
238145512Sume				h_errno = NETDB_SUCCESS;
239145633Sume				return 0;
240145512Sume			}
241145512Sume			if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.')
242145512Sume				break;
243145512Sume		}
244145512Sume
245145633Sume	rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyname",
246145633Sume	    default_src, name, af, he, hed);
2471991Swollman
248145633Sume	return (rval == NS_SUCCESS) ? 0 : -1;
2491991Swollman}
2501991Swollman
251145633Sumeint
252145633Sumegethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
253145633Sume    struct hostent_data *hed)
2541991Swollman{
25565532Snectar	int rval;
2561991Swollman
25765532Snectar	static const ns_dtab dtab[] = {
25865532Snectar		NS_FILES_CB(_ht_gethostbyaddr, NULL)
25965532Snectar		{ NSSRC_DNS, _dns_gethostbyaddr, NULL },
26065532Snectar		NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
26165532Snectar		{ 0 }
262145633Sume	};
2631991Swollman
264145633Sume	rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyaddr",
265145633Sume	    default_src, addr, len, af, he, hed);
26665532Snectar
267145633Sume	return (rval == NS_SUCCESS) ? 0 : -1;
2681991Swollman}
2691991Swollman
2703070Spstvoid
271145633Sumesethostent_r(int stayopen, struct hostent_data *hed)
2723070Spst{
273145633Sume	_sethosthtent(stayopen, hed);
2743070Spst	_sethostdnsent(stayopen);
2753070Spst}
2763070Spst
2773070Spstvoid
278145633Sumeendhostent_r(struct hostent_data *hed)
2793070Spst{
280145633Sume	_endhosthtent(hed);
2813070Spst	_endhostdnsent();
2823070Spst}
283145633Sume
284145633Sumestruct hostent *
285145633Sumegethostbyname(const char *name)
286145633Sume{
287145633Sume	struct hostdata *hd;
288145633Sume
289145633Sume	if ((hd = __hostdata_init()) == NULL)
290145633Sume		return NULL;
291145633Sume	if (gethostbyname_r(name, &hd->host, &hd->data) != 0)
292145633Sume		return NULL;
293145633Sume	return &hd->host;
294145633Sume}
295145633Sume
296145633Sumestruct hostent *
297145633Sumegethostbyname2(const char *name, int af)
298145633Sume{
299145633Sume	struct hostdata *hd;
300145633Sume
301145633Sume	if ((hd = __hostdata_init()) == NULL)
302145633Sume		return NULL;
303145633Sume	if (gethostbyname2_r(name, af, &hd->host, &hd->data) != 0)
304145633Sume		return NULL;
305145633Sume	return &hd->host;
306145633Sume}
307145633Sume
308145633Sumestruct hostent *
309145633Sumegethostbyaddr(const char *addr, int len, int af)
310145633Sume{
311145633Sume	struct hostdata *hd;
312145633Sume
313145633Sume	if ((hd = __hostdata_init()) == NULL)
314145633Sume		return NULL;
315145633Sume	if (gethostbyaddr_r(addr, len, af, &hd->host, &hd->data) != 0)
316145633Sume		return NULL;
317145633Sume	return &hd->host;
318145633Sume}
319145633Sume
320145633Sumevoid
321145633Sumesethostent(int stayopen)
322145633Sume{
323145633Sume	struct hostdata *hd;
324145633Sume
325145633Sume	if ((hd = __hostdata_init()) == NULL)
326145633Sume		return;
327145633Sume	sethostent_r(stayopen, &hd->data);
328145633Sume}
329145633Sume
330145633Sumevoid
331145633Sumeendhostent(void)
332145633Sume{
333145633Sume	struct hostdata *hd;
334145633Sume
335145633Sume	if ((hd = __hostdata_init()) == NULL)
336145633Sume		return;
337145633Sume	endhostent_r(&hd->data);
338145633Sume}
339