1/*
2 * Copyright (C) 2004, 2005, 2007, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: gethost.c,v 1.34 2007/06/19 23:47:22 tbox Exp $ */
19
20/*! \file */
21
22/**
23 *    These functions provide hostname-to-address and address-to-hostname
24 *    lookups by means of the lightweight resolver. They are similar to the
25 *    standard gethostent(3) functions provided by most operating systems.
26 *    They use a struct hostent which is usually defined in <namedb.h>.
27 *
28 * \code
29 * struct  hostent {
30 *         char    *h_name;        // official name of host
31 * 	   char    **h_aliases;    // alias list
32 *         int     h_addrtype;     // host address type
33 *         int     h_length;       // length of address
34 *         char    **h_addr_list;  // list of addresses from name server
35 * };
36 * #define h_addr  h_addr_list[0]  // address, for backward compatibility
37 * \endcode
38 *
39 *    The members of this structure are:
40 *
41 * \li   h_name:
42 *           The official (canonical) name of the host.
43 *
44 * \li   h_aliases:
45 *           A NULL-terminated array of alternate names (nicknames) for the
46 *           host.
47 *
48 * \li   h_addrtype:
49 *           The type of address being returned -- PF_INET or PF_INET6.
50 *
51 * \li   h_length:
52 *           The length of the address in bytes.
53 *
54 * \li   h_addr_list:
55 *           A NULL terminated array of network addresses for the host. Host
56 *           addresses are returned in network byte order.
57 *
58 *    For backward compatibility with very old software, h_addr is the first
59 *    address in h_addr_list.
60 *
61 *    lwres_gethostent(), lwres_sethostent(), lwres_endhostent(),
62 *    lwres_gethostent_r(), lwres_sethostent_r() and lwres_endhostent_r()
63 *    provide iteration over the known host entries on systems that provide
64 *    such functionality through facilities like /etc/hosts or NIS. The
65 *    lightweight resolver does not currently implement these functions; it
66 *    only provides them as stub functions that always return failure.
67 *
68 *    lwres_gethostbyname() and lwres_gethostbyname2() look up the hostname
69 *    name. lwres_gethostbyname() always looks for an IPv4 address while
70 *    lwres_gethostbyname2() looks for an address of protocol family af:
71 *    either PF_INET or PF_INET6 -- IPv4 or IPV6 addresses respectively.
72 *    Successful calls of the functions return a struct hostent for the name
73 *    that was looked up. NULL is returned if the lookups by
74 *    lwres_gethostbyname() or lwres_gethostbyname2() fail.
75 *
76 *    Reverse lookups of addresses are performed by lwres_gethostbyaddr().
77 *    addr is an address of length len bytes and protocol family type --
78 *    PF_INET or PF_INET6. lwres_gethostbyname_r() is a thread-safe function
79 *    for forward lookups. If an error occurs, an error code is returned in
80 *    *error. resbuf is a pointer to a struct hostent which is initialised
81 *    by a successful call to lwres_gethostbyname_r() . buf is a buffer of
82 *    length len bytes which is used to store the h_name, h_aliases, and
83 *    h_addr_list elements of the struct hostent returned in resbuf.
84 *    Successful calls to lwres_gethostbyname_r() return resbuf, which is a
85 *    pointer to the struct hostent it created.
86 *
87 *    lwres_gethostbyaddr_r() is a thread-safe function that performs a
88 *    reverse lookup of address addr which is len bytes long and is of
89 *    protocol family type -- PF_INET or PF_INET6. If an error occurs, the
90 *    error code is returned in *error. The other function parameters are
91 *    identical to those in lwres_gethostbyname_r(). resbuf is a pointer to
92 *    a struct hostent which is initialised by a successful call to
93 *    lwres_gethostbyaddr_r(). buf is a buffer of length len bytes which is
94 *    used to store the h_name, h_aliases, and h_addr_list elements of the
95 *    struct hostent returned in resbuf. Successful calls to
96 *    lwres_gethostbyaddr_r() return resbuf, which is a pointer to the
97 *    struct hostent it created.
98 *
99 * \section gethost_return Return Values
100 *
101 *    The functions lwres_gethostbyname(), lwres_gethostbyname2(),
102 *    lwres_gethostbyaddr(), and lwres_gethostent() return NULL to indicate
103 *    an error. In this case the global variable lwres_h_errno will contain
104 *    one of the following error codes defined in \link netdb.h <lwres/netdb.h>:\endlink
105 *
106 * \li #HOST_NOT_FOUND:
107 *           The host or address was not found.
108 *
109 * \li #TRY_AGAIN:
110 *           A recoverable error occurred, e.g., a timeout. Retrying the
111 *           lookup may succeed.
112 *
113 * \li #NO_RECOVERY:
114 *           A non-recoverable error occurred.
115 *
116 * \li #NO_DATA:
117 *           The name exists, but has no address information associated with
118 *           it (or vice versa in the case of a reverse lookup). The code
119 *           NO_ADDRESS is accepted as a synonym for NO_DATA for backwards
120 *           compatibility.
121 *
122 *    lwres_hstrerror() translates these error codes to suitable error
123 *    messages.
124 *
125 *    lwres_gethostent() and lwres_gethostent_r() always return NULL.
126 *
127 *    Successful calls to lwres_gethostbyname_r() and
128 *    lwres_gethostbyaddr_r() return resbuf, a pointer to the struct hostent
129 *    that was initialised by these functions. They return NULL if the
130 *    lookups fail or if buf was too small to hold the list of addresses and
131 *    names referenced by the h_name, h_aliases, and h_addr_list elements of
132 *    the struct hostent. If buf was too small, both lwres_gethostbyname_r()
133 *    and lwres_gethostbyaddr_r() set the global variable errno to ERANGE.
134 *
135 * \section gethost_see See Also
136 *
137 *    gethostent(), \link getipnode.c getipnode\endlink, lwres_hstrerror()
138 *
139 * \section gethost_bugs Bugs
140 *
141 *    lwres_gethostbyname(), lwres_gethostbyname2(), lwres_gethostbyaddr()
142 *    and lwres_endhostent() are not thread safe; they return pointers to
143 *    static data and provide error codes through a global variable.
144 *    Thread-safe versions for name and address lookup are provided by
145 *    lwres_gethostbyname_r(), and lwres_gethostbyaddr_r() respectively.
146 *
147 *    The resolver daemon does not currently support any non-DNS name
148 *    services such as /etc/hosts or NIS, consequently the above functions
149 *    don't, either.
150 */
151
152#include <config.h>
153
154#include <errno.h>
155#include <string.h>
156
157#include <lwres/net.h>
158#include <lwres/netdb.h>
159
160#include "assert_p.h"
161
162#define LWRES_ALIGNBYTES (sizeof(char *) - 1)
163#define LWRES_ALIGN(p) \
164	(((uintptr_t)(p) + LWRES_ALIGNBYTES) &~ LWRES_ALIGNBYTES)
165
166static struct hostent *he = NULL;
167static int copytobuf(struct hostent *, struct hostent *, char *, int);
168
169/*% Always looks for an IPv4 address. */
170struct hostent *
171lwres_gethostbyname(const char *name) {
172
173	if (he != NULL)
174		lwres_freehostent(he);
175
176	he = lwres_getipnodebyname(name, AF_INET, 0, &lwres_h_errno);
177	return (he);
178}
179
180/*% Looks for either an IPv4 or IPv6 address. */
181struct hostent *
182lwres_gethostbyname2(const char *name, int af) {
183	if (he != NULL)
184		lwres_freehostent(he);
185
186	he = lwres_getipnodebyname(name, af, 0, &lwres_h_errno);
187	return (he);
188}
189
190/*% Reverse lookup of addresses. */
191struct hostent *
192lwres_gethostbyaddr(const char *addr, int len, int type) {
193
194	if (he != NULL)
195		lwres_freehostent(he);
196
197	he = lwres_getipnodebyaddr(addr, len, type, &lwres_h_errno);
198	return (he);
199}
200
201/*% Stub function.  Always returns failure. */
202struct hostent *
203lwres_gethostent(void) {
204	if (he != NULL)
205		lwres_freehostent(he);
206
207	return (NULL);
208}
209
210/*% Stub function.  Always returns failure. */
211void
212lwres_sethostent(int stayopen) {
213	/*
214	 * Empty.
215	 */
216	UNUSED(stayopen);
217}
218
219/*% Stub function.  Always returns failure. */
220void
221lwres_endhostent(void) {
222	/*
223	 * Empty.
224	 */
225}
226
227/*% Thread-safe function for forward lookups. */
228struct hostent *
229lwres_gethostbyname_r(const char *name, struct hostent *resbuf,
230		char *buf, int buflen, int *error)
231{
232	struct hostent *he;
233	int res;
234
235	he = lwres_getipnodebyname(name, AF_INET, 0, error);
236	if (he == NULL)
237		return (NULL);
238	res = copytobuf(he, resbuf, buf, buflen);
239	lwres_freehostent(he);
240	if (res != 0) {
241		errno = ERANGE;
242		return (NULL);
243	}
244	return (resbuf);
245}
246
247/*% Thread-safe reverse lookup. */
248struct hostent  *
249lwres_gethostbyaddr_r(const char *addr, int len, int type,
250		      struct hostent *resbuf, char *buf, int buflen,
251		      int *error)
252{
253	struct hostent *he;
254	int res;
255
256	he = lwres_getipnodebyaddr(addr, len, type, error);
257	if (he == NULL)
258		return (NULL);
259	res = copytobuf(he, resbuf, buf, buflen);
260	lwres_freehostent(he);
261	if (res != 0) {
262		errno = ERANGE;
263		return (NULL);
264	}
265	return (resbuf);
266}
267
268/*% Stub function.  Always returns failure. */
269struct hostent  *
270lwres_gethostent_r(struct hostent *resbuf, char *buf, int buflen, int *error) {
271	UNUSED(resbuf);
272	UNUSED(buf);
273	UNUSED(buflen);
274	*error = 0;
275	return (NULL);
276}
277
278/*% Stub function.  Always returns failure. */
279void
280lwres_sethostent_r(int stayopen) {
281	/*
282	 * Empty.
283	 */
284	UNUSED(stayopen);
285}
286
287/*% Stub function.  Always returns failure. */
288void
289lwres_endhostent_r(void) {
290	/*
291	 * Empty.
292	 */
293}
294
295static int
296copytobuf(struct hostent *he, struct hostent *hptr, char *buf, int buflen) {
297	char *cp;
298	char **ptr;
299	int i, n;
300	int nptr, len;
301
302	/*
303	 * Find out the amount of space required to store the answer.
304	 */
305	nptr = 2; /* NULL ptrs */
306	len = (int)((char *)LWRES_ALIGN(buf) - buf);
307	for (i = 0; he->h_addr_list[i]; i++, nptr++) {
308		len += he->h_length;
309	}
310	for (i = 0; he->h_aliases[i]; i++, nptr++) {
311		len += strlen(he->h_aliases[i]) + 1;
312	}
313	len += strlen(he->h_name) + 1;
314	len += nptr * sizeof(char*);
315
316	if (len > buflen) {
317		return (-1);
318	}
319
320	/*
321	 * Copy address size and type.
322	 */
323	hptr->h_addrtype = he->h_addrtype;
324	n = hptr->h_length = he->h_length;
325
326	ptr = (char **)LWRES_ALIGN(buf);
327	cp = (char *)LWRES_ALIGN(buf) + nptr * sizeof(char *);
328
329	/*
330	 * Copy address list.
331	 */
332	hptr->h_addr_list = ptr;
333	for (i = 0; he->h_addr_list[i]; i++, ptr++) {
334		memmove(cp, he->h_addr_list[i], n);
335		hptr->h_addr_list[i] = cp;
336		cp += n;
337	}
338	hptr->h_addr_list[i] = NULL;
339	ptr++;
340
341	/*
342	 * Copy official name.
343	 */
344	n = strlen(he->h_name) + 1;
345	strcpy(cp, he->h_name);
346	hptr->h_name = cp;
347	cp += n;
348
349	/*
350	 * Copy aliases.
351	 */
352	hptr->h_aliases = ptr;
353	for (i = 0; he->h_aliases[i]; i++) {
354		n = strlen(he->h_aliases[i]) + 1;
355		strcpy(cp, he->h_aliases[i]);
356		hptr->h_aliases[i] = cp;
357		cp += n;
358	}
359	hptr->h_aliases[i] = NULL;
360
361	return (0);
362}
363