1135446Strhodes/*
2262706Serwin * Copyright (C) 2004, 2005, 2007, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000, 2001  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: gethost.c,v 1.34 2007/06/19 23:47:22 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22170222Sdougb/**
23170222Sdougb *    These functions provide hostname-to-address and address-to-hostname
24170222Sdougb *    lookups by means of the lightweight resolver. They are similar to the
25170222Sdougb *    standard gethostent(3) functions provided by most operating systems.
26170222Sdougb *    They use a struct hostent which is usually defined in <namedb.h>.
27262706Serwin *
28170222Sdougb * \code
29170222Sdougb * struct  hostent {
30170222Sdougb *         char    *h_name;        // official name of host
31170222Sdougb * 	   char    **h_aliases;    // alias list
32170222Sdougb *         int     h_addrtype;     // host address type
33170222Sdougb *         int     h_length;       // length of address
34170222Sdougb *         char    **h_addr_list;  // list of addresses from name server
35170222Sdougb * };
36170222Sdougb * #define h_addr  h_addr_list[0]  // address, for backward compatibility
37170222Sdougb * \endcode
38262706Serwin *
39170222Sdougb *    The members of this structure are:
40262706Serwin *
41170222Sdougb * \li   h_name:
42170222Sdougb *           The official (canonical) name of the host.
43262706Serwin *
44170222Sdougb * \li   h_aliases:
45170222Sdougb *           A NULL-terminated array of alternate names (nicknames) for the
46170222Sdougb *           host.
47262706Serwin *
48170222Sdougb * \li   h_addrtype:
49170222Sdougb *           The type of address being returned -- PF_INET or PF_INET6.
50262706Serwin *
51170222Sdougb * \li   h_length:
52170222Sdougb *           The length of the address in bytes.
53262706Serwin *
54170222Sdougb * \li   h_addr_list:
55170222Sdougb *           A NULL terminated array of network addresses for the host. Host
56170222Sdougb *           addresses are returned in network byte order.
57262706Serwin *
58170222Sdougb *    For backward compatibility with very old software, h_addr is the first
59170222Sdougb *    address in h_addr_list.
60262706Serwin *
61170222Sdougb *    lwres_gethostent(), lwres_sethostent(), lwres_endhostent(),
62170222Sdougb *    lwres_gethostent_r(), lwres_sethostent_r() and lwres_endhostent_r()
63170222Sdougb *    provide iteration over the known host entries on systems that provide
64170222Sdougb *    such functionality through facilities like /etc/hosts or NIS. The
65170222Sdougb *    lightweight resolver does not currently implement these functions; it
66170222Sdougb *    only provides them as stub functions that always return failure.
67262706Serwin *
68170222Sdougb *    lwres_gethostbyname() and lwres_gethostbyname2() look up the hostname
69170222Sdougb *    name. lwres_gethostbyname() always looks for an IPv4 address while
70170222Sdougb *    lwres_gethostbyname2() looks for an address of protocol family af:
71170222Sdougb *    either PF_INET or PF_INET6 -- IPv4 or IPV6 addresses respectively.
72170222Sdougb *    Successful calls of the functions return a struct hostent for the name
73170222Sdougb *    that was looked up. NULL is returned if the lookups by
74170222Sdougb *    lwres_gethostbyname() or lwres_gethostbyname2() fail.
75262706Serwin *
76170222Sdougb *    Reverse lookups of addresses are performed by lwres_gethostbyaddr().
77170222Sdougb *    addr is an address of length len bytes and protocol family type --
78170222Sdougb *    PF_INET or PF_INET6. lwres_gethostbyname_r() is a thread-safe function
79170222Sdougb *    for forward lookups. If an error occurs, an error code is returned in
80170222Sdougb *    *error. resbuf is a pointer to a struct hostent which is initialised
81170222Sdougb *    by a successful call to lwres_gethostbyname_r() . buf is a buffer of
82170222Sdougb *    length len bytes which is used to store the h_name, h_aliases, and
83170222Sdougb *    h_addr_list elements of the struct hostent returned in resbuf.
84170222Sdougb *    Successful calls to lwres_gethostbyname_r() return resbuf, which is a
85170222Sdougb *    pointer to the struct hostent it created.
86262706Serwin *
87170222Sdougb *    lwres_gethostbyaddr_r() is a thread-safe function that performs a
88170222Sdougb *    reverse lookup of address addr which is len bytes long and is of
89170222Sdougb *    protocol family type -- PF_INET or PF_INET6. If an error occurs, the
90170222Sdougb *    error code is returned in *error. The other function parameters are
91170222Sdougb *    identical to those in lwres_gethostbyname_r(). resbuf is a pointer to
92170222Sdougb *    a struct hostent which is initialised by a successful call to
93170222Sdougb *    lwres_gethostbyaddr_r(). buf is a buffer of length len bytes which is
94170222Sdougb *    used to store the h_name, h_aliases, and h_addr_list elements of the
95170222Sdougb *    struct hostent returned in resbuf. Successful calls to
96170222Sdougb *    lwres_gethostbyaddr_r() return resbuf, which is a pointer to the
97170222Sdougb *    struct hostent it created.
98262706Serwin *
99170222Sdougb * \section gethost_return Return Values
100262706Serwin *
101170222Sdougb *    The functions lwres_gethostbyname(), lwres_gethostbyname2(),
102170222Sdougb *    lwres_gethostbyaddr(), and lwres_gethostent() return NULL to indicate
103170222Sdougb *    an error. In this case the global variable lwres_h_errno will contain
104170222Sdougb *    one of the following error codes defined in \link netdb.h <lwres/netdb.h>:\endlink
105262706Serwin *
106170222Sdougb * \li #HOST_NOT_FOUND:
107170222Sdougb *           The host or address was not found.
108262706Serwin *
109170222Sdougb * \li #TRY_AGAIN:
110170222Sdougb *           A recoverable error occurred, e.g., a timeout. Retrying the
111170222Sdougb *           lookup may succeed.
112262706Serwin *
113170222Sdougb * \li #NO_RECOVERY:
114170222Sdougb *           A non-recoverable error occurred.
115262706Serwin *
116170222Sdougb * \li #NO_DATA:
117170222Sdougb *           The name exists, but has no address information associated with
118170222Sdougb *           it (or vice versa in the case of a reverse lookup). The code
119170222Sdougb *           NO_ADDRESS is accepted as a synonym for NO_DATA for backwards
120170222Sdougb *           compatibility.
121262706Serwin *
122170222Sdougb *    lwres_hstrerror() translates these error codes to suitable error
123170222Sdougb *    messages.
124262706Serwin *
125170222Sdougb *    lwres_gethostent() and lwres_gethostent_r() always return NULL.
126262706Serwin *
127170222Sdougb *    Successful calls to lwres_gethostbyname_r() and
128170222Sdougb *    lwres_gethostbyaddr_r() return resbuf, a pointer to the struct hostent
129170222Sdougb *    that was initialised by these functions. They return NULL if the
130170222Sdougb *    lookups fail or if buf was too small to hold the list of addresses and
131170222Sdougb *    names referenced by the h_name, h_aliases, and h_addr_list elements of
132170222Sdougb *    the struct hostent. If buf was too small, both lwres_gethostbyname_r()
133170222Sdougb *    and lwres_gethostbyaddr_r() set the global variable errno to ERANGE.
134262706Serwin *
135170222Sdougb * \section gethost_see See Also
136262706Serwin *
137170222Sdougb *    gethostent(), \link getipnode.c getipnode\endlink, lwres_hstrerror()
138262706Serwin *
139170222Sdougb * \section gethost_bugs Bugs
140262706Serwin *
141170222Sdougb *    lwres_gethostbyname(), lwres_gethostbyname2(), lwres_gethostbyaddr()
142170222Sdougb *    and lwres_endhostent() are not thread safe; they return pointers to
143170222Sdougb *    static data and provide error codes through a global variable.
144170222Sdougb *    Thread-safe versions for name and address lookup are provided by
145170222Sdougb *    lwres_gethostbyname_r(), and lwres_gethostbyaddr_r() respectively.
146262706Serwin *
147170222Sdougb *    The resolver daemon does not currently support any non-DNS name
148170222Sdougb *    services such as /etc/hosts or NIS, consequently the above functions
149170222Sdougb *    don't, either.
150170222Sdougb */
151170222Sdougb
152135446Strhodes#include <config.h>
153135446Strhodes
154135446Strhodes#include <errno.h>
155135446Strhodes#include <string.h>
156135446Strhodes
157135446Strhodes#include <lwres/net.h>
158135446Strhodes#include <lwres/netdb.h>
159135446Strhodes
160135446Strhodes#include "assert_p.h"
161135446Strhodes
162135446Strhodes#define LWRES_ALIGNBYTES (sizeof(char *) - 1)
163135446Strhodes#define LWRES_ALIGN(p) \
164262706Serwin	(((uintptr_t)(p) + LWRES_ALIGNBYTES) &~ LWRES_ALIGNBYTES)
165135446Strhodes
166135446Strhodesstatic struct hostent *he = NULL;
167135446Strhodesstatic int copytobuf(struct hostent *, struct hostent *, char *, int);
168135446Strhodes
169170222Sdougb/*% Always looks for an IPv4 address. */
170135446Strhodesstruct hostent *
171135446Strhodeslwres_gethostbyname(const char *name) {
172135446Strhodes
173135446Strhodes	if (he != NULL)
174135446Strhodes		lwres_freehostent(he);
175135446Strhodes
176135446Strhodes	he = lwres_getipnodebyname(name, AF_INET, 0, &lwres_h_errno);
177135446Strhodes	return (he);
178135446Strhodes}
179135446Strhodes
180170222Sdougb/*% Looks for either an IPv4 or IPv6 address. */
181135446Strhodesstruct hostent *
182135446Strhodeslwres_gethostbyname2(const char *name, int af) {
183135446Strhodes	if (he != NULL)
184135446Strhodes		lwres_freehostent(he);
185135446Strhodes
186135446Strhodes	he = lwres_getipnodebyname(name, af, 0, &lwres_h_errno);
187135446Strhodes	return (he);
188135446Strhodes}
189135446Strhodes
190170222Sdougb/*% Reverse lookup of addresses. */
191135446Strhodesstruct hostent *
192135446Strhodeslwres_gethostbyaddr(const char *addr, int len, int type) {
193135446Strhodes
194135446Strhodes	if (he != NULL)
195135446Strhodes		lwres_freehostent(he);
196135446Strhodes
197135446Strhodes	he = lwres_getipnodebyaddr(addr, len, type, &lwres_h_errno);
198135446Strhodes	return (he);
199135446Strhodes}
200135446Strhodes
201170222Sdougb/*% Stub function.  Always returns failure. */
202135446Strhodesstruct hostent *
203135446Strhodeslwres_gethostent(void) {
204135446Strhodes	if (he != NULL)
205135446Strhodes		lwres_freehostent(he);
206135446Strhodes
207135446Strhodes	return (NULL);
208135446Strhodes}
209135446Strhodes
210170222Sdougb/*% Stub function.  Always returns failure. */
211135446Strhodesvoid
212135446Strhodeslwres_sethostent(int stayopen) {
213135446Strhodes	/*
214135446Strhodes	 * Empty.
215135446Strhodes	 */
216135446Strhodes	UNUSED(stayopen);
217135446Strhodes}
218135446Strhodes
219170222Sdougb/*% Stub function.  Always returns failure. */
220135446Strhodesvoid
221135446Strhodeslwres_endhostent(void) {
222135446Strhodes	/*
223135446Strhodes	 * Empty.
224135446Strhodes	 */
225135446Strhodes}
226135446Strhodes
227170222Sdougb/*% Thread-safe function for forward lookups. */
228135446Strhodesstruct hostent *
229135446Strhodeslwres_gethostbyname_r(const char *name, struct hostent *resbuf,
230135446Strhodes		char *buf, int buflen, int *error)
231135446Strhodes{
232135446Strhodes	struct hostent *he;
233135446Strhodes	int res;
234135446Strhodes
235135446Strhodes	he = lwres_getipnodebyname(name, AF_INET, 0, error);
236135446Strhodes	if (he == NULL)
237135446Strhodes		return (NULL);
238135446Strhodes	res = copytobuf(he, resbuf, buf, buflen);
239135446Strhodes	lwres_freehostent(he);
240135446Strhodes	if (res != 0) {
241135446Strhodes		errno = ERANGE;
242135446Strhodes		return (NULL);
243135446Strhodes	}
244135446Strhodes	return (resbuf);
245135446Strhodes}
246135446Strhodes
247170222Sdougb/*% Thread-safe reverse lookup. */
248135446Strhodesstruct hostent  *
249135446Strhodeslwres_gethostbyaddr_r(const char *addr, int len, int type,
250135446Strhodes		      struct hostent *resbuf, char *buf, int buflen,
251135446Strhodes		      int *error)
252135446Strhodes{
253135446Strhodes	struct hostent *he;
254135446Strhodes	int res;
255135446Strhodes
256135446Strhodes	he = lwres_getipnodebyaddr(addr, len, type, error);
257135446Strhodes	if (he == NULL)
258135446Strhodes		return (NULL);
259135446Strhodes	res = copytobuf(he, resbuf, buf, buflen);
260135446Strhodes	lwres_freehostent(he);
261135446Strhodes	if (res != 0) {
262135446Strhodes		errno = ERANGE;
263135446Strhodes		return (NULL);
264135446Strhodes	}
265135446Strhodes	return (resbuf);
266135446Strhodes}
267135446Strhodes
268170222Sdougb/*% Stub function.  Always returns failure. */
269135446Strhodesstruct hostent  *
270135446Strhodeslwres_gethostent_r(struct hostent *resbuf, char *buf, int buflen, int *error) {
271135446Strhodes	UNUSED(resbuf);
272135446Strhodes	UNUSED(buf);
273135446Strhodes	UNUSED(buflen);
274135446Strhodes	*error = 0;
275135446Strhodes	return (NULL);
276135446Strhodes}
277135446Strhodes
278170222Sdougb/*% Stub function.  Always returns failure. */
279135446Strhodesvoid
280135446Strhodeslwres_sethostent_r(int stayopen) {
281135446Strhodes	/*
282135446Strhodes	 * Empty.
283135446Strhodes	 */
284135446Strhodes	UNUSED(stayopen);
285135446Strhodes}
286135446Strhodes
287170222Sdougb/*% Stub function.  Always returns failure. */
288135446Strhodesvoid
289135446Strhodeslwres_endhostent_r(void) {
290135446Strhodes	/*
291135446Strhodes	 * Empty.
292135446Strhodes	 */
293135446Strhodes}
294135446Strhodes
295135446Strhodesstatic int
296135446Strhodescopytobuf(struct hostent *he, struct hostent *hptr, char *buf, int buflen) {
297262706Serwin	char *cp;
298262706Serwin	char **ptr;
299262706Serwin	int i, n;
300262706Serwin	int nptr, len;
301135446Strhodes
302262706Serwin	/*
303135446Strhodes	 * Find out the amount of space required to store the answer.
304135446Strhodes	 */
305262706Serwin	nptr = 2; /* NULL ptrs */
306262706Serwin	len = (int)((char *)LWRES_ALIGN(buf) - buf);
307262706Serwin	for (i = 0; he->h_addr_list[i]; i++, nptr++) {
308262706Serwin		len += he->h_length;
309262706Serwin	}
310262706Serwin	for (i = 0; he->h_aliases[i]; i++, nptr++) {
311262706Serwin		len += strlen(he->h_aliases[i]) + 1;
312262706Serwin	}
313262706Serwin	len += strlen(he->h_name) + 1;
314262706Serwin	len += nptr * sizeof(char*);
315135446Strhodes
316262706Serwin	if (len > buflen) {
317262706Serwin		return (-1);
318262706Serwin	}
319135446Strhodes
320262706Serwin	/*
321135446Strhodes	 * Copy address size and type.
322135446Strhodes	 */
323262706Serwin	hptr->h_addrtype = he->h_addrtype;
324262706Serwin	n = hptr->h_length = he->h_length;
325135446Strhodes
326262706Serwin	ptr = (char **)LWRES_ALIGN(buf);
327262706Serwin	cp = (char *)LWRES_ALIGN(buf) + nptr * sizeof(char *);
328135446Strhodes
329262706Serwin	/*
330135446Strhodes	 * Copy address list.
331135446Strhodes	 */
332262706Serwin	hptr->h_addr_list = ptr;
333262706Serwin	for (i = 0; he->h_addr_list[i]; i++, ptr++) {
334262706Serwin		memmove(cp, he->h_addr_list[i], n);
335262706Serwin		hptr->h_addr_list[i] = cp;
336262706Serwin		cp += n;
337262706Serwin	}
338262706Serwin	hptr->h_addr_list[i] = NULL;
339262706Serwin	ptr++;
340135446Strhodes
341262706Serwin	/*
342135446Strhodes	 * Copy official name.
343135446Strhodes	 */
344262706Serwin	n = strlen(he->h_name) + 1;
345262706Serwin	strcpy(cp, he->h_name);
346262706Serwin	hptr->h_name = cp;
347262706Serwin	cp += n;
348135446Strhodes
349262706Serwin	/*
350135446Strhodes	 * Copy aliases.
351135446Strhodes	 */
352262706Serwin	hptr->h_aliases = ptr;
353262706Serwin	for (i = 0; he->h_aliases[i]; i++) {
354262706Serwin		n = strlen(he->h_aliases[i]) + 1;
355262706Serwin		strcpy(cp, he->h_aliases[i]);
356262706Serwin		hptr->h_aliases[i] = cp;
357262706Serwin		cp += n;
358262706Serwin	}
359262706Serwin	hptr->h_aliases[i] = NULL;
360135446Strhodes
361262706Serwin	return (0);
362135446Strhodes}
363