xref: /openbsd-src/lib/libcrypto/bio/b_sock.c (revision 37aae7a4401c06f6f0d96f20113c2905b525b39e)
1 /* $OpenBSD: b_sock.c,v 1.42 2014/06/24 17:30:00 jsing 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 
62 #include <netinet/in.h>
63 #include <netinet/tcp.h>
64 
65 #include <errno.h>
66 #include <netdb.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <unistd.h>
70 
71 #include <openssl/bio.h>
72 
73 #include "cryptlib.h"
74 
75 static int get_ip(const char *str, unsigned char *ip);
76 
77 int
78 BIO_get_host_ip(const char *str, unsigned char *ip)
79 {
80 	int i;
81 	int err = 1;
82 	int locked = 0;
83 	struct hostent *he;
84 
85 	i = get_ip(str, ip);
86 	if (i < 0) {
87 		BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_INVALID_IP_ADDRESS);
88 		goto err;
89 	}
90 
91 	/* If the string actually contained an IP address, we need not do
92 	   anything more */
93 	if (i > 0)
94 		return (1);
95 
96 	/* do a gethostbyname */
97 	CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
98 	locked = 1;
99 	he = BIO_gethostbyname(str);
100 	if (he == NULL) {
101 		BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP);
102 		goto err;
103 	}
104 
105 	/* cast to short because of win16 winsock definition */
106 	if ((short)he->h_addrtype != AF_INET) {
107 		BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
108 		goto err;
109 	}
110 	for (i = 0; i < 4; i++)
111 		ip[i] = he->h_addr_list[0][i];
112 	err = 0;
113 
114 err:
115 	if (locked)
116 		CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
117 	if (err) {
118 		ERR_asprintf_error_data("host=%s", str);
119 		return 0;
120 	} else
121 		return 1;
122 }
123 
124 int
125 BIO_get_port(const char *str, unsigned short *port_ptr)
126 {
127 	struct servent *s;
128 	long port;
129 	char *ep;
130 
131 	if (str == NULL) {
132 		BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_SPECIFIED);
133 		return (0);
134 	}
135 
136 	errno = 0;
137 	port = strtol(str, &ep, 10);
138 	if (str[0] != '\0' && *ep == '\0') {
139 		if (errno == ERANGE && (port == LONG_MAX || port == LONG_MIN)) {
140 			BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
141 			return (0);
142 		}
143 		if (port < 0 || port > 65535) {
144 			BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
145 			return (0);
146 		}
147 
148 		*port_ptr = (unsigned short)port;
149 		return (1);
150 	}
151 
152 	CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME);
153 	s = getservbyname(str, "tcp");
154 	if (s != NULL)
155 		*port_ptr = ntohs((unsigned short)s->s_port);
156 	CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME);
157 
158 	if (s == NULL) {
159 		if (strcmp(str, "http") == 0)
160 			*port_ptr = 80;
161 		else if (strcmp(str, "telnet") == 0)
162 			*port_ptr = 23;
163 		else if (strcmp(str, "socks") == 0)
164 			*port_ptr = 1080;
165 		else if (strcmp(str, "https") == 0)
166 			*port_ptr = 443;
167 		else if (strcmp(str, "ssl") == 0)
168 			*port_ptr = 443;
169 		else if (strcmp(str, "ftp") == 0)
170 			*port_ptr = 21;
171 		else if (strcmp(str, "gopher") == 0)
172 			*port_ptr = 70;
173 		else {
174 			SYSerr(SYS_F_GETSERVBYNAME, errno);
175 			ERR_asprintf_error_data("service='%s'", str);
176 			return (0);
177 		}
178 	}
179 	return (1);
180 }
181 
182 int
183 BIO_sock_error(int sock)
184 {
185 	int j, i;
186 	int size;
187 
188 	size = sizeof(int);
189 	/* Note: under Windows the third parameter is of type (char *)
190 	 * whereas under other systems it is (void *) if you don't have
191 	 * a cast it will choke the compiler: if you do have a cast then
192 	 * you can either go for (char *) or (void *).
193 	 */
194 	i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, (void *)&size);
195 	if (i < 0)
196 		return (1);
197 	else
198 		return (j);
199 }
200 
201 struct hostent *
202 BIO_gethostbyname(const char *name)
203 {
204 	return gethostbyname(name);
205 }
206 
207 int
208 BIO_sock_init(void)
209 {
210 	return (1);
211 }
212 
213 void
214 BIO_sock_cleanup(void)
215 {
216 }
217 
218 int
219 BIO_socket_ioctl(int fd, long type, void *arg)
220 {
221 	int i;
222 
223 #  define ARG arg
224 
225 	i = ioctl(fd, type, ARG);
226 	if (i < 0)
227 		SYSerr(SYS_F_IOCTLSOCKET, errno);
228 	return (i);
229 }
230 
231 /* The reason I have implemented this instead of using sscanf is because
232  * Visual C 1.52c gives an unresolved external when linking a DLL :-( */
233 static int
234 get_ip(const char *str, unsigned char ip[4])
235 {
236 	unsigned int tmp[4];
237 	int num = 0, c, ok = 0;
238 
239 	tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
240 
241 	for (;;) {
242 		c= *(str++);
243 		if ((c >= '0') && (c <= '9')) {
244 			ok = 1;
245 			tmp[num] = tmp[num]*10 + c-'0';
246 			if (tmp[num] > 255)
247 				return (0);
248 		} else if (c == '.') {
249 			if (!ok)
250 				return (-1);
251 			if (num == 3)
252 				return (0);
253 			num++;
254 			ok = 0;
255 		} else if (c == '\0' && (num == 3) && ok)
256 			break;
257 		else
258 			return (0);
259 	}
260 	ip[0] = tmp[0];
261 	ip[1] = tmp[1];
262 	ip[2] = tmp[2];
263 	ip[3] = tmp[3];
264 	return (1);
265 }
266 
267 int
268 BIO_get_accept_socket(char *host, int bind_mode)
269 {
270 	int ret = 0;
271 	union {
272 		struct sockaddr sa;
273 		struct sockaddr_in sa_in;
274 		struct sockaddr_in6 sa_in6;
275 	} server, client;
276 	int s = -1, cs, addrlen;
277 	unsigned char ip[4];
278 	unsigned short port;
279 	char *str = NULL, *e;
280 	char *h, *p;
281 	unsigned long l;
282 	int err_num;
283 
284 	if ((str = BUF_strdup(host)) == NULL)
285 		return (-1);
286 
287 	h = p = NULL;
288 	h = str;
289 	for (e = str; *e; e++) {
290 		if (*e == ':') {
291 			p = e;
292 		} else if (*e == '/') {
293 			*e = '\0';
294 			break;
295 		}
296 	}
297 	if (p)
298 		*p++='\0';	/* points at last ':', '::port' is special [see below] */
299 	else
300 		p = h, h = NULL;
301 
302 #ifdef EAI_FAMILY
303 	do {
304 		struct addrinfo *res, hint;
305 
306 		/* '::port' enforces IPv6 wildcard listener. Some OSes,
307 		 * e.g. Solaris, default to IPv6 without any hint. Also
308 		 * note that commonly IPv6 wildchard socket can service
309 		 * IPv4 connections just as well...  */
310 		memset(&hint, 0, sizeof(hint));
311 		hint.ai_flags = AI_PASSIVE;
312 		if (h) {
313 			if (strchr(h, ':')) {
314 				if (h[1] == '\0')
315 					h = NULL;
316 				hint.ai_family = AF_INET6;
317 			} else if (h[0] == '*' && h[1] == '\0') {
318 				hint.ai_family = AF_INET;
319 				h = NULL;
320 			}
321 		}
322 
323 		if (getaddrinfo(h, p, &hint, &res))
324 			break;
325 
326 		addrlen = res->ai_addrlen <= sizeof(server) ?
327 		    res->ai_addrlen : sizeof(server);
328 		memcpy(&server, res->ai_addr, addrlen);
329 
330 		freeaddrinfo(res);
331 		goto again;
332 	} while (0);
333 #endif
334 
335 	if (!BIO_get_port(p, &port))
336 		goto err;
337 
338 	memset((char *)&server, 0, sizeof(server));
339 	server.sa_in.sin_family = AF_INET;
340 	server.sa_in.sin_port = htons(port);
341 	addrlen = sizeof(server.sa_in);
342 
343 	if (h == NULL || strcmp(h, "*") == 0)
344 		server.sa_in.sin_addr.s_addr = INADDR_ANY;
345 	else {
346 		if (!BIO_get_host_ip(h, &(ip[0])))
347 			goto err;
348 		l = (unsigned long)((unsigned long)ip[0]<<24L)|
349 		    ((unsigned long)ip[1]<<16L)|
350 		    ((unsigned long)ip[2]<< 8L)|
351 		    ((unsigned long)ip[3]);
352 		server.sa_in.sin_addr.s_addr = htonl(l);
353 	}
354 
355 again:
356 	s = socket(server.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
357 	if (s == -1) {
358 		SYSerr(SYS_F_SOCKET, errno);
359 		ERR_asprintf_error_data("port='%s'", host);
360 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET);
361 		goto err;
362 	}
363 
364 #ifdef SO_REUSEADDR
365 	if (bind_mode == BIO_BIND_REUSEADDR) {
366 		int i = 1;
367 
368 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));
369 		bind_mode = BIO_BIND_NORMAL;
370 	}
371 #endif
372 	if (bind(s, &server.sa, addrlen) == -1) {
373 #ifdef SO_REUSEADDR
374 		err_num = errno;
375 		if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
376 		    (err_num == EADDRINUSE)) {
377 			client = server;
378 			if (h == NULL || strcmp(h, "*") == 0) {
379 				if (client.sa.sa_family == AF_INET6) {
380 					memset(&client.sa_in6.sin6_addr, 0, sizeof(client.sa_in6.sin6_addr));
381 					client.sa_in6.sin6_addr.s6_addr[15] = 1;
382 				} else if (client.sa.sa_family == AF_INET) {
383 					client.sa_in.sin_addr.s_addr = htonl(0x7F000001);
384 				} else
385 					goto err;
386 			}
387 			cs = socket(client.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
388 			if (cs != -1) {
389 				int ii;
390 				ii = connect(cs, &client.sa, addrlen);
391 				close(cs);
392 				if (ii == -1) {
393 					bind_mode = BIO_BIND_REUSEADDR;
394 					close(s);
395 					goto again;
396 				}
397 				/* else error */
398 			}
399 			/* else error */
400 		}
401 #endif
402 		SYSerr(SYS_F_BIND, err_num);
403 		ERR_asprintf_error_data("port='%s'", host);
404 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_BIND_SOCKET);
405 		goto err;
406 	}
407 	if (listen(s, SOMAXCONN) == -1) {
408 		SYSerr(SYS_F_BIND, errno);
409 		ERR_asprintf_error_data("port='%s'", host);
410 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_LISTEN_SOCKET);
411 		goto err;
412 	}
413 	ret = 1;
414 err:
415 	free(str);
416 	if ((ret == 0) && (s != -1)) {
417 		close(s);
418 		s = -1;
419 	}
420 	return (s);
421 }
422 
423 int
424 BIO_accept(int sock, char **addr)
425 {
426 	int ret = -1;
427 	unsigned long l;
428 	unsigned short port;
429 	char *p, *tmp;
430 
431 	struct {
432 		socklen_t len;
433 		union {
434 			struct sockaddr sa;
435 			struct sockaddr_in sa_in;
436 			struct sockaddr_in6 sa_in6;
437 		} from;
438 	} sa;
439 
440 	sa.len = sizeof(sa.from);
441 	memset(&sa.from, 0, sizeof(sa.from));
442 	ret = accept(sock, &sa.from.sa, &sa.len);
443 	if (ret == -1) {
444 		if (BIO_sock_should_retry(ret))
445 			return -2;
446 		SYSerr(SYS_F_ACCEPT, errno);
447 		BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
448 		goto end;
449 	}
450 
451 	if (addr == NULL)
452 		goto end;
453 
454 #ifdef EAI_FAMILY
455 	do {
456 		char   h[NI_MAXHOST], s[NI_MAXSERV];
457 		size_t nl;
458 
459 		if (getnameinfo(&sa.from.sa, sa.len, h, sizeof(h),
460 		    s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV))
461 			break;
462 		nl = strlen(h) + strlen(s) + 2;
463 		p = *addr;
464 		if (p) {
465 			*p = '\0';
466 			if (!(tmp = realloc(p, nl))) {
467 				close(ret);
468 				ret = -1;
469 				free(p);
470 				*addr = NULL;
471 				BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
472 				goto end;
473 			}
474 			p = tmp;
475 		} else {
476 			p = malloc(nl);
477 		}
478 		if (p == NULL) {
479 			close(ret);
480 			ret = -1;
481 			BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
482 			goto end;
483 		}
484 		*addr = p;
485 		snprintf(*addr, nl, "%s:%s", h, s);
486 		goto end;
487 	} while (0);
488 #endif
489 	if (sa.from.sa.sa_family != AF_INET)
490 		goto end;
491 	l = ntohl(sa.from.sa_in.sin_addr.s_addr);
492 	port = ntohs(sa.from.sa_in.sin_port);
493 	if (*addr == NULL) {
494 		if ((p = malloc(24)) == NULL) {
495 			close(ret);
496 			ret = -1;
497 			BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
498 			goto end;
499 		}
500 		*addr = p;
501 	}
502 	snprintf(*addr, 24, "%d.%d.%d.%d:%d",
503 	    (unsigned char)(l >> 24L) & 0xff, (unsigned char)(l >> 16L) & 0xff,
504 	    (unsigned char)(l >> 8L) & 0xff, (unsigned char)(l) & 0xff, port);
505 
506 end:
507 	return (ret);
508 }
509 
510 int
511 BIO_set_tcp_ndelay(int s, int on)
512 {
513 	return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);
514 }
515 
516 int
517 BIO_socket_nbio(int s, int mode)
518 {
519 	int ret = -1;
520 	int l;
521 
522 	l = mode;
523 	ret = BIO_socket_ioctl(s, FIONBIO, &l);
524 
525 	return (ret == 0);
526 }
527