join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
acceptor.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_ACCEPTOR_HPP
26#define JOIN_CORE_ACCEPTOR_HPP
27
28// libjoin.
29#include <join/socketstream.hpp>
30
31namespace join
32{
36 template <class Protocol>
38 {
39 public:
40 using Endpoint = typename Protocol::Endpoint;
41 using Socket = typename Protocol::Socket;
42 using Stream = typename Protocol::Stream;
43
47 BasicStreamAcceptor () = default;
48
54
61
67 : _handle (other._handle)
68 , _protocol (other._protocol)
69 {
70 other._handle = -1;
71 other._protocol = Protocol ();
72 }
73
80 {
81 this->close ();
82
83 this->_handle = other._handle;
84 this->_protocol = other._protocol;
85
86 other._handle = -1;
87 other._protocol = Protocol ();
88
89 return *this;
90 }
91
96 {
97 this->close ();
98 }
99
105 virtual int create (const Endpoint& endpoint) noexcept
106 {
107 if (this->opened ())
108 {
109 lastError = make_error_code (Errc::InUse);
110 return -1;
111 }
112
113 this->_handle = ::socket (endpoint.protocol ().family (), endpoint.protocol ().type () | SOCK_CLOEXEC,
114 endpoint.protocol ().protocol ());
115 if (this->_handle == -1)
116 {
117 lastError = std::error_code (errno, std::generic_category ());
118 this->close ();
119 return -1;
120 }
121
122 if (endpoint.protocol ().family () == AF_INET6)
123 {
124 int off = 0;
125
126 if (::setsockopt (this->_handle, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof (off)) == -1)
127 {
128 lastError = std::error_code (errno, std::generic_category ());
129 this->close ();
130 return -1;
131 }
132 }
133
134 if (endpoint.protocol ().family () == AF_UNIX)
135 {
136 ::unlink (endpoint.device ().c_str ());
137 }
138 else if (endpoint.protocol ().protocol () == IPPROTO_TCP)
139 {
140 int on = 1;
141
142 if (::setsockopt (this->_handle, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1)
143 {
144 lastError = std::error_code (errno, std::generic_category ());
145 this->close ();
146 return -1;
147 }
148 }
149
150 if ((::bind (this->_handle, endpoint.addr (), endpoint.length ()) == -1) ||
151 (::listen (this->_handle, SOMAXCONN) == -1))
152 {
153 lastError = std::error_code (errno, std::generic_category ());
154 this->close ();
155 return -1;
156 }
157
158 this->_protocol = endpoint.protocol ();
159
160 return 0;
161 }
162
166 virtual void close () noexcept
167 {
168 if (this->_handle != -1)
169 {
170 ::close (this->_handle);
171 this->_handle = -1;
172 }
173
174 this->_protocol = Protocol ();
175 }
176
181 virtual Socket accept () const
182 {
183 struct sockaddr_storage sa;
184 socklen_t sa_len = sizeof (struct sockaddr_storage);
185 Socket sock;
186
187 sock._handle = ::accept (this->_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len);
188 if (sock._handle == -1)
189 {
190 lastError = std::error_code (errno, std::generic_category ());
191 return sock;
192 }
193
194 sock._remote = Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
195 sock._state = Socket::Connected;
196
197 if (sock.protocol () == IPPROTO_TCP)
198 {
199 sock.setOption (Socket::NoDelay, 1);
200 }
201 sock.setMode (Socket::NonBlocking);
202
203 return sock;
204 }
205
210 virtual Stream acceptStream () const
211 {
212 Stream stream;
213 stream.socket () = this->accept ();
214 return stream;
215 }
216
222 {
223 struct sockaddr_storage sa;
224 socklen_t sa_len = sizeof (struct sockaddr_storage);
225
226 if (::getsockname (this->_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len) == -1)
227 {
228 lastError = std::error_code (errno, std::generic_category ());
229 return {};
230 }
231
232 return Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
233 }
234
239 bool opened () const noexcept
240 {
241 return (this->_handle != -1);
242 }
243
248 int family () const noexcept
249 {
250 return this->_protocol.family ();
251 }
252
257 int type () const noexcept
258 {
259 return this->_protocol.type ();
260 }
261
266 int protocol () const noexcept
267 {
268 return this->_protocol.protocol ();
269 }
270
275 int handle () const noexcept
276 {
277 return this->_handle;
278 }
279
280 protected:
282 int _handle = -1;
283
285 Protocol _protocol;
286 };
287
291 template <class Protocol>
292 class BasicTlsAcceptor : public BasicStreamAcceptor<Protocol>
293 {
294 public:
295 using Endpoint = typename Protocol::Endpoint;
296 using Socket = typename Protocol::Socket;
297 using Stream = typename Protocol::Stream;
298
303 : BasicStreamAcceptor<Protocol> ()
304 , _tlsContext (SSL_CTX_new (TLS_server_method ()))
305 , _sessionId (randomize<int> ())
306 {
307 // enable the OpenSSL bug workaround options.
308 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_ALL);
309
310 // disallow compression.
311 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_NO_COMPRESSION);
312
313 // disallow usage of SSLv2, SSLv3, TLSv1 and TLSv1.1 which are considered insecure.
314 SSL_CTX_set_options (_tlsContext.get (),
315 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
316
317 // choose the cipher according to the server's preferences.
318 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_CIPHER_SERVER_PREFERENCE);
319
320 // setup write mode.
321 SSL_CTX_set_mode (_tlsContext.get (), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
322
323 // automatically renegotiates.
324 SSL_CTX_set_mode (_tlsContext.get (), SSL_MODE_AUTO_RETRY);
325
326 // enable SSL session caching.
327 SSL_CTX_set_session_id_context (_tlsContext.get (), reinterpret_cast<const unsigned char*> (&_sessionId),
328 sizeof (_sessionId));
329
330 // no verification by default.
331 SSL_CTX_set_verify (_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
332
333 // set default TLSv1.2 and below cipher suites.
334 SSL_CTX_set_cipher_list (_tlsContext.get (), join::defaultCipher.c_str ());
335
336 // set default TLSv1.3 cipher suites.
337 SSL_CTX_set_ciphersuites (_tlsContext.get (), join::defaultCipher_1_3.c_str ());
338
339 // disallow client-side renegotiation.
340 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_NO_RENEGOTIATION);
341
342#if OPENSSL_VERSION_NUMBER >= 0x30000000L
343 // use the default built-in Diffie-Hellman parameters.
344 SSL_CTX_set_dh_auto (_tlsContext.get (), 1);
345
346 // Set elliptic curve Diffie-Hellman key.
347 SSL_CTX_set1_groups_list (_tlsContext.get (), join::defaultCurve.c_str ());
348#else
349 // Set Diffie-Hellman key.
351 if (dh)
352 {
353 SSL_CTX_set_tmp_dh (_tlsContext.get (), dh.get ());
354 }
355
356 // Set elliptic curve Diffie-Hellman key.
357 join::EcdhKeyPtr ecdh (EC_KEY_new_by_curve_name (NID_X9_62_prime256v1));
358 if (ecdh)
359 {
360 SSL_CTX_set_tmp_ecdh (_tlsContext.get (), ecdh.get ());
361 }
362#endif
363 }
364
369 BasicTlsAcceptor (const BasicTlsAcceptor& other) = delete;
370
377
383 : BasicStreamAcceptor<Protocol> (std::move (other))
384 , _tlsContext (std::move (other._tlsContext))
385 , _sessionId (other._sessionId)
386 {
387 other._sessionId = 0;
388 }
389
396 {
398 _tlsContext = std::move (other._tlsContext);
399 _sessionId = other._sessionId;
400 other._sessionId = 0;
401 return *this;
402 }
403
408 virtual Socket accept () const override
409 {
410 struct sockaddr_storage sa;
411 socklen_t sa_len = sizeof (struct sockaddr_storage);
412 Socket sock (join::SslCtxPtr (this->_tlsContext.get ()));
413 SSL_CTX_up_ref (this->_tlsContext.get ());
414
415 sock._handle = ::accept (this->_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len);
416 if (sock._handle == -1)
417 {
418 lastError = std::error_code (errno, std::generic_category ());
419 return sock;
420 }
421
422 sock._remote = Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
423 sock._state = Socket::Connected;
424
425 sock.setOption (Socket::NoDelay, 1);
426 sock.setMode (Socket::NonBlocking);
427
428 return sock;
429 }
430
435 virtual Socket acceptEncrypted () const
436 {
437 Socket sock = this->accept ();
438 if (!sock.connected ())
439 {
440 return sock;
441 }
442
443 sock._tlsHandle.reset (SSL_new (sock._tlsContext.get ()));
444 if (sock._tlsHandle == nullptr)
445 {
447 sock.close ();
448 return sock;
449 }
450
451 SSL_set_fd (sock._tlsHandle.get (), sock._handle);
452 SSL_set_accept_state (sock._tlsHandle.get ());
453 SSL_set_app_data (sock._tlsHandle.get (), &sock);
454#ifdef DEBUG
455 SSL_set_info_callback (sock._tlsHandle.get (), Socket::infoWrapper);
456#endif
457
458 sock._tlsState = Socket::Encrypted;
459
460 return sock;
461 }
462
468 {
469 Stream stream;
470 stream.socket () = this->acceptEncrypted ();
471 return stream;
472 }
473
480 int setCertificate (const std::string& cert, const std::string& key = "")
481 {
482 if (SSL_CTX_use_certificate_file (this->_tlsContext.get (), cert.c_str (), SSL_FILETYPE_PEM) == 0)
483 {
485 return -1;
486 }
487
488 if (key.size ())
489 {
490 if (SSL_CTX_use_PrivateKey_file (this->_tlsContext.get (), key.c_str (), SSL_FILETYPE_PEM) == 0)
491 {
493 return -1;
494 }
495 }
496
497 // check the consistency of the private key and the certificate.
498 if (SSL_CTX_check_private_key (this->_tlsContext.get ()) == 0)
499 {
501 this->close ();
502 return -1;
503 }
504
505 return 0;
506 }
507
513 int setCaCertificate (const std::string& caFile)
514 {
515 join::StackOfX509NamePtr certNames (SSL_load_client_CA_file (caFile.c_str ()));
516 if (certNames == nullptr)
517 {
519 return -1;
520 }
521
522 SSL_CTX_load_verify_locations (this->_tlsContext.get (), caFile.c_str (), nullptr);
523 SSL_CTX_set_client_CA_list (this->_tlsContext.get (), certNames.release ());
524
525 return 0;
526 }
527
533 void setVerify (bool verify, int depth = -1)
534 {
535 if (verify)
536 {
537 // SSL_VERIFY_PEER will lead the client to verify the server certificate.
538 // If the verification process fails, the TLS/SSL handshake is immediately terminated.
539 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_PEER, Socket::verifyWrapper);
540 SSL_CTX_set_verify_depth (this->_tlsContext.get (), depth);
541 }
542 else
543 {
544 // SSL_VERIFY_NONE will lead the client to continue the handshake regardless of the verification result.
545 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
546 }
547 }
548
554 int setCipher (const std::string& cipher)
555 {
556 if (SSL_CTX_set_cipher_list (this->_tlsContext.get (), cipher.c_str ()) == 0)
557 {
559 return -1;
560 }
561
562 return 0;
563 }
564
570 int setCipher_1_3 (const std::string& cipher)
571 {
572 if (SSL_CTX_set_ciphersuites (this->_tlsContext.get (), cipher.c_str ()) == 0)
573 {
575 return -1;
576 }
577
578 return 0;
579 }
580
581#if OPENSSL_VERSION_NUMBER >= 0x30000000L
587 int setCurve (const std::string& curves)
588 {
589 if (SSL_CTX_set1_groups_list (this->_tlsContext.get (), curves.c_str ()) == 0)
590 {
592 return -1;
593 }
594
595 return 0;
596 }
597#else
598
599 protected:
605 static DH* getDh2236 ()
606 {
607 static unsigned char dhp_2236[] = {
608 0x0C, 0xA5, 0x51, 0x2B, 0x8F, 0xF7, 0xA8, 0x74, 0x4D, 0x52, 0xD7, 0xED, 0x97, 0x83, 0xA4, 0xD2, 0x8B,
609 0xF3, 0xE7, 0x92, 0xF0, 0x27, 0x1B, 0xA0, 0x80, 0x83, 0x19, 0xDD, 0x02, 0xEF, 0xA3, 0xE6, 0x13, 0x0A,
610 0x47, 0xE6, 0xF1, 0x3B, 0xC1, 0x5F, 0x63, 0xC4, 0x03, 0xBA, 0xAC, 0xAA, 0xA3, 0x44, 0xC2, 0x03, 0x6D,
611 0x62, 0x33, 0xAA, 0xF9, 0xA2, 0x5A, 0x98, 0xC2, 0xC0, 0x71, 0x6F, 0xB0, 0x93, 0x6A, 0x26, 0x92, 0x90,
612 0x95, 0xEA, 0xE8, 0x5F, 0x81, 0x50, 0x57, 0xB3, 0xB7, 0xE6, 0x3A, 0x3A, 0x90, 0x15, 0x01, 0x2F, 0xC7,
613 0x8F, 0xAA, 0x0C, 0xAE, 0xC0, 0xFF, 0x3A, 0xA7, 0x26, 0x5C, 0x87, 0xC2, 0x00, 0x68, 0xCA, 0x02, 0x06,
614 0x50, 0x44, 0xEE, 0x75, 0xE7, 0xFF, 0x16, 0xD1, 0x0F, 0x64, 0x51, 0x97, 0x52, 0x54, 0x69, 0xF0, 0x31,
615 0x81, 0x4D, 0xEB, 0xF5, 0xA8, 0xB3, 0x7B, 0x48, 0x60, 0xBD, 0xC7, 0xC9, 0x6E, 0x97, 0x86, 0x9B, 0xE6,
616 0x66, 0x4E, 0x1D, 0xE5, 0x6F, 0xBA, 0xC5, 0x3D, 0xFD, 0x3F, 0x34, 0x69, 0x6F, 0xC0, 0xFA, 0x8D, 0x42,
617 0x73, 0xA2, 0x49, 0xDE, 0xB6, 0x8D, 0x71, 0x15, 0xFC, 0xB4, 0x18, 0x31, 0x5A, 0x24, 0xD0, 0x5E, 0xA8,
618 0xE0, 0xD8, 0x1C, 0xF8, 0x0F, 0x1F, 0x59, 0x22, 0x5A, 0x07, 0x75, 0x06, 0x98, 0x58, 0xE1, 0xF6, 0xA5,
619 0x53, 0xFD, 0x66, 0x1E, 0x8F, 0x41, 0x63, 0x61, 0xA1, 0x79, 0x0D, 0x3B, 0xA7, 0xF4, 0xBD, 0x72, 0xEB,
620 0xE1, 0xDC, 0xE2, 0xC9, 0x9B, 0x41, 0xF6, 0x33, 0x3F, 0x9F, 0x0C, 0x33, 0x7B, 0xF2, 0x90, 0x68, 0x28,
621 0xD3, 0x5A, 0xC1, 0x5C, 0xDE, 0x15, 0x11, 0xF4, 0xDD, 0xCB, 0x09, 0x78, 0x63, 0x3B, 0xB6, 0xE8, 0xEE,
622 0x9A, 0x48, 0xE9, 0x79, 0x80, 0x3F, 0x34, 0x8D, 0xB9, 0x24, 0x8D, 0x94, 0x88, 0xA9, 0x75, 0xA5, 0x19,
623 0x05, 0x8D, 0x77, 0x20, 0xAF, 0xC2, 0xC9, 0x7B, 0xD2, 0x51, 0xEE, 0x17, 0x22, 0xAC, 0x33, 0xA8, 0xA6,
624 0x1B, 0x8B, 0xE3, 0x79, 0xF3, 0xE8, 0x3B, 0x6B};
625
626 static unsigned char dhg_2236[] = {0x02};
627
628 DH* dh = DH_new ();
629 if (dh == nullptr)
630 {
631 return nullptr;
632 }
633
634 BIGNUM* p = BN_bin2bn (dhp_2236, sizeof (dhp_2236), nullptr);
635 BIGNUM* g = BN_bin2bn (dhg_2236, sizeof (dhg_2236), nullptr);
636 if (p == nullptr || g == nullptr || !DH_set0_pqg (dh, p, nullptr, g))
637 {
638 DH_free (dh);
639 BN_free (p);
640 BN_free (g);
641 return nullptr;
642 }
643
644 return dh;
645 }
646#endif
647
648 protected:
651
653 int _sessionId = 0;
654 };
655}
656
657#endif
basic stream acceptor class.
Definition protocol.hpp:52
BasicStreamAcceptor()=default
create the acceptor instance.
bool opened() const noexcept
check if the socket is opened.
Definition acceptor.hpp:239
BasicStreamAcceptor(const BasicStreamAcceptor &other)=delete
copy constructor.
virtual Socket accept() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:181
typename Protocol::Endpoint Endpoint
Definition acceptor.hpp:40
Endpoint localEndpoint() const
determine the local endpoint associated with this socket.
Definition acceptor.hpp:221
int family() const noexcept
get address family.
Definition acceptor.hpp:248
int _handle
socket handle.
Definition acceptor.hpp:282
typename Protocol::Stream Stream
Definition acceptor.hpp:42
virtual void close() noexcept
close acceptor.
Definition acceptor.hpp:166
int protocol() const noexcept
get acceptor protocol.
Definition acceptor.hpp:266
int type() const noexcept
get the protocol communication semantic.
Definition acceptor.hpp:257
virtual ~BasicStreamAcceptor()
destroy instance.
Definition acceptor.hpp:95
virtual Stream acceptStream() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:210
virtual int create(const Endpoint &endpoint) noexcept
create acceptor
Definition acceptor.hpp:105
typename Protocol::Socket Socket
Definition acceptor.hpp:41
int handle() const noexcept
get socket native handle.
Definition acceptor.hpp:275
BasicStreamAcceptor(BasicStreamAcceptor &&other)
move constructor.
Definition acceptor.hpp:66
Protocol _protocol
protocol.
Definition acceptor.hpp:285
BasicStreamAcceptor & operator=(const BasicStreamAcceptor &other)=delete
copy assignment operator.
basic TLS acceptor class.
Definition protocol.hpp:54
static DH * getDh2236()
generate openssl Diffie-Hellman parameters.
Definition acceptor.hpp:605
int setCipher_1_3(const std::string &cipher)
set the cipher list (TLSv1.3).
Definition acceptor.hpp:570
void setVerify(bool verify, int depth=-1)
Enable/Disable the verification of the peer certificate.
Definition acceptor.hpp:533
typename Protocol::Endpoint Endpoint
Definition acceptor.hpp:295
join::SslCtxPtr _tlsContext
SSL/TLS context.
Definition acceptor.hpp:650
int _sessionId
SSL session id.
Definition acceptor.hpp:653
virtual Socket acceptEncrypted() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:435
int setCipher(const std::string &cipher)
set the cipher list (TLSv1.2 and below).
Definition acceptor.hpp:554
typename Protocol::Socket Socket
Definition acceptor.hpp:296
BasicTlsAcceptor(BasicTlsAcceptor &&other)
move constructor.
Definition acceptor.hpp:382
BasicTlsAcceptor()
create the acceptor instance.
Definition acceptor.hpp:302
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition acceptor.hpp:480
virtual Stream acceptStreamEncrypted() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:467
BasicTlsAcceptor(const BasicTlsAcceptor &other)=delete
copy constructor.
int setCaCertificate(const std::string &caFile)
Set the location of the trusted CA certificate.
Definition acceptor.hpp:513
BasicTlsAcceptor & operator=(const BasicTlsAcceptor &other)=delete
copy assignment operator.
typename Protocol::Stream Stream
Definition acceptor.hpp:297
virtual Socket accept() const override
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:408
Event handler interface class.
Definition reactor.hpp:46
const std::string key(65, 'a')
key.
Definition acceptor.hpp:32
std::unique_ptr< SSL_CTX, SslCtxDelete > SslCtxPtr
Definition openssl.hpp:240
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:403
const std::string defaultCipher_1_3
Definition openssl.cpp:40
std::unique_ptr< EC_KEY, EcdhKeyDelete > EcdhKeyPtr
Definition openssl.hpp:271
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150
std::unique_ptr< DH, DhKeyDelete > DhKeyPtr
Definition openssl.hpp:256
const std::string defaultCipher
Definition openssl.cpp:36
std::unique_ptr< STACK_OF(X509_NAME), StackOfX509NameDelete > StackOfX509NamePtr
Definition openssl.hpp:195
Definition error.hpp:137