xref: /dragonfly/crypto/libressl/crypto/bio/b_sock.c (revision ffe53622)
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.
4  *
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.
8  *
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).
15  *
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.
22  *
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)"
40  *
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.
52  *
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.]
57  */
58 
59 #include <sys/ioctl.h>
60 #include <sys/socket.h>
61 #include <string.h>
62 
63 #include <arpa/inet.h>
64 #include <netinet/in.h>
65 #include <netinet/tcp.h>
66 
67 #include <errno.h>
68 #include <limits.h>
69 #include <netdb.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73 
74 #include <openssl/bio.h>
75 #include <openssl/buffer.h>
76 #include <openssl/err.h>
77 
78 int
79 BIO_get_host_ip(const char *str, unsigned char *ip)
80 {
81 	int i;
82 	int err = 1;
83 	struct hostent *he;
84 
85 	if (inet_pton(AF_INET, str, ip) == 1)
86 		return (1);
87 
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;
94 	}
95 
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;
100 	}
101 	for (i = 0; i < 4; i++)
102 		ip[i] = he->h_addr_list[0][i];
103 	err = 0;
104 
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;
112 }
113 
114 int
115 BIO_get_port(const char *str, unsigned short *port_ptr)
116 {
117 	struct addrinfo *res = NULL;
118 	struct addrinfo hints = {
119 		.ai_family = AF_UNSPEC,
120 		.ai_socktype = SOCK_STREAM,
121 		.ai_flags = AI_PASSIVE,
122 	};
123 	long port;
124 	char *ep;
125 
126 	if (str == NULL) {
127 		BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_SPECIFIED);
128 		return (0);
129 	}
130 
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);
137 		}
138 		if (port < 0 || port > 65535) {
139 			BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
140 			return (0);
141 		}
142 		goto done;
143 	}
144 
145 	if (getaddrinfo(NULL, str, &hints, &res) == 0) {
146 		port = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
147 		goto done;
148 	}
149 
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);
168 	}
169 
170 done:
171 	if (res)
172 		freeaddrinfo(res);
173 	*port_ptr = (unsigned short)port;
174 	return (1);
175 }
176 
177 int
178 BIO_sock_error(int sock)
179 {
180 	socklen_t len;
181 	int err;
182 
183 	len = sizeof(err);
184 	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0)
185 		return (1);
186 	return (err);
187 }
188 
189 struct hostent *
190 BIO_gethostbyname(const char *name)
191 {
192 	return gethostbyname(name);
193 }
194 
195 int
196 BIO_socket_ioctl(int fd, long type, void *arg)
197 {
198 	int ret;
199 
200 	ret = ioctl(fd, type, arg);
201 	if (ret < 0)
202 		SYSerr(SYS_F_IOCTLSOCKET, errno);
203 	return (ret);
204 }
205 
206 int
207 BIO_get_accept_socket(char *host, int bind_mode)
208 {
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;
222 
223 	if (host == NULL || (str = strdup(host)) == NULL)
224 		return (-1);
225 
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;
234 		}
235 	}
236 	/* points at last ':', '::port' is special [see below] */
237 	if (p)
238 		*p++ = '\0';
239 	else
240 		p = h, h = NULL;
241 
242 	do {
243 		struct addrinfo *res, hint;
244 
245 		/*
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...
250 		 */
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;
261 			}
262 		}
263 
264 		if (getaddrinfo(h, p, &hint, &res))
265 			break;
266 
267 		addrlen = res->ai_addrlen <= sizeof(server) ?
268 		    res->ai_addrlen : sizeof(server);
269 		memcpy(&server, res->ai_addr, addrlen);
270 
271 		freeaddrinfo(res);
272 		goto again;
273 	} while (0);
274 
275 	if (!BIO_get_port(p, &port))
276 		goto err;
277 
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);
282 
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);
293 	}
294 
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;
303 	}
304 
305 	if (bind_mode == BIO_BIND_REUSEADDR) {
306 		int i = 1;
307 
308 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
309 		bind_mode = BIO_BIND_NORMAL;
310 	}
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;
326 			}
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;
336 				}
337 				/* else error */
338 			}
339 			/* else error */
340 		}
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;
346 	}
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;
353 	}
354 	ret = 1;
355 err:
356 	free(str);
357 	if ((ret == 0) && (s != -1)) {
358 		close(s);
359 		s = -1;
360 	}
361 	return (s);
362 }
363 
364 int
365 BIO_accept(int sock, char **addr)
366 {
367 	int ret = -1;
368 	unsigned long l;
369 	unsigned short port;
370 	char *p, *tmp;
371 
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;
380 
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;
390 	}
391 
392 	if (addr == NULL)
393 		goto end;
394 
395 	do {
396 		char   h[NI_MAXHOST], s[NI_MAXSERV];
397 		size_t nl;
398 
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;
413 		}
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;
429 		}
430 		*addr = p;
431 	}
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);
435 
436 end:
437 	return (ret);
438 }
439 
440 int
441 BIO_set_tcp_ndelay(int s, int on)
442 {
443 	return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);
444 }
445