Import LibreSSL v2.4.2 to vendor branch
[dragonfly.git] / crypto / libressl / crypto / bio / b_sock.c
blob0290fb94393e7da75a1ab2c5cc506c654ce0f7f6
1 /* $OpenBSD: b_sock.c,v 1.60 2014/12/03 21:55:51 bcook Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * "This product includes cryptographic software written by
34 * Eric Young (eay@cryptsoft.com)"
35 * The word 'cryptographic' can be left out if the rouines from the library
36 * being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 * the apps directory (application code) you must include an acknowledgement:
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed. i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
59 #include <sys/ioctl.h>
60 #include <sys/socket.h>
61 #include <string.h>
63 #include <arpa/inet.h>
64 #include <netinet/in.h>
65 #include <netinet/tcp.h>
67 #include <errno.h>
68 #include <limits.h>
69 #include <netdb.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <unistd.h>
74 #include <openssl/bio.h>
75 #include <openssl/buffer.h>
76 #include <openssl/err.h>
78 int
79 BIO_get_host_ip(const char *str, unsigned char *ip)
81 int i;
82 int err = 1;
83 struct hostent *he;
85 if (inet_pton(AF_INET, str, ip) == 1)
86 return (1);
88 /* do a gethostbyname */
89 CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
90 he = BIO_gethostbyname(str);
91 if (he == NULL) {
92 BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP);
93 goto err;
96 if (he->h_addrtype != AF_INET) {
97 BIOerr(BIO_F_BIO_GET_HOST_IP,
98 BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
99 goto err;
101 for (i = 0; i < 4; i++)
102 ip[i] = he->h_addr_list[0][i];
103 err = 0;
105 err:
106 CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
107 if (err) {
108 ERR_asprintf_error_data("host=%s", str);
109 return 0;
110 } else
111 return 1;
115 BIO_get_port(const char *str, unsigned short *port_ptr)
117 struct addrinfo *res = NULL;
118 struct addrinfo hints = {
119 .ai_family = AF_UNSPEC,
120 .ai_socktype = SOCK_STREAM,
121 .ai_flags = AI_PASSIVE,
123 long port;
124 char *ep;
126 if (str == NULL) {
127 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_SPECIFIED);
128 return (0);
131 errno = 0;
132 port = strtol(str, &ep, 10);
133 if (str[0] != '\0' && *ep == '\0') {
134 if (errno == ERANGE && (port == LONG_MAX || port == LONG_MIN)) {
135 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
136 return (0);
138 if (port < 0 || port > 65535) {
139 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
140 return (0);
142 goto done;
145 if (getaddrinfo(NULL, str, &hints, &res) == 0) {
146 port = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
147 goto done;
150 if (strcmp(str, "http") == 0)
151 port = 80;
152 else if (strcmp(str, "telnet") == 0)
153 port = 23;
154 else if (strcmp(str, "socks") == 0)
155 port = 1080;
156 else if (strcmp(str, "https") == 0)
157 port = 443;
158 else if (strcmp(str, "ssl") == 0)
159 port = 443;
160 else if (strcmp(str, "ftp") == 0)
161 port = 21;
162 else if (strcmp(str, "gopher") == 0)
163 port = 70;
164 else {
165 SYSerr(SYS_F_GETSERVBYNAME, errno);
166 ERR_asprintf_error_data("service='%s'", str);
167 return (0);
170 done:
171 if (res)
172 freeaddrinfo(res);
173 *port_ptr = (unsigned short)port;
174 return (1);
178 BIO_sock_error(int sock)
180 socklen_t len;
181 int err;
183 len = sizeof(err);
184 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0)
185 return (1);
186 return (err);
189 struct hostent *
190 BIO_gethostbyname(const char *name)
192 return gethostbyname(name);
196 BIO_socket_ioctl(int fd, long type, void *arg)
198 int ret;
200 ret = ioctl(fd, type, arg);
201 if (ret < 0)
202 SYSerr(SYS_F_IOCTLSOCKET, errno);
203 return (ret);
207 BIO_get_accept_socket(char *host, int bind_mode)
209 int ret = 0;
210 union {
211 struct sockaddr sa;
212 struct sockaddr_in sa_in;
213 struct sockaddr_in6 sa_in6;
214 } server, client;
215 int s = -1, cs, addrlen;
216 unsigned char ip[4];
217 unsigned short port;
218 char *str = NULL, *e;
219 char *h, *p;
220 unsigned long l;
221 int err_num;
223 if (host == NULL || (str = strdup(host)) == NULL)
224 return (-1);
226 h = p = NULL;
227 h = str;
228 for (e = str; *e; e++) {
229 if (*e == ':') {
230 p = e;
231 } else if (*e == '/') {
232 *e = '\0';
233 break;
236 /* points at last ':', '::port' is special [see below] */
237 if (p)
238 *p++ = '\0';
239 else
240 p = h, h = NULL;
242 do {
243 struct addrinfo *res, hint;
246 * '::port' enforces IPv6 wildcard listener. Some OSes,
247 * e.g. Solaris, default to IPv6 without any hint. Also
248 * note that commonly IPv6 wildchard socket can service
249 * IPv4 connections just as well...
251 memset(&hint, 0, sizeof(hint));
252 hint.ai_flags = AI_PASSIVE;
253 if (h) {
254 if (strchr(h, ':')) {
255 if (h[1] == '\0')
256 h = NULL;
257 hint.ai_family = AF_INET6;
258 } else if (h[0] == '*' && h[1] == '\0') {
259 hint.ai_family = AF_INET;
260 h = NULL;
264 if (getaddrinfo(h, p, &hint, &res))
265 break;
267 addrlen = res->ai_addrlen <= sizeof(server) ?
268 res->ai_addrlen : sizeof(server);
269 memcpy(&server, res->ai_addr, addrlen);
271 freeaddrinfo(res);
272 goto again;
273 } while (0);
275 if (!BIO_get_port(p, &port))
276 goto err;
278 memset((char *)&server, 0, sizeof(server));
279 server.sa_in.sin_family = AF_INET;
280 server.sa_in.sin_port = htons(port);
281 addrlen = sizeof(server.sa_in);
283 if (h == NULL || strcmp(h, "*") == 0)
284 server.sa_in.sin_addr.s_addr = INADDR_ANY;
285 else {
286 if (!BIO_get_host_ip(h, &(ip[0])))
287 goto err;
288 l = (unsigned long)((unsigned long)ip[0]<<24L)|
289 ((unsigned long)ip[1]<<16L)|
290 ((unsigned long)ip[2]<< 8L)|
291 ((unsigned long)ip[3]);
292 server.sa_in.sin_addr.s_addr = htonl(l);
295 again:
296 s = socket(server.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
297 if (s == -1) {
298 SYSerr(SYS_F_SOCKET, errno);
299 ERR_asprintf_error_data("port='%s'", host);
300 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,
301 BIO_R_UNABLE_TO_CREATE_SOCKET);
302 goto err;
305 if (bind_mode == BIO_BIND_REUSEADDR) {
306 int i = 1;
308 ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
309 bind_mode = BIO_BIND_NORMAL;
311 if (bind(s, &server.sa, addrlen) == -1) {
312 err_num = errno;
313 if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
314 (err_num == EADDRINUSE)) {
315 client = server;
316 if (h == NULL || strcmp(h, "*") == 0) {
317 if (client.sa.sa_family == AF_INET6) {
318 memset(&client.sa_in6.sin6_addr, 0,
319 sizeof(client.sa_in6.sin6_addr));
320 client.sa_in6.sin6_addr.s6_addr[15] = 1;
321 } else if (client.sa.sa_family == AF_INET) {
322 client.sa_in.sin_addr.s_addr =
323 htonl(0x7F000001);
324 } else
325 goto err;
327 cs = socket(client.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
328 if (cs != -1) {
329 int ii;
330 ii = connect(cs, &client.sa, addrlen);
331 close(cs);
332 if (ii == -1) {
333 bind_mode = BIO_BIND_REUSEADDR;
334 close(s);
335 goto again;
337 /* else error */
339 /* else error */
341 SYSerr(SYS_F_BIND, err_num);
342 ERR_asprintf_error_data("port='%s'", host);
343 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,
344 BIO_R_UNABLE_TO_BIND_SOCKET);
345 goto err;
347 if (listen(s, SOMAXCONN) == -1) {
348 SYSerr(SYS_F_BIND, errno);
349 ERR_asprintf_error_data("port='%s'", host);
350 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,
351 BIO_R_UNABLE_TO_LISTEN_SOCKET);
352 goto err;
354 ret = 1;
355 err:
356 free(str);
357 if ((ret == 0) && (s != -1)) {
358 close(s);
359 s = -1;
361 return (s);
365 BIO_accept(int sock, char **addr)
367 int ret = -1;
368 unsigned long l;
369 unsigned short port;
370 char *p, *tmp;
372 struct {
373 socklen_t len;
374 union {
375 struct sockaddr sa;
376 struct sockaddr_in sa_in;
377 struct sockaddr_in6 sa_in6;
378 } from;
379 } sa;
381 sa.len = sizeof(sa.from);
382 memset(&sa.from, 0, sizeof(sa.from));
383 ret = accept(sock, &sa.from.sa, &sa.len);
384 if (ret == -1) {
385 if (BIO_sock_should_retry(ret))
386 return -2;
387 SYSerr(SYS_F_ACCEPT, errno);
388 BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
389 goto end;
392 if (addr == NULL)
393 goto end;
395 do {
396 char h[NI_MAXHOST], s[NI_MAXSERV];
397 size_t nl;
399 if (getnameinfo(&sa.from.sa, sa.len, h, sizeof(h),
400 s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV))
401 break;
402 nl = strlen(h) + strlen(s) + 2;
403 p = *addr;
404 if (p)
405 *p = '\0';
406 if (!(tmp = realloc(p, nl))) {
407 close(ret);
408 ret = -1;
409 free(p);
410 *addr = NULL;
411 BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
412 goto end;
414 p = tmp;
415 *addr = p;
416 snprintf(*addr, nl, "%s:%s", h, s);
417 goto end;
418 } while (0);
419 if (sa.from.sa.sa_family != AF_INET)
420 goto end;
421 l = ntohl(sa.from.sa_in.sin_addr.s_addr);
422 port = ntohs(sa.from.sa_in.sin_port);
423 if (*addr == NULL) {
424 if ((p = malloc(24)) == NULL) {
425 close(ret);
426 ret = -1;
427 BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
428 goto end;
430 *addr = p;
432 snprintf(*addr, 24, "%d.%d.%d.%d:%d",
433 (unsigned char)(l >> 24L) & 0xff, (unsigned char)(l >> 16L) & 0xff,
434 (unsigned char)(l >> 8L) & 0xff, (unsigned char)(l) & 0xff, port);
436 end:
437 return (ret);
441 BIO_set_tcp_ndelay(int s, int on)
443 return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);