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)
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.
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).
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.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
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)"
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
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.]
59 #include <sys/ioctl.h>
60 #include <sys/socket.h>
63 #include <arpa/inet.h>
64 #include <netinet/in.h>
65 #include <netinet/tcp.h>
74 #include <openssl/bio.h>
75 #include <openssl/buffer.h>
76 #include <openssl/err.h>
79 BIO_get_host_ip(const char *str
, unsigned char *ip
)
85 if (inet_pton(AF_INET
, str
, ip
) == 1)
88 /* do a gethostbyname */
89 CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME
);
90 he
= BIO_gethostbyname(str
);
92 BIOerr(BIO_F_BIO_GET_HOST_IP
, BIO_R_BAD_HOSTNAME_LOOKUP
);
96 if (he
->h_addrtype
!= AF_INET
) {
97 BIOerr(BIO_F_BIO_GET_HOST_IP
,
98 BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET
);
101 for (i
= 0; i
< 4; i
++)
102 ip
[i
] = he
->h_addr_list
[0][i
];
106 CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME
);
108 ERR_asprintf_error_data("host=%s", str
);
115 BIO_get_port(const char *str
, unsigned short *port_ptr
)
117 struct addrinfo
*res
= NULL
;
118 struct addrinfo hints
= {
119 .ai_family
= AF_UNSPEC
,
120 .ai_socktype
= SOCK_STREAM
,
121 .ai_flags
= AI_PASSIVE
,
127 BIOerr(BIO_F_BIO_GET_PORT
, BIO_R_NO_PORT_SPECIFIED
);
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
);
138 if (port
< 0 || port
> 65535) {
139 BIOerr(BIO_F_BIO_GET_PORT
, BIO_R_INVALID_PORT_NUMBER
);
145 if (getaddrinfo(NULL
, str
, &hints
, &res
) == 0) {
146 port
= ntohs(((struct sockaddr_in
*)(res
->ai_addr
))->sin_port
);
150 if (strcmp(str
, "http") == 0)
152 else if (strcmp(str
, "telnet") == 0)
154 else if (strcmp(str
, "socks") == 0)
156 else if (strcmp(str
, "https") == 0)
158 else if (strcmp(str
, "ssl") == 0)
160 else if (strcmp(str
, "ftp") == 0)
162 else if (strcmp(str
, "gopher") == 0)
165 SYSerr(SYS_F_GETSERVBYNAME
, errno
);
166 ERR_asprintf_error_data("service='%s'", str
);
173 *port_ptr
= (unsigned short)port
;
178 BIO_sock_error(int sock
)
184 if (getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &len
) != 0)
190 BIO_gethostbyname(const char *name
)
192 return gethostbyname(name
);
196 BIO_socket_ioctl(int fd
, long type
, void *arg
)
200 ret
= ioctl(fd
, type
, arg
);
202 SYSerr(SYS_F_IOCTLSOCKET
, errno
);
207 BIO_get_accept_socket(char *host
, int bind_mode
)
212 struct sockaddr_in sa_in
;
213 struct sockaddr_in6 sa_in6
;
215 int s
= -1, cs
, addrlen
;
218 char *str
= NULL
, *e
;
223 if (host
== NULL
|| (str
= strdup(host
)) == NULL
)
228 for (e
= str
; *e
; e
++) {
231 } else if (*e
== '/') {
236 /* points at last ':', '::port' is special [see below] */
243 struct addrinfo
*res
, hint
;
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...
251 memset(&hint
, 0, sizeof(hint
));
252 hint
.ai_flags
= AI_PASSIVE
;
254 if (strchr(h
, ':')) {
257 hint
.ai_family
= AF_INET6
;
258 } else if (h
[0] == '*' && h
[1] == '\0') {
259 hint
.ai_family
= AF_INET
;
264 if (getaddrinfo(h
, p
, &hint
, &res
))
267 addrlen
= res
->ai_addrlen
<= sizeof(server
) ?
268 res
->ai_addrlen
: sizeof(server
);
269 memcpy(&server
, res
->ai_addr
, addrlen
);
275 if (!BIO_get_port(p
, &port
))
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
);
283 if (h
== NULL
|| strcmp(h
, "*") == 0)
284 server
.sa_in
.sin_addr
.s_addr
= INADDR_ANY
;
286 if (!BIO_get_host_ip(h
, &(ip
[0])))
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
);
296 s
= socket(server
.sa
.sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
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
);
305 if (bind_mode
== BIO_BIND_REUSEADDR
) {
308 ret
= setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &i
, sizeof(i
));
309 bind_mode
= BIO_BIND_NORMAL
;
311 if (bind(s
, &server
.sa
, addrlen
) == -1) {
313 if ((bind_mode
== BIO_BIND_REUSEADDR_IF_UNUSED
) &&
314 (err_num
== EADDRINUSE
)) {
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
=
327 cs
= socket(client
.sa
.sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
330 ii
= connect(cs
, &client
.sa
, addrlen
);
333 bind_mode
= BIO_BIND_REUSEADDR
;
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
);
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
);
357 if ((ret
== 0) && (s
!= -1)) {
365 BIO_accept(int sock
, char **addr
)
376 struct sockaddr_in sa_in
;
377 struct sockaddr_in6 sa_in6
;
381 sa
.len
= sizeof(sa
.from
);
382 memset(&sa
.from
, 0, sizeof(sa
.from
));
383 ret
= accept(sock
, &sa
.from
.sa
, &sa
.len
);
385 if (BIO_sock_should_retry(ret
))
387 SYSerr(SYS_F_ACCEPT
, errno
);
388 BIOerr(BIO_F_BIO_ACCEPT
, BIO_R_ACCEPT_ERROR
);
396 char h
[NI_MAXHOST
], s
[NI_MAXSERV
];
399 if (getnameinfo(&sa
.from
.sa
, sa
.len
, h
, sizeof(h
),
400 s
, sizeof(s
), NI_NUMERICHOST
|NI_NUMERICSERV
))
402 nl
= strlen(h
) + strlen(s
) + 2;
406 if (!(tmp
= realloc(p
, nl
))) {
411 BIOerr(BIO_F_BIO_ACCEPT
, ERR_R_MALLOC_FAILURE
);
416 snprintf(*addr
, nl
, "%s:%s", h
, s
);
419 if (sa
.from
.sa
.sa_family
!= AF_INET
)
421 l
= ntohl(sa
.from
.sa_in
.sin_addr
.s_addr
);
422 port
= ntohs(sa
.from
.sa_in
.sin_port
);
424 if ((p
= malloc(24)) == NULL
) {
427 BIOerr(BIO_F_BIO_ACCEPT
, ERR_R_MALLOC_FAILURE
);
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
);
441 BIO_set_tcp_ndelay(int s
, int on
)
443 return (setsockopt(s
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) == 0);