xref: /openbsd-src/lib/libc/asr/gethostnamadr.c (revision 5be03f8ff4bfdb72cf93ab0aee9dc90ee972fe34)
1 /*	$OpenBSD: gethostnamadr.c,v 1.10 2014/03/25 19:48:11 eric Exp $	*/
2 /*
3  * Copyright (c) 2012,2013 Eric Faurot <eric@openbsd.org>
4  *
5  * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 
21 #include <errno.h>
22 #include <resolv.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "asr.h"
28 
29 static int _gethostbyname(const char *, int, struct hostent *, char *, size_t,
30     int *);
31 static int _fillhostent(const struct hostent *, struct hostent *, char *,
32     size_t);
33 
34 static struct hostent	 _hostent;
35 static char		 _entbuf[4096];
36 
37 static char *_empty[] = { NULL, };
38 
39 static int
40 _fillhostent(const struct hostent *h, struct hostent *r, char *buf, size_t len)
41 {
42 	char	**ptr, *end, *pos;
43 	size_t	n, i;
44 	int	naliases, naddrs;
45 
46 	bzero(buf, len);
47 	bzero(r, sizeof(*r));
48 	r->h_aliases = _empty;
49 	r->h_addr_list = _empty;
50 
51 	end = buf + len;
52 	ptr = (char **)ALIGN(buf);
53 
54 	if ((char *)ptr >= end)
55 		return (ERANGE);
56 
57 	for (naliases = 0; h->h_aliases[naliases]; naliases++)
58 		;
59 	for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++)
60 		;
61 
62 	pos = (char *)(ptr + (naliases + 1) + (naddrs + 1));
63 	if (pos >= end)
64 		return (ERANGE);
65 
66 	r->h_name = NULL;
67 	r->h_addrtype = h->h_addrtype;
68 	r->h_length = h->h_length;
69 	r->h_aliases = ptr;
70 	r->h_addr_list = ptr + naliases + 1;
71 
72 	n = strlcpy(pos, h->h_name, end - pos);
73 	if (n >= end - pos)
74 		return (ERANGE);
75 	r->h_name = pos;
76 	pos += n + 1;
77 
78 	for (i = 0; i < naliases; i++) {
79 		n = strlcpy(pos, h->h_aliases[i], end - pos);
80 		if (n >= end - pos)
81 			return (ERANGE);
82 		r->h_aliases[i] = pos;
83 		pos += n + 1;
84 	}
85 
86 	pos = (char *)ALIGN(pos);
87 	if (pos >= end)
88 		return (ERANGE);
89 
90 	for (i = 0; i < naddrs; i++) {
91 		if (r->h_length > end - pos)
92 			return (ERANGE);
93 		memmove(pos, h->h_addr_list[i], r->h_length);
94 		r->h_addr_list[i] = pos;
95 		pos += r->h_length;
96 	}
97 
98 	return (0);
99 }
100 
101 static int
102 _gethostbyname(const char *name, int af, struct hostent *ret, char *buf,
103     size_t buflen, int *h_errnop)
104 {
105 	struct asr_query *as;
106 	struct asr_result ar;
107 	int r;
108 
109 	if (af == -1)
110 		as = gethostbyname_async(name, NULL);
111 	else
112 		as = gethostbyname2_async(name, af, NULL);
113 
114 	if (as == NULL)
115 		return (errno);
116 
117 	asr_run_sync(as, &ar);
118 
119 	errno = ar.ar_errno;
120 	*h_errnop = ar.ar_h_errno;
121 	if (ar.ar_hostent == NULL)
122 		return (0);
123 
124 	r = _fillhostent(ar.ar_hostent, ret, buf, buflen);
125 	free(ar.ar_hostent);
126 
127 	return (r);
128 }
129 
130 struct hostent *
131 gethostbyname(const char *name)
132 {
133 	struct hostent	*h;
134 
135 	res_init();
136 
137 	if (_res.options & RES_USE_INET6 &&
138 	    (h = gethostbyname2(name, AF_INET6)))
139 		return (h);
140 
141 	return gethostbyname2(name, AF_INET);
142 }
143 
144 struct hostent *
145 gethostbyname2(const char *name, int af)
146 {
147 	int	r;
148 
149 	res_init();
150 
151 	r = _gethostbyname(name, af, &_hostent, _entbuf, sizeof(_entbuf),
152 	    &h_errno);
153 	if (r) {
154 		h_errno = NETDB_INTERNAL;
155 		errno = r;
156 	}
157 
158 	if (h_errno)
159 		return (NULL);
160 
161 	return (&_hostent);
162 }
163 
164 struct hostent *
165 gethostbyaddr(const void *addr, socklen_t len, int af)
166 {
167 	struct asr_query *as;
168 	struct asr_result ar;
169 	int r;
170 
171 	res_init();
172 
173 	as = gethostbyaddr_async(addr, len, af, NULL);
174 	if (as == NULL) {
175 		h_errno = NETDB_INTERNAL;
176 		return (NULL);
177 	}
178 
179 	asr_run_sync(as, &ar);
180 
181 	errno = ar.ar_errno;
182 	h_errno = ar.ar_h_errno;
183 	if (ar.ar_hostent == NULL)
184 		return (NULL);
185 
186 	r = _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf));
187 	free(ar.ar_hostent);
188 
189 	if (r) {
190 		h_errno = NETDB_INTERNAL;
191 		errno = r;
192 		return (NULL);
193 	}
194 
195 	return (&_hostent);
196 }
197