diff options
author | beck <> | 2017-04-30 04:18:58 +0000 |
---|---|---|
committer | beck <> | 2017-04-30 04:18:58 +0000 |
commit | c24d2cd7917d204ee45c3ba761b4dd27fade46c5 (patch) | |
tree | bf86809bcc6cf7fd367721f42ad6a553db17f620 /src | |
parent | 453806043c6350970962ebbaa93e03df79df0d3d (diff) | |
download | openbsd-c24d2cd7917d204ee45c3ba761b4dd27fade46c5.tar.gz openbsd-c24d2cd7917d204ee45c3ba761b4dd27fade46c5.tar.bz2 openbsd-c24d2cd7917d204ee45c3ba761b4dd27fade46c5.zip |
Microsoft Windows hates BIO_get_accept_socket in portable. Fix it to
not be awful or have any claims on supporting ipv6 when it does so
very badly
ok jsing@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/bio/b_sock.c | 150 |
1 files changed, 35 insertions, 115 deletions
diff --git a/src/lib/libcrypto/bio/b_sock.c b/src/lib/libcrypto/bio/b_sock.c index 0cc570b66f..cb5549434f 100644 --- a/src/lib/libcrypto/bio/b_sock.c +++ b/src/lib/libcrypto/bio/b_sock.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: b_sock.c,v 1.63 2017/01/29 17:49:22 beck Exp $ */ | 1 | /* $OpenBSD: b_sock.c,v 1.64 2017/04/30 04:18:58 beck Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -168,151 +168,71 @@ BIO_socket_ioctl(int fd, long type, void *arg) | |||
168 | int | 168 | int |
169 | BIO_get_accept_socket(char *host, int bind_mode) | 169 | BIO_get_accept_socket(char *host, int bind_mode) |
170 | { | 170 | { |
171 | int ret = 0; | 171 | struct addrinfo hints = { |
172 | union { | 172 | .ai_family = AF_INET, |
173 | struct sockaddr sa; | 173 | .ai_socktype = SOCK_STREAM, |
174 | struct sockaddr_in sa_in; | 174 | .ai_flags = AI_PASSIVE, |
175 | struct sockaddr_in6 sa_in6; | 175 | }; |
176 | } server, client; | 176 | struct addrinfo *res = NULL; |
177 | int s = -1, cs, addrlen; | 177 | char *h, *p, *str = NULL; |
178 | unsigned char ip[4]; | 178 | int error, ret = 0, s = -1; |
179 | unsigned short port; | ||
180 | char *str = NULL, *e; | ||
181 | char *h, *p; | ||
182 | unsigned long l; | ||
183 | int err_num; | ||
184 | 179 | ||
185 | if (host == NULL || (str = strdup(host)) == NULL) | 180 | if (host == NULL || (str = strdup(host)) == NULL) |
186 | return (-1); | 181 | return (-1); |
187 | 182 | p = NULL; | |
188 | h = p = NULL; | ||
189 | h = str; | 183 | h = str; |
190 | for (e = str; *e; e++) { | 184 | if ((p = strrchr(str, ':')) == NULL) { |
191 | if (*e == ':') { | 185 | BIOerror(BIO_R_NO_PORT_SPECIFIED); |
192 | p = e; | 186 | goto err; |
193 | } else if (*e == '/') { | ||
194 | *e = '\0'; | ||
195 | break; | ||
196 | } | ||
197 | } | 187 | } |
198 | /* points at last ':', '::port' is special [see below] */ | 188 | *p++ = '\0'; |
199 | if (p) | 189 | if (*p == '\0') { |
200 | *p++ = '\0'; | 190 | BIOerror(BIO_R_NO_PORT_SPECIFIED); |
201 | else | ||
202 | p = h, h = NULL; | ||
203 | |||
204 | do { | ||
205 | struct addrinfo *res, hint; | ||
206 | |||
207 | /* | ||
208 | * '::port' enforces IPv6 wildcard listener. Some OSes, | ||
209 | * e.g. Solaris, default to IPv6 without any hint. Also | ||
210 | * note that commonly IPv6 wildchard socket can service | ||
211 | * IPv4 connections just as well... | ||
212 | */ | ||
213 | memset(&hint, 0, sizeof(hint)); | ||
214 | hint.ai_flags = AI_PASSIVE; | ||
215 | if (h) { | ||
216 | if (strchr(h, ':')) { | ||
217 | if (h[1] == '\0') | ||
218 | h = NULL; | ||
219 | hint.ai_family = AF_INET6; | ||
220 | } else if (h[0] == '*' && h[1] == '\0') { | ||
221 | hint.ai_family = AF_INET; | ||
222 | h = NULL; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | if (getaddrinfo(h, p, &hint, &res)) | ||
227 | break; | ||
228 | |||
229 | addrlen = res->ai_addrlen <= sizeof(server) ? | ||
230 | res->ai_addrlen : sizeof(server); | ||
231 | memcpy(&server, res->ai_addr, addrlen); | ||
232 | |||
233 | freeaddrinfo(res); | ||
234 | goto again; | ||
235 | } while (0); | ||
236 | |||
237 | if (!BIO_get_port(p, &port)) | ||
238 | goto err; | 191 | goto err; |
192 | } | ||
193 | if (*h == '\0' || strcmp(h, "*") == 0) | ||
194 | h = NULL; | ||
239 | 195 | ||
240 | memset((char *)&server, 0, sizeof(server)); | 196 | if ((error = getaddrinfo(h, p, &hints, &res)) != 0) { |
241 | server.sa_in.sin_family = AF_INET; | 197 | ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h, p, |
242 | server.sa_in.sin_port = htons(port); | 198 | gai_strerror(error)); |
243 | addrlen = sizeof(server.sa_in); | 199 | goto err; |
244 | 200 | } | |
245 | if (h == NULL || strcmp(h, "*") == 0) | 201 | if (h == NULL) { |
246 | server.sa_in.sin_addr.s_addr = INADDR_ANY; | 202 | struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr; |
247 | else { | 203 | sin->sin_addr.s_addr = INADDR_ANY; |
248 | if (!BIO_get_host_ip(h, &(ip[0]))) | ||
249 | goto err; | ||
250 | l = (unsigned long)((unsigned long)ip[0]<<24L)| | ||
251 | ((unsigned long)ip[1]<<16L)| | ||
252 | ((unsigned long)ip[2]<< 8L)| | ||
253 | ((unsigned long)ip[3]); | ||
254 | server.sa_in.sin_addr.s_addr = htonl(l); | ||
255 | } | 204 | } |
256 | 205 | ||
257 | again: | 206 | s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
258 | s = socket(server.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); | ||
259 | if (s == -1) { | 207 | if (s == -1) { |
260 | SYSerror(errno); | 208 | SYSerror(errno); |
261 | ERR_asprintf_error_data("port='%s'", host); | 209 | ERR_asprintf_error_data("host='%s'", host); |
262 | BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET); | 210 | BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET); |
263 | goto err; | 211 | goto err; |
264 | } | 212 | } |
265 | |||
266 | if (bind_mode == BIO_BIND_REUSEADDR) { | 213 | if (bind_mode == BIO_BIND_REUSEADDR) { |
267 | int i = 1; | 214 | int i = 1; |
268 | 215 | ||
269 | ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); | 216 | ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); |
270 | bind_mode = BIO_BIND_NORMAL; | 217 | bind_mode = BIO_BIND_NORMAL; |
271 | } | 218 | } |
272 | if (bind(s, &server.sa, addrlen) == -1) { | 219 | if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { |
273 | err_num = errno; | 220 | SYSerror(errno); |
274 | if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) && | 221 | ERR_asprintf_error_data("host='%s'", host); |
275 | (err_num == EADDRINUSE)) { | ||
276 | client = server; | ||
277 | if (h == NULL || strcmp(h, "*") == 0) { | ||
278 | if (client.sa.sa_family == AF_INET6) { | ||
279 | memset(&client.sa_in6.sin6_addr, 0, | ||
280 | sizeof(client.sa_in6.sin6_addr)); | ||
281 | client.sa_in6.sin6_addr.s6_addr[15] = 1; | ||
282 | } else if (client.sa.sa_family == AF_INET) { | ||
283 | client.sa_in.sin_addr.s_addr = | ||
284 | htonl(0x7F000001); | ||
285 | } else | ||
286 | goto err; | ||
287 | } | ||
288 | cs = socket(client.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); | ||
289 | if (cs != -1) { | ||
290 | int ii; | ||
291 | ii = connect(cs, &client.sa, addrlen); | ||
292 | close(cs); | ||
293 | if (ii == -1) { | ||
294 | bind_mode = BIO_BIND_REUSEADDR; | ||
295 | close(s); | ||
296 | goto again; | ||
297 | } | ||
298 | /* else error */ | ||
299 | } | ||
300 | /* else error */ | ||
301 | } | ||
302 | SYSerror(err_num); | ||
303 | ERR_asprintf_error_data("port='%s'", host); | ||
304 | BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET); | 222 | BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET); |
305 | goto err; | 223 | goto err; |
306 | } | 224 | } |
307 | if (listen(s, SOMAXCONN) == -1) { | 225 | if (listen(s, SOMAXCONN) == -1) { |
308 | SYSerror(errno); | 226 | SYSerror(errno); |
309 | ERR_asprintf_error_data("port='%s'", host); | 227 | ERR_asprintf_error_data("host='%s'", host); |
310 | BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET); | 228 | BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET); |
311 | goto err; | 229 | goto err; |
312 | } | 230 | } |
313 | ret = 1; | 231 | ret = 1; |
232 | |||
314 | err: | 233 | err: |
315 | free(str); | 234 | free(str); |
235 | freeaddrinfo(res); | ||
316 | if ((ret == 0) && (s != -1)) { | 236 | if ((ret == 0) && (s != -1)) { |
317 | close(s); | 237 | close(s); |
318 | s = -1; | 238 | s = -1; |