xref: /openbsd-src/lib/libc/asr/gethostnamadr.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: gethostnamadr.c,v 1.11 2014/03/26 18:13:15 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 <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netdb.h>
22 
23 #include <asr.h>
24 #include <errno.h>
25 #include <resolv.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 static int _gethostbyname(const char *, int, struct hostent *, char *, size_t,
31     int *);
32 static int _fillhostent(const struct hostent *, struct hostent *, char *,
33     size_t);
34 
35 static struct hostent	 _hostent;
36 static char		 _entbuf[4096];
37 
38 static char *_empty[] = { NULL, };
39 
40 static int
41 _fillhostent(const struct hostent *h, struct hostent *r, char *buf, size_t len)
42 {
43 	char	**ptr, *end, *pos;
44 	size_t	n, i;
45 	int	naliases, naddrs;
46 
47 	bzero(buf, len);
48 	bzero(r, sizeof(*r));
49 	r->h_aliases = _empty;
50 	r->h_addr_list = _empty;
51 
52 	end = buf + len;
53 	ptr = (char **)ALIGN(buf);
54 
55 	if ((char *)ptr >= end)
56 		return (ERANGE);
57 
58 	for (naliases = 0; h->h_aliases[naliases]; naliases++)
59 		;
60 	for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++)
61 		;
62 
63 	pos = (char *)(ptr + (naliases + 1) + (naddrs + 1));
64 	if (pos >= end)
65 		return (ERANGE);
66 
67 	r->h_name = NULL;
68 	r->h_addrtype = h->h_addrtype;
69 	r->h_length = h->h_length;
70 	r->h_aliases = ptr;
71 	r->h_addr_list = ptr + naliases + 1;
72 
73 	n = strlcpy(pos, h->h_name, end - pos);
74 	if (n >= end - pos)
75 		return (ERANGE);
76 	r->h_name = pos;
77 	pos += n + 1;
78 
79 	for (i = 0; i < naliases; i++) {
80 		n = strlcpy(pos, h->h_aliases[i], end - pos);
81 		if (n >= end - pos)
82 			return (ERANGE);
83 		r->h_aliases[i] = pos;
84 		pos += n + 1;
85 	}
86 
87 	pos = (char *)ALIGN(pos);
88 	if (pos >= end)
89 		return (ERANGE);
90 
91 	for (i = 0; i < naddrs; i++) {
92 		if (r->h_length > end - pos)
93 			return (ERANGE);
94 		memmove(pos, h->h_addr_list[i], r->h_length);
95 		r->h_addr_list[i] = pos;
96 		pos += r->h_length;
97 	}
98 
99 	return (0);
100 }
101 
102 static int
103 _gethostbyname(const char *name, int af, struct hostent *ret, char *buf,
104     size_t buflen, int *h_errnop)
105 {
106 	struct asr_query *as;
107 	struct asr_result ar;
108 	int r;
109 
110 	if (af == -1)
111 		as = gethostbyname_async(name, NULL);
112 	else
113 		as = gethostbyname2_async(name, af, NULL);
114 
115 	if (as == NULL)
116 		return (errno);
117 
118 	asr_run_sync(as, &ar);
119 
120 	errno = ar.ar_errno;
121 	*h_errnop = ar.ar_h_errno;
122 	if (ar.ar_hostent == NULL)
123 		return (0);
124 
125 	r = _fillhostent(ar.ar_hostent, ret, buf, buflen);
126 	free(ar.ar_hostent);
127 
128 	return (r);
129 }
130 
131 struct hostent *
132 gethostbyname(const char *name)
133 {
134 	struct hostent	*h;
135 
136 	res_init();
137 
138 	if (_res.options & RES_USE_INET6 &&
139 	    (h = gethostbyname2(name, AF_INET6)))
140 		return (h);
141 
142 	return gethostbyname2(name, AF_INET);
143 }
144 
145 struct hostent *
146 gethostbyname2(const char *name, int af)
147 {
148 	int	r;
149 
150 	res_init();
151 
152 	r = _gethostbyname(name, af, &_hostent, _entbuf, sizeof(_entbuf),
153 	    &h_errno);
154 	if (r) {
155 		h_errno = NETDB_INTERNAL;
156 		errno = r;
157 	}
158 
159 	if (h_errno)
160 		return (NULL);
161 
162 	return (&_hostent);
163 }
164 
165 struct hostent *
166 gethostbyaddr(const void *addr, socklen_t len, int af)
167 {
168 	struct asr_query *as;
169 	struct asr_result ar;
170 	int r;
171 
172 	res_init();
173 
174 	as = gethostbyaddr_async(addr, len, af, NULL);
175 	if (as == NULL) {
176 		h_errno = NETDB_INTERNAL;
177 		return (NULL);
178 	}
179 
180 	asr_run_sync(as, &ar);
181 
182 	errno = ar.ar_errno;
183 	h_errno = ar.ar_h_errno;
184 	if (ar.ar_hostent == NULL)
185 		return (NULL);
186 
187 	r = _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf));
188 	free(ar.ar_hostent);
189 
190 	if (r) {
191 		h_errno = NETDB_INTERNAL;
192 		errno = r;
193 		return (NULL);
194 	}
195 
196 	return (&_hostent);
197 }
198