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
_fillhostent(const struct hostent * h,struct hostent * r,char * buf,size_t len)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
_gethostbyname(const char * name,int af,struct hostent * ret,char * buf,size_t buflen,int * h_errnop)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 *
gethostbyname(const char * name)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 *
gethostbyname2(const char * name,int af)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 *
gethostbyaddr(const void * addr,socklen_t len,int af)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