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