GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/bio/b_sock.c Lines: 52 206 25.2 %
Date: 2016-12-06 Branches: 30 130 23.1 %

Line Branch Exec Source
1
/* $OpenBSD: b_sock.c,v 1.61 2014/12/03 22:14:38 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
14
{
81
	int i;
82
14
	int err = 1;
83
	struct hostent *he;
84
85
14
	if (inet_pton(AF_INET, str, ip) == 1)
86
4
		return (1);
87
88
	/* do a gethostbyname */
89
10
	CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
90
10
	he = BIO_gethostbyname(str);
91
10
	if (he == NULL) {
92
9
		BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP);
93
9
		goto err;
94
	}
95
96
1
	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
5
	for (i = 0; i < 4; i++)
102
4
		ip[i] = he->h_addr_list[0][i];
103
1
	err = 0;
104
105
10
err:
106
10
	CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
107
10
	if (err) {
108
9
		ERR_asprintf_error_data("host=%s", str);
109
9
		return 0;
110
	} else
111
1
		return 1;
112
}
113
114
int
115
BIO_get_port(const char *str, unsigned short *port_ptr)
116
13
{
117
13
	struct addrinfo *res = NULL;
118
	struct addrinfo hints = {
119
		.ai_family = AF_UNSPEC,
120
		.ai_socktype = SOCK_STREAM,
121
		.ai_flags = AI_PASSIVE,
122
13
	};
123
	long port;
124
	char *ep;
125
126
13
	if (str == NULL) {
127
1
		BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_SPECIFIED);
128
1
		return (0);
129
	}
130
131
12
	errno = 0;
132
12
	port = strtol(str, &ep, 10);
133

12
	if (str[0] != '\0' && *ep == '\0') {
134

7
		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
7
		if (port < 0 || port > 65535) {
139
3
			BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER);
140
3
			return (0);
141
		}
142
		goto done;
143
	}
144
145
5
	if (getaddrinfo(NULL, str, &hints, &res) == 0) {
146
3
		port = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
147
3
		goto done;
148
	}
149
150
2
	if (strcmp(str, "http") == 0)
151
		port = 80;
152
2
	else if (strcmp(str, "telnet") == 0)
153
		port = 23;
154
2
	else if (strcmp(str, "socks") == 0)
155
		port = 1080;
156
2
	else if (strcmp(str, "https") == 0)
157
		port = 443;
158
2
	else if (strcmp(str, "ssl") == 0)
159
		port = 443;
160
2
	else if (strcmp(str, "ftp") == 0)
161
		port = 21;
162
2
	else if (strcmp(str, "gopher") == 0)
163
		port = 70;
164
	else {
165
2
		SYSerr(SYS_F_GETSERVBYNAME, errno);
166
2
		ERR_asprintf_error_data("service='%s'", str);
167
2
		return (0);
168
	}
169
170
7
done:
171
7
	if (res)
172
3
		freeaddrinfo(res);
173
7
	*port_ptr = (unsigned short)port;
174
7
	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
10
{
192
10
	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
}