GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/bio/b_sock.c Lines: 63 110 57.3 %
Date: 2017-11-07 Branches: 26 52 50.0 %

Line Branch Exec Source
1
/* $OpenBSD: b_sock.c,v 1.67 2017/04/30 17:54:11 beck Exp $ */
2
/*
3
 * Copyright (c) 2017 Bob Beck <beck@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/ioctl.h>
19
#include <sys/socket.h>
20
#include <string.h>
21
22
#include <arpa/inet.h>
23
#include <netinet/in.h>
24
#include <netinet/tcp.h>
25
26
#include <errno.h>
27
#include <limits.h>
28
#include <netdb.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <unistd.h>
32
33
#include <openssl/bio.h>
34
#include <openssl/buffer.h>
35
#include <openssl/err.h>
36
37
int
38
BIO_get_host_ip(const char *str, unsigned char *ip)
39
{
40
16010
	struct addrinfo *res = NULL;
41
8005
	struct addrinfo hints = {
42
		.ai_family = AF_INET,
43
		.ai_socktype = SOCK_STREAM,
44
		.ai_flags = AI_PASSIVE,
45
	};
46
8005
	uint32_t *iap = (in_addr_t *)ip;
47
	int error;
48
49
8005
	if (str == NULL) {
50
		ERR_asprintf_error_data("NULL host provided");
51
		return (0);
52
	}
53
54
8005
	if ((error = getaddrinfo(str, NULL, &hints, &res)) != 0) {
55
54
		BIOerror(BIO_R_BAD_HOSTNAME_LOOKUP);
56
54
		ERR_asprintf_error_data("getaddrinfo: host='%s' : %s'", str,
57
54
		    gai_strerror(error));
58
54
		return (0);
59
	}
60
7951
	*iap = (uint32_t)(((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr);
61
7951
	freeaddrinfo(res);
62
7951
	return (1);
63
8005
}
64
65
int
66
BIO_get_port(const char *str, unsigned short *port_ptr)
67
{
68
15998
	struct addrinfo *res = NULL;
69
7999
	struct addrinfo hints = {
70
		.ai_family = AF_UNSPEC,
71
		.ai_socktype = SOCK_STREAM,
72
		.ai_flags = AI_PASSIVE,
73
	};
74
	int error;
75
76
7999
	if (str == NULL) {
77
6
		BIOerror(BIO_R_NO_PORT_SPECIFIED);
78
6
		return (0);
79
	}
80
81
7993
	if ((error = getaddrinfo(NULL, str, &hints, &res)) != 0) {
82
30
		ERR_asprintf_error_data("getaddrinfo: service='%s' : %s'", str,
83
30
		    gai_strerror(error));
84
30
		return (0);
85
	}
86
7963
	*port_ptr = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
87
7963
	freeaddrinfo(res);
88
7963
	return (1);
89
7999
}
90
91
int
92
BIO_sock_error(int sock)
93
{
94
	socklen_t len;
95
	int err;
96
97
	len = sizeof(err);
98
	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0)
99
		return (1);
100
	return (err);
101
}
102
103
struct hostent *
104
BIO_gethostbyname(const char *name)
105
{
106
	return gethostbyname(name);
107
}
108
109
int
110
BIO_socket_ioctl(int fd, long type, void *arg)
111
{
112
	int ret;
113
114
	ret = ioctl(fd, type, arg);
115
	if (ret < 0)
116
		SYSerror(errno);
117
	return (ret);
118
}
119
120
int
121
BIO_get_accept_socket(char *host, int bind_mode)
122
{
123
4
	struct addrinfo hints = {
124
		.ai_family = AF_INET,
125
		.ai_socktype = SOCK_STREAM,
126
		.ai_flags = AI_PASSIVE,
127
	};
128
2
	struct addrinfo *res = NULL;
129
	char *h, *p, *str = NULL;
130
	int error, ret = 0, s = -1;
131
132

4
	if (host == NULL || (str = strdup(host)) == NULL)
133
		return (-1);
134
	p = NULL;
135
	h = str;
136
2
	if ((p = strrchr(str, ':')) == NULL) {
137
		BIOerror(BIO_R_NO_PORT_SPECIFIED);
138
		goto err;
139
	}
140
2
	*p++ = '\0';
141
2
	if (*p == '\0') {
142
		BIOerror(BIO_R_NO_PORT_SPECIFIED);
143
		goto err;
144
	}
145

4
	if (*h == '\0' || strcmp(h, "*") == 0)
146
2
		h = NULL;
147
148
2
	if ((error = getaddrinfo(h, p, &hints, &res)) != 0) {
149
		ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h, p,
150
		    gai_strerror(error));
151
		goto err;
152
	}
153
2
	if (h == NULL) {
154
2
		struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
155
2
		sin->sin_addr.s_addr = INADDR_ANY;
156
2
	}
157
158
2
	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
159
2
	if (s == -1) {
160
		SYSerror(errno);
161
		ERR_asprintf_error_data("host='%s'", host);
162
		BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET);
163
		goto err;
164
	}
165
2
	if (bind_mode == BIO_BIND_REUSEADDR) {
166
		int i = 1;
167
168
		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
169
		bind_mode = BIO_BIND_NORMAL;
170
	}
171
2
	if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
172
		SYSerror(errno);
173
		ERR_asprintf_error_data("host='%s'", host);
174
		BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET);
175
		goto err;
176
	}
177
2
	if (listen(s, SOMAXCONN) == -1) {
178
		SYSerror(errno);
179
		ERR_asprintf_error_data("host='%s'", host);
180
		BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET);
181
		goto err;
182
	}
183
2
	ret = 1;
184
185
err:
186
2
	free(str);
187
2
	freeaddrinfo(res);
188
2
	if ((ret == 0) && (s != -1)) {
189
		close(s);
190
		s = -1;
191
	}
192
2
	return (s);
193
2
}
194
195
int
196
BIO_accept(int sock, char **addr)
197
{
198
4
	char   h[NI_MAXHOST], s[NI_MAXSERV];
199
2
	struct sockaddr_in sin;
200
2
	socklen_t sin_len = sizeof(sin);
201
	int ret = -1;
202
203
2
	if (addr == NULL)
204
		goto end;
205
206
2
	ret = accept(sock, (struct sockaddr *)&sin, &sin_len);
207
2
	if (ret == -1) {
208
		if (BIO_sock_should_retry(ret))
209
			return -2;
210
		SYSerror(errno);
211
		BIOerror(BIO_R_ACCEPT_ERROR);
212
		goto end;
213
	}
214
	/* XXX Crazy API. Can't be helped */
215
2
	if (*addr != NULL) {
216
		free(*addr);
217
		*addr = NULL;
218
	}
219
220
2
	if (sin.sin_family != AF_INET)
221
		goto end;
222
223
6
	if (getnameinfo((struct sockaddr *)&sin, sin_len, h, sizeof(h),
224
4
		s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV) != 0)
225
		goto end;
226
227
2
	if ((asprintf(addr, "%s:%s", h, s)) == -1) {
228
		BIOerror(ERR_R_MALLOC_FAILURE);
229
		*addr = NULL;
230
		goto end;
231
	}
232
end:
233
2
	return (ret);
234
2
}
235
236
int
237
BIO_set_tcp_ndelay(int s, int on)
238
{
239
	return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);
240
}