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 |
|
31442 |
struct addrinfo *res = NULL; |
41 |
|
15721 |
struct addrinfo hints = { |
42 |
|
|
.ai_family = AF_INET, |
43 |
|
|
.ai_socktype = SOCK_STREAM, |
44 |
|
|
.ai_flags = AI_PASSIVE, |
45 |
|
|
}; |
46 |
|
15721 |
uint32_t *iap = (in_addr_t *)ip; |
47 |
|
|
int error; |
48 |
|
|
|
49 |
✗✓ |
15721 |
if (str == NULL) { |
50 |
|
|
ERR_asprintf_error_data("NULL host provided"); |
51 |
|
|
return (0); |
52 |
|
|
} |
53 |
|
|
|
54 |
✓✓ |
15721 |
if ((error = getaddrinfo(str, NULL, &hints, &res)) != 0) { |
55 |
|
27 |
BIOerror(BIO_R_BAD_HOSTNAME_LOOKUP); |
56 |
|
27 |
ERR_asprintf_error_data("getaddrinfo: host='%s' : %s'", str, |
57 |
|
27 |
gai_strerror(error)); |
58 |
|
27 |
return (0); |
59 |
|
|
} |
60 |
|
15694 |
*iap = (uint32_t)(((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr); |
61 |
|
15694 |
freeaddrinfo(res); |
62 |
|
15694 |
return (1); |
63 |
|
15721 |
} |
64 |
|
|
|
65 |
|
|
int |
66 |
|
|
BIO_get_port(const char *str, unsigned short *port_ptr) |
67 |
|
|
{ |
68 |
|
31436 |
struct addrinfo *res = NULL; |
69 |
|
15718 |
struct addrinfo hints = { |
70 |
|
|
.ai_family = AF_UNSPEC, |
71 |
|
|
.ai_socktype = SOCK_STREAM, |
72 |
|
|
.ai_flags = AI_PASSIVE, |
73 |
|
|
}; |
74 |
|
|
int error; |
75 |
|
|
|
76 |
✓✓ |
15718 |
if (str == NULL) { |
77 |
|
3 |
BIOerror(BIO_R_NO_PORT_SPECIFIED); |
78 |
|
3 |
return (0); |
79 |
|
|
} |
80 |
|
|
|
81 |
✓✓ |
15715 |
if ((error = getaddrinfo(NULL, str, &hints, &res)) != 0) { |
82 |
|
15 |
ERR_asprintf_error_data("getaddrinfo: service='%s' : %s'", str, |
83 |
|
15 |
gai_strerror(error)); |
84 |
|
15 |
return (0); |
85 |
|
|
} |
86 |
|
15700 |
*port_ptr = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port); |
87 |
|
15700 |
freeaddrinfo(res); |
88 |
|
15700 |
return (1); |
89 |
|
15718 |
} |
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 |
|
|
} |