• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 
14 #include "bio_local.h"
15 
16 #include <openssl/err.h>
17 
18 #ifndef OPENSSL_NO_SOCK
19 # ifdef SO_MAXCONN
20 #  define MAX_LISTEN  SO_MAXCONN
21 # elif defined(SOMAXCONN)
22 #  define MAX_LISTEN  SOMAXCONN
23 # else
24 #  define MAX_LISTEN  32
25 # endif
26 
27 /*-
28  * BIO_socket - create a socket
29  * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...)
30  * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM)
31  * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP)
32  * @options: BIO socket options (currently unused)
33  *
34  * Creates a socket.  This should be called before calling any
35  * of BIO_connect and BIO_listen.
36  *
37  * Returns the file descriptor on success or INVALID_SOCKET on failure.  On
38  * failure errno is set, and a status is added to the OpenSSL error stack.
39  */
BIO_socket(int domain,int socktype,int protocol,int options)40 int BIO_socket(int domain, int socktype, int protocol, int options)
41 {
42     int sock = -1;
43 
44     if (BIO_sock_init() != 1)
45         return INVALID_SOCKET;
46 
47     sock = socket(domain, socktype, protocol);
48     if (sock == -1) {
49         SYSerr(SYS_F_SOCKET, get_last_socket_error());
50         BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET);
51         return INVALID_SOCKET;
52     }
53 
54     return sock;
55 }
56 
57 /*-
58  * BIO_connect - connect to an address
59  * @sock: the socket to connect with
60  * @addr: the address to connect to
61  * @options: BIO socket options
62  *
63  * Connects to the address using the given socket and options.
64  *
65  * Options can be a combination of the following:
66  * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages.
67  * - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
68  * - BIO_SOCK_NODELAY: don't delay small messages.
69  *
70  * options holds BIO socket options that can be used
71  * You should call this for every address returned by BIO_lookup
72  * until the connection is successful.
73  *
74  * Returns 1 on success or 0 on failure.  On failure errno is set
75  * and an error status is added to the OpenSSL error stack.
76  */
BIO_connect(int sock,const BIO_ADDR * addr,int options)77 int BIO_connect(int sock, const BIO_ADDR *addr, int options)
78 {
79     const int on = 1;
80 
81     if (sock == -1) {
82         BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET);
83         return 0;
84     }
85 
86     if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0))
87         return 0;
88 
89     if (options & BIO_SOCK_KEEPALIVE) {
90         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
91                        (const void *)&on, sizeof(on)) != 0) {
92             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
93             BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE);
94             return 0;
95         }
96     }
97 
98     if (options & BIO_SOCK_NODELAY) {
99         if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
100                        (const void *)&on, sizeof(on)) != 0) {
101             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
102             BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY);
103             return 0;
104         }
105     }
106 
107     if (connect(sock, BIO_ADDR_sockaddr(addr),
108                 BIO_ADDR_sockaddr_size(addr)) == -1) {
109         if (!BIO_sock_should_retry(-1)) {
110             SYSerr(SYS_F_CONNECT, get_last_socket_error());
111             BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR);
112         }
113         return 0;
114     }
115     return 1;
116 }
117 
118 /*-
119  * BIO_bind - bind socket to address
120  * @sock: the socket to set
121  * @addr: local address to bind to
122  * @options: BIO socket options
123  *
124  * Binds to the address using the given socket and options.
125  *
126  * Options can be a combination of the following:
127  * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination
128  *   for a recently closed port.
129  *
130  * When restarting the program it could be that the port is still in use.  If
131  * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway.
132  * It's recommended that you use this.
133  */
BIO_bind(int sock,const BIO_ADDR * addr,int options)134 int BIO_bind(int sock, const BIO_ADDR *addr, int options)
135 {
136 # ifndef OPENSSL_SYS_WINDOWS
137     int on = 1;
138 # endif
139 
140     if (sock == -1) {
141         BIOerr(BIO_F_BIO_BIND, BIO_R_INVALID_SOCKET);
142         return 0;
143     }
144 
145 # ifndef OPENSSL_SYS_WINDOWS
146     /*
147      * SO_REUSEADDR has different behavior on Windows than on
148      * other operating systems, don't set it there.
149      */
150     if (options & BIO_SOCK_REUSEADDR) {
151         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
152                        (const void *)&on, sizeof(on)) != 0) {
153             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
154             BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_REUSEADDR);
155             return 0;
156         }
157     }
158 # endif
159 
160     if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) {
161         SYSerr(SYS_F_BIND, get_last_socket_error());
162         BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_BIND_SOCKET);
163         return 0;
164     }
165 
166     return 1;
167 }
168 
169 /*-
170  * BIO_listen - Creates a listen socket
171  * @sock: the socket to listen with
172  * @addr: local address to bind to
173  * @options: BIO socket options
174  *
175  * Binds to the address using the given socket and options, then
176  * starts listening for incoming connections.
177  *
178  * Options can be a combination of the following:
179  * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages.
180  * - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
181  * - BIO_SOCK_NODELAY: don't delay small messages.
182  * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination
183  *   for a recently closed port.
184  * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only
185  *   for IPv6 addresses and not IPv4 addresses mapped to IPv6.
186  *
187  * It's recommended that you set up both an IPv6 and IPv4 listen socket, and
188  * then check both for new clients that connect to it.  You want to set up
189  * the socket as non-blocking in that case since else it could hang.
190  *
191  * Not all operating systems support IPv4 addresses on an IPv6 socket, and for
192  * others it's an option.  If you pass the BIO_LISTEN_V6_ONLY it will try to
193  * create the IPv6 sockets to only listen for IPv6 connection.
194  *
195  * It could be that the first BIO_listen() call will listen to all the IPv6
196  * and IPv4 addresses and that then trying to bind to the IPv4 address will
197  * fail.  We can't tell the difference between already listening ourself to
198  * it and someone else listening to it when failing and errno is EADDRINUSE, so
199  * it's recommended to not give an error in that case if the first call was
200  * successful.
201  *
202  * When restarting the program it could be that the port is still in use.  If
203  * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway.
204  * It's recommended that you use this.
205  */
BIO_listen(int sock,const BIO_ADDR * addr,int options)206 int BIO_listen(int sock, const BIO_ADDR *addr, int options)
207 {
208     int on = 1;
209     int socktype;
210     socklen_t socktype_len = sizeof(socktype);
211 
212     if (sock == -1) {
213         BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET);
214         return 0;
215     }
216 
217     if (getsockopt(sock, SOL_SOCKET, SO_TYPE,
218                    (void *)&socktype, &socktype_len) != 0
219         || socktype_len != sizeof(socktype)) {
220         SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error());
221         BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE);
222         return 0;
223     }
224 
225     if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0))
226         return 0;
227 
228     if (options & BIO_SOCK_KEEPALIVE) {
229         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
230                        (const void *)&on, sizeof(on)) != 0) {
231             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
232             BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE);
233             return 0;
234         }
235     }
236 
237     if (options & BIO_SOCK_NODELAY) {
238         if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
239                        (const void *)&on, sizeof(on)) != 0) {
240             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
241             BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY);
242             return 0;
243         }
244     }
245 
246   /* On OpenBSD it is always ipv6 only with ipv6 sockets thus read-only */
247 # if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
248     if (BIO_ADDR_family(addr) == AF_INET6) {
249         /*
250          * Note: Windows default of IPV6_V6ONLY is ON, and Linux is OFF.
251          * Therefore we always have to use setsockopt here.
252          */
253         on = options & BIO_SOCK_V6_ONLY ? 1 : 0;
254         if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
255                        (const void *)&on, sizeof(on)) != 0) {
256             SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
257             BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY);
258             return 0;
259         }
260     }
261 # endif
262 
263     if (!BIO_bind(sock, addr, options))
264         return 0;
265 
266     if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) {
267         SYSerr(SYS_F_LISTEN, get_last_socket_error());
268         BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET);
269         return 0;
270     }
271 
272     return 1;
273 }
274 
275 /*-
276  * BIO_accept_ex - Accept new incoming connections
277  * @sock: the listening socket
278  * @addr: the BIO_ADDR to store the peer address in
279  * @options: BIO socket options, applied on the accepted socket.
280  *
281  */
BIO_accept_ex(int accept_sock,BIO_ADDR * addr_,int options)282 int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options)
283 {
284     socklen_t len;
285     int accepted_sock;
286     BIO_ADDR locaddr;
287     BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_;
288 
289     len = sizeof(*addr);
290     accepted_sock = accept(accept_sock,
291                            BIO_ADDR_sockaddr_noconst(addr), &len);
292     if (accepted_sock == -1) {
293         if (!BIO_sock_should_retry(accepted_sock)) {
294             SYSerr(SYS_F_ACCEPT, get_last_socket_error());
295             BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR);
296         }
297         return INVALID_SOCKET;
298     }
299 
300     if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) {
301         closesocket(accepted_sock);
302         return INVALID_SOCKET;
303     }
304 
305     return accepted_sock;
306 }
307 
308 /*-
309  * BIO_closesocket - Close a socket
310  * @sock: the socket to close
311  */
BIO_closesocket(int sock)312 int BIO_closesocket(int sock)
313 {
314     if (closesocket(sock) < 0)
315         return 0;
316     return 1;
317 }
318 #endif
319