join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
acceptor.hpp
Go to the documentation of this file.
1
25#ifndef __JOIN_ACCEPTOR_HPP__
26#define __JOIN_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, endpoint.protocol ().protocol ());
114 if (this->_handle == -1)
115 {
116 lastError = std::make_error_code (static_cast <std::errc> (errno));
117 this->close ();
118 return -1;
119 }
120
121 if (endpoint.protocol ().family () == AF_INET6)
122 {
123 int off = 0;
124
125 if (::setsockopt (this->_handle, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof (off)) == -1)
126 {
127 lastError = std::make_error_code (static_cast <std::errc> (errno));
128 this->close ();
129 return -1;
130 }
131 }
132
133 if (endpoint.protocol ().family () == AF_UNIX)
134 {
135 ::unlink (endpoint.device ().c_str ());
136 }
137 else if (endpoint.protocol ().protocol () == IPPROTO_TCP)
138 {
139 int on = 1;
140
141 if (::setsockopt (this->_handle, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1)
142 {
143 lastError = std::make_error_code (static_cast <std::errc> (errno));
144 this->close ();
145 return -1;
146 }
147 }
148
149 if ((::bind (this->_handle, endpoint.addr (), endpoint.length ()) == -1) || (::listen (this->_handle, SOMAXCONN) == -1))
150 {
151 lastError = std::make_error_code (static_cast <std::errc> (errno));
152 this->close ();
153 return -1;
154 }
155
156 this->_protocol = endpoint.protocol ();
157
158 return 0;
159 }
160
164 virtual void close () noexcept
165 {
166 if (this->_handle != -1)
167 {
168 ::close (this->_handle);
169 this->_handle = -1;
170 }
171
172 this->_protocol = Protocol ();
173 }
174
179 virtual Socket accept () const
180 {
181 struct sockaddr_storage sa;
182 socklen_t sa_len = sizeof (struct sockaddr_storage);
183 Socket sock;
184
185 sock._handle = ::accept (this->_handle, reinterpret_cast <struct sockaddr*> (&sa), &sa_len);
186 if (sock._handle == -1)
187 {
188 lastError = std::make_error_code (static_cast <std::errc> (errno));
189 return sock;
190 }
191
192 sock._remote = Endpoint (reinterpret_cast <struct sockaddr*> (&sa), sa_len);
193 sock._state = Socket::Connected;
194
195 if (sock.protocol () == IPPROTO_TCP)
196 {
197 sock.setOption (Socket::NoDelay, 1);
198 }
199 sock.setMode (Socket::NonBlocking);
200
201 return sock;
202 }
203
208 virtual Stream acceptStream () const
209 {
210 Stream stream;
211 stream.socket () = this->accept ();
212 return stream;
213 }
214
220 {
221 struct sockaddr_storage sa;
222 socklen_t sa_len = sizeof (struct sockaddr_storage);
223
224 if (::getsockname (this->_handle, reinterpret_cast <struct sockaddr*> (&sa), &sa_len) == -1)
225 {
226 lastError = std::make_error_code (static_cast <std::errc> (errno));
227 return {};
228 }
229
230 return Endpoint (reinterpret_cast <struct sockaddr*> (&sa), sa_len);
231 }
232
237 bool opened () const noexcept
238 {
239 return (this->_handle != -1);
240 }
241
246 int family () const noexcept
247 {
248 return this->_protocol.family ();
249 }
250
255 int type () const noexcept
256 {
257 return this->_protocol.type ();
258 }
259
264 int protocol () const noexcept
265 {
266 return this->_protocol.protocol ();
267 }
268
273 int handle () const noexcept override
274 {
275 return this->_handle;
276 }
277
278 protected:
280 int _handle = -1;
281
283 Protocol _protocol;
284 };
285
289 template <class Protocol>
290 class BasicTlsAcceptor : public BasicStreamAcceptor <Protocol>
291 {
292 public:
293 using Endpoint = typename Protocol::Endpoint;
294 using Socket = typename Protocol::Socket;
295 using Stream = typename Protocol::Stream;
296
301 : BasicStreamAcceptor <Protocol> (),
302 _tlsContext (SSL_CTX_new (TLS_server_method ())),
303 _sessionId (randomize <int> ())
304 {
305 // enable the OpenSSL bug workaround options.
306 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_ALL);
307
308 // disallow compression.
309 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_NO_COMPRESSION);
310
311 // disallow usage of SSLv2, SSLv3, TLSv1 and TLSv1.1 which are considered insecure.
312 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
313
314 // choose the cipher according to the server's preferences.
315 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_CIPHER_SERVER_PREFERENCE);
316
317 // setup write mode.
318 SSL_CTX_set_mode (_tlsContext.get (), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
319
320 // automatically renegotiates.
321 SSL_CTX_set_mode (_tlsContext.get (), SSL_MODE_AUTO_RETRY);
322
323 // enable SSL session caching.
324 SSL_CTX_set_session_id_context (_tlsContext.get (), reinterpret_cast <const unsigned char *> (&_sessionId), sizeof (_sessionId));
325
326 // no verification by default.
327 SSL_CTX_set_verify (_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
328
329 // set default TLSv1.2 and below cipher suites.
330 SSL_CTX_set_cipher_list (_tlsContext.get (), join::defaultCipher.c_str ());
331
332 // set default TLSv1.3 cipher suites.
333 SSL_CTX_set_ciphersuites (_tlsContext.get (), join::defaultCipher_1_3.c_str ());
334
335 // disallow client-side renegotiation.
336 SSL_CTX_set_options (_tlsContext.get (), SSL_OP_NO_RENEGOTIATION);
337
338 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
339 // use the default built-in Diffie-Hellman parameters.
340 SSL_CTX_set_dh_auto (_tlsContext.get (), 1);
341
342 // Set elliptic curve Diffie-Hellman key.
343 SSL_CTX_set1_groups_list (_tlsContext.get (), join::defaultCurve.c_str ());
344 #else
345 // Set Diffie-Hellman key.
347 if (dh)
348 {
349 SSL_CTX_set_tmp_dh (_tlsContext.get (), dh.get ());
350 }
351
352 // Set elliptic curve Diffie-Hellman key.
353 join::EcdhKeyPtr ecdh (EC_KEY_new_by_curve_name (NID_X9_62_prime256v1));
354 if (ecdh)
355 {
356 SSL_CTX_set_tmp_ecdh (_tlsContext.get (), ecdh.get ());
357 }
358 #endif
359 }
360
365 BasicTlsAcceptor (const BasicTlsAcceptor& other) = delete;
366
373
379 : BasicStreamAcceptor <Protocol> (std::move (other)),
380 _tlsContext (std::move (other._tlsContext)),
381 _sessionId (other._sessionId)
382 {
383 other._sessionId = 0;
384 }
385
392 {
393 BasicStreamAcceptor <Protocol>::operator= (std::move (other));
394 _tlsContext = std::move (other._tlsContext);
395 _sessionId = other._sessionId;
396 other._sessionId = 0;
397 return *this;
398 }
399
404 virtual Socket accept () const override
405 {
406 struct sockaddr_storage sa;
407 socklen_t sa_len = sizeof (struct sockaddr_storage);
408 Socket sock (join::SslCtxPtr (this->_tlsContext.get ()));
409 SSL_CTX_up_ref (this->_tlsContext.get ());
410
411 sock._handle = ::accept (this->_handle, reinterpret_cast <struct sockaddr*> (&sa), &sa_len);
412 if (sock._handle == -1)
413 {
414 lastError = std::make_error_code (static_cast <std::errc> (errno));
415 return sock;
416 }
417
418 sock._remote = Endpoint (reinterpret_cast <struct sockaddr*> (&sa), sa_len);
419 sock._state = Socket::Connected;
420
421 sock.setOption (Socket::NoDelay, 1);
422 sock.setMode (Socket::NonBlocking);
423
424 return sock;
425 }
426
431 virtual Socket acceptEncrypted () const
432 {
433 Socket sock = this->accept ();
434 if (!sock.connected ())
435 {
436 return sock;
437 }
438
439 sock._tlsHandle.reset (SSL_new (sock._tlsContext.get ()));
440 if (sock._tlsHandle == nullptr)
441 {
443 sock.close ();
444 return sock;
445 }
446
447 SSL_set_fd (sock._tlsHandle.get (), sock._handle);
448 SSL_set_accept_state (sock._tlsHandle.get ());
449 SSL_set_app_data (sock._tlsHandle.get (), &sock);
450 #ifdef DEBUG
451 SSL_set_info_callback (sock._tlsHandle.get (), Socket::infoWrapper);
452 #endif
453
454 sock._tlsState = Socket::Encrypted;
455
456 return sock;
457 }
458
464 {
465 Stream stream;
466 stream.socket () = this->acceptEncrypted ();
467 return stream;
468 }
469
476 int setCertificate (const std::string& cert, const std::string& key = "")
477 {
478 if (SSL_CTX_use_certificate_file (this->_tlsContext.get (), cert.c_str (), SSL_FILETYPE_PEM) == 0)
479 {
481 return -1;
482 }
483
484 if (key.size ())
485 {
486 if (SSL_CTX_use_PrivateKey_file (this->_tlsContext.get (), key.c_str(), SSL_FILETYPE_PEM) == 0)
487 {
489 return -1;
490 }
491 }
492
493 // check the consistency of the private key and the certificate.
494 if (SSL_CTX_check_private_key (this->_tlsContext.get ()) == 0)
495 {
497 this->close ();
498 return -1;
499 }
500
501 return 0;
502 }
503
509 int setCaCertificate (const std::string& caFile)
510 {
511 join::StackOfX509NamePtr certNames (SSL_load_client_CA_file (caFile.c_str ()));
512 if (certNames == nullptr)
513 {
515 return -1;
516 }
517
518 SSL_CTX_load_verify_locations (this->_tlsContext.get (), caFile.c_str (), nullptr);
519 SSL_CTX_set_client_CA_list (this->_tlsContext.get (), certNames.release ());
520
521 return 0;
522 }
523
529 void setVerify (bool verify, int depth = -1)
530 {
531 if (verify)
532 {
533 // SSL_VERIFY_PEER will lead the client to verify the server certificate.
534 // If the verification process fails, the TLS/SSL handshake is immediately terminated.
535 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_PEER, Socket::verifyWrapper);
536 SSL_CTX_set_verify_depth (this->_tlsContext.get (), depth);
537 }
538 else
539 {
540 // SSL_VERIFY_NONE will lead the client to continue the handshake regardless of the verification result.
541 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
542 }
543 }
544
550 int setCipher (const std::string& cipher)
551 {
552 if (SSL_CTX_set_cipher_list (this->_tlsContext.get (), cipher.c_str ()) == 0)
553 {
555 return -1;
556 }
557
558 return 0;
559 }
560
566 int setCipher_1_3 (const std::string &cipher)
567 {
568 if (SSL_CTX_set_ciphersuites (this->_tlsContext.get (), cipher.c_str ()) == 0)
569 {
571 return -1;
572 }
573
574 return 0;
575 }
576
577 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
583 int setCurve (const std::string &curves)
584 {
585 if (SSL_CTX_set1_groups_list (this->_tlsContext.get (), curves.c_str ()) == 0)
586 {
588 return -1;
589 }
590
591 return 0;
592 }
593 #else
594
595 protected:
601 static DH* getDh2236 ()
602 {
603 static unsigned char dhp_2236[] = {
604 0x0C, 0xA5, 0x51, 0x2B, 0x8F, 0xF7, 0xA8, 0x74, 0x4D, 0x52,
605 0xD7, 0xED, 0x97, 0x83, 0xA4, 0xD2, 0x8B, 0xF3, 0xE7, 0x92,
606 0xF0, 0x27, 0x1B, 0xA0, 0x80, 0x83, 0x19, 0xDD, 0x02, 0xEF,
607 0xA3, 0xE6, 0x13, 0x0A, 0x47, 0xE6, 0xF1, 0x3B, 0xC1, 0x5F,
608 0x63, 0xC4, 0x03, 0xBA, 0xAC, 0xAA, 0xA3, 0x44, 0xC2, 0x03,
609 0x6D, 0x62, 0x33, 0xAA, 0xF9, 0xA2, 0x5A, 0x98, 0xC2, 0xC0,
610 0x71, 0x6F, 0xB0, 0x93, 0x6A, 0x26, 0x92, 0x90, 0x95, 0xEA,
611 0xE8, 0x5F, 0x81, 0x50, 0x57, 0xB3, 0xB7, 0xE6, 0x3A, 0x3A,
612 0x90, 0x15, 0x01, 0x2F, 0xC7, 0x8F, 0xAA, 0x0C, 0xAE, 0xC0,
613 0xFF, 0x3A, 0xA7, 0x26, 0x5C, 0x87, 0xC2, 0x00, 0x68, 0xCA,
614 0x02, 0x06, 0x50, 0x44, 0xEE, 0x75, 0xE7, 0xFF, 0x16, 0xD1,
615 0x0F, 0x64, 0x51, 0x97, 0x52, 0x54, 0x69, 0xF0, 0x31, 0x81,
616 0x4D, 0xEB, 0xF5, 0xA8, 0xB3, 0x7B, 0x48, 0x60, 0xBD, 0xC7,
617 0xC9, 0x6E, 0x97, 0x86, 0x9B, 0xE6, 0x66, 0x4E, 0x1D, 0xE5,
618 0x6F, 0xBA, 0xC5, 0x3D, 0xFD, 0x3F, 0x34, 0x69, 0x6F, 0xC0,
619 0xFA, 0x8D, 0x42, 0x73, 0xA2, 0x49, 0xDE, 0xB6, 0x8D, 0x71,
620 0x15, 0xFC, 0xB4, 0x18, 0x31, 0x5A, 0x24, 0xD0, 0x5E, 0xA8,
621 0xE0, 0xD8, 0x1C, 0xF8, 0x0F, 0x1F, 0x59, 0x22, 0x5A, 0x07,
622 0x75, 0x06, 0x98, 0x58, 0xE1, 0xF6, 0xA5, 0x53, 0xFD, 0x66,
623 0x1E, 0x8F, 0x41, 0x63, 0x61, 0xA1, 0x79, 0x0D, 0x3B, 0xA7,
624 0xF4, 0xBD, 0x72, 0xEB, 0xE1, 0xDC, 0xE2, 0xC9, 0x9B, 0x41,
625 0xF6, 0x33, 0x3F, 0x9F, 0x0C, 0x33, 0x7B, 0xF2, 0x90, 0x68,
626 0x28, 0xD3, 0x5A, 0xC1, 0x5C, 0xDE, 0x15, 0x11, 0xF4, 0xDD,
627 0xCB, 0x09, 0x78, 0x63, 0x3B, 0xB6, 0xE8, 0xEE, 0x9A, 0x48,
628 0xE9, 0x79, 0x80, 0x3F, 0x34, 0x8D, 0xB9, 0x24, 0x8D, 0x94,
629 0x88, 0xA9, 0x75, 0xA5, 0x19, 0x05, 0x8D, 0x77, 0x20, 0xAF,
630 0xC2, 0xC9, 0x7B, 0xD2, 0x51, 0xEE, 0x17, 0x22, 0xAC, 0x33,
631 0xA8, 0xA6, 0x1B, 0x8B, 0xE3, 0x79, 0xF3, 0xE8, 0x3B, 0x6B
632 };
633
634 static unsigned char dhg_2236[] = {
635 0x02
636 };
637
638 DH *dh = DH_new ();
639 if (dh == nullptr)
640 {
641 return nullptr;
642 }
643
644 BIGNUM *p = BN_bin2bn (dhp_2236, sizeof (dhp_2236), nullptr);
645 BIGNUM *g = BN_bin2bn (dhg_2236, sizeof (dhg_2236), nullptr);
646 if (p == nullptr || g == nullptr || !DH_set0_pqg (dh, p, nullptr, g))
647 {
648 DH_free (dh);
649 BN_free (p);
650 BN_free (g);
651 return nullptr;
652 }
653
654 return dh;
655 }
656 #endif
657
658 protected:
661
663 int _sessionId = 0;
664 };
665}
666
667#endif
basic stream acceptor class.
Definition protocol.hpp:45
BasicStreamAcceptor()=default
create the acceptor instance.
bool opened() const noexcept
check if the socket is opened.
Definition acceptor.hpp:237
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:179
typename Protocol::Endpoint Endpoint
Definition acceptor.hpp:40
Endpoint localEndpoint() const
determine the local endpoint associated with this socket.
Definition acceptor.hpp:219
int family() const noexcept
get address family.
Definition acceptor.hpp:246
int _handle
socket handle.
Definition acceptor.hpp:280
typename Protocol::Stream Stream
Definition acceptor.hpp:42
virtual void close() noexcept
close acceptor.
Definition acceptor.hpp:164
int protocol() const noexcept
get acceptor protocol.
Definition acceptor.hpp:264
int type() const noexcept
get the protocol communication semantic.
Definition acceptor.hpp:255
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:208
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 override
get socket native handle.
Definition acceptor.hpp:273
BasicStreamAcceptor(BasicStreamAcceptor &&other)
move constructor.
Definition acceptor.hpp:66
Protocol _protocol
protocol.
Definition acceptor.hpp:283
BasicStreamAcceptor & operator=(const BasicStreamAcceptor &other)=delete
copy assignment operator.
basic TLS acceptor class.
Definition protocol.hpp:46
static DH * getDh2236()
generate openssl Diffie-Hellman parameters.
Definition acceptor.hpp:601
int setCipher_1_3(const std::string &cipher)
set the cipher list (TLSv1.3).
Definition acceptor.hpp:566
void setVerify(bool verify, int depth=-1)
Enable/Disable the verification of the peer certificate.
Definition acceptor.hpp:529
typename Protocol::Endpoint Endpoint
Definition acceptor.hpp:293
join::SslCtxPtr _tlsContext
SSL/TLS context.
Definition acceptor.hpp:660
int _sessionId
SSL session id.
Definition acceptor.hpp:663
virtual Socket acceptEncrypted() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:431
int setCipher(const std::string &cipher)
set the cipher list (TLSv1.2 and below).
Definition acceptor.hpp:550
typename Protocol::Socket Socket
Definition acceptor.hpp:294
BasicTlsAcceptor(BasicTlsAcceptor &&other)
move constructor.
Definition acceptor.hpp:378
BasicTlsAcceptor()
create the acceptor instance.
Definition acceptor.hpp:300
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition acceptor.hpp:476
virtual Stream acceptStreamEncrypted() const
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:463
BasicTlsAcceptor(const BasicTlsAcceptor &other)=delete
copy constructor.
int setCaCertificate(const std::string &caFile)
Set the location of the trusted CA certificate.
Definition acceptor.hpp:509
BasicTlsAcceptor & operator=(const BasicTlsAcceptor &other)=delete
copy assignment operator.
typename Protocol::Stream Stream
Definition acceptor.hpp:295
virtual Socket accept() const override
accept new connection and fill in the client object with connection parameters.
Definition acceptor.hpp:404
Event handler interface class.
Definition reactor.hpp:44
const std::string key(65, 'a')
key.
Definition acceptor.hpp:32
std::unique_ptr< EC_KEY, EcdhKeyDelete > EcdhKeyPtr
Definition openssl.hpp:271
std::error_code make_error_code(join::Errc code)
Create an std::error_code object.
Definition error.cpp:154
std::unique_ptr< DH, DhKeyDelete > DhKeyPtr
Definition openssl.hpp:256
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:395
std::unique_ptr< STACK_OF(X509_NAME), StackOfX509NameDelete > StackOfX509NamePtr
Definition openssl.hpp:195
const std::string defaultCipher_1_3
Definition openssl.cpp:39
std::unique_ptr< SSL_CTX, SslCtxDelete > SslCtxPtr
Definition openssl.hpp:240
const std::string defaultCipher
Definition openssl.cpp:36
Definition error.hpp:106