Initial commit
[udp-dtls-proxy.git] / dtls-port-forwarder.c++
blob4f4f9b3fe1d283f1c157f08614303e5d06e517fd
1 #include <climits>
2 #if defined(__OpenBSD__)
3 #include <errno.h>
4 #else
5 #include <asm-generic/errno.h>
6 #endif
8 #include <stdexcept>
9 #include <string>
10 #ifdef WIN32
11 #include <Ws2tcpip.h>
12 #include <winsock2.h>
13 #define in_port_t u_short
14 #define ssize_t int
15 #define my_tid_t DWORD
16 #else // UNIX/Linux
17 #include <arpa/inet.h>
18 #include <cstdlib>
19 #include <cstring>
20 #include <netdb.h>
21 #include <netinet/in.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #define my_tid_t pthread_t
29 #endif
31 #include <openssl/bio.h>
32 #include <openssl/err.h>
33 #include <openssl/opensslv.h>
34 #include <openssl/rand.h>
35 #include <openssl/ssl.h>
37 #include "3rdparty/popl.hpp"
39 using namespace std::string_literals;
41 static unsigned long id_thread(void) {
42 #ifdef WIN32
43 return (unsigned long)GetCurrentThreadId();
44 #else
45 return (unsigned long)pthread_self();
46 #endif
49 #define debug_print(x) \
50 if (false) \
51 fprintf(stderr, \
52 "Thread %lx:%s:%lld:%d:%s\n", \
53 id_thread(), \
54 __func__, \
55 time(NULL), \
56 __LINE__, \
57 x); \
58 ; \
59 ; // fflush(stderr);
60 //#define debug_print(x)
62 static auto closer = [](int * sock_ptr) {
63 #ifdef WIN32
64 closesocket(*sock_ptr);
65 #else
66 close(*sock_ptr);
67 #endif
68 debug_print(("Closed socket="s + std::to_string(*sock_ptr)).c_str());
71 void my_explain_recvfrom_error(int arg) {
72 switch (arg) {
73 case EAGAIN:
74 debug_print(
75 "The socket is marked nonblocking and the receive operation would "
76 " "
77 "block, or a receive timeout had been set and the timeout expired "
78 " "
79 "before data was received. POSIX.1 allows either error to be "
80 "returned for this case, and does not require these constants to "
81 " "
82 "have the same value, so a portable application should check for "
83 "both possibilities.");
84 break;
85 case EBADF:
86 debug_print("The argument sockfd is an invalid file descriptor.");
87 break;
88 case ECONNREFUSED:
89 debug_print(
90 "A remote host refused to allow the network connection( "
91 "typically because it is not running the requested service) "
92 ".");
93 break;
94 case EFAULT:
95 debug_print(
96 "The receive buffer pointer(s) point outside the process's address "
97 "space.");
98 break;
99 case EINTR:
100 debug_print(
101 "The receive was interrupted by delivery of a signal before "
102 "any data was available; see signal(7).");
103 break;
104 case EINVAL:
105 debug_print("Invalid argument passed.");
106 break;
107 case ENOMEM:
108 debug_print("Could not allocate memory for recvmsg().");
109 break;
110 case ENOTCONN:
111 debug_print("The socket is associated with a connection-oriented "
112 "protocol and has "
113 "not been connected (see connect(2) and accept(2)).");
114 break;
115 case ENOTSOCK:
116 debug_print("The file descriptor sockfd does not refer to a socket.");
117 break;
118 default:
119 debug_print(
120 ("Cannot explain recvfrom error "s + std::to_string(errno)).c_str());
124 typedef union {
125 struct sockaddr_storage ss;
126 struct sockaddr_in s4;
127 struct sockaddr_in6 s6;
128 } my_ip46_address;
130 std::string my_ip46_address_to_string(my_ip46_address address_bin) {
131 char addrbuf[INET6_ADDRSTRLEN];
132 short port = -1;
133 if (address_bin.ss.ss_family == AF_INET) {
134 inet_ntop(
135 AF_INET, &address_bin.s4.sin_addr, addrbuf, INET6_ADDRSTRLEN);
136 port = ntohs(address_bin.s4.sin_port);
138 } else {
139 inet_ntop(
140 AF_INET6, &address_bin.s6.sin6_addr, addrbuf, INET6_ADDRSTRLEN);
141 port = ntohs(address_bin.s6.sin6_port);
144 return "["s + addrbuf + "]:" + std::to_string(port);
147 void my_ip46_address_init(my_ip46_address & address_bin,
148 char const * address_txt,
149 short const port) {
150 // unp address resolution
151 struct addrinfo hints;
152 struct addrinfo * res;
153 struct addrinfo * ressave;
154 std::memset(&hints, 0, sizeof(struct addrinfo));
155 hints.ai_flags = AI_PASSIVE;
156 hints.ai_family = AF_UNSPEC;
157 hints.ai_socktype = SOCK_DGRAM;
158 int unp_n;
159 // simple ip address code
160 std::memset(&address_bin, 0, sizeof(struct sockaddr_storage));
161 debug_print(
162 ("Initing address "s + address_txt + ":" + std::to_string(port))
163 .c_str());
165 #if !defined(__OpenBSD__)
166 if (inet_pton(AF_INET6,
167 ("::FFFF:"s + address_txt).c_str(),
168 &address_bin.s6.sin6_addr) == 1) {
169 address_bin.s6.sin6_family = AF_INET6;
170 address_bin.s6.sin6_port = htons(port);
171 } else /**/
172 #endif
173 if (inet_pton(AF_INET, address_txt, &address_bin.s4.sin_addr) == 1) {
174 address_bin.s4.sin_family = AF_INET;
175 debug_print(("It is an ipv4 address "s).c_str());
177 #ifdef HAVE_SIN_LEN
178 address_bin.s4.sin_len = sizeof(struct sockaddr_in);
179 #endif
180 address_bin.s4.sin_port = htons(port);
181 } else if (inet_pton(AF_INET6, address_txt, &address_bin.s6.sin6_addr) ==
182 1) {
183 address_bin.s6.sin6_family = AF_INET6;
184 debug_print(("It is an ipv6 address "s).c_str());
185 #ifdef HAVE_SIN6_LEN
186 address_bin.s6.sin6_len = sizeof(struct sockaddr_in6);
187 #endif
188 address_bin.s6.sin6_port = htons(port);
189 } else if ((unp_n = getaddrinfo(address_txt, NULL, &hints, &res)) == 0) {
190 ressave = res;
191 debug_print("It's a domain name!");
192 address_bin.ss.ss_family = res->ai_family;
193 if (res->ai_family == AF_INET) {
194 debug_print(("ipv4 domain name"s).c_str());
195 std::memcpy(&address_bin.s4.sin_addr,
196 &(((struct sockaddr_in *)res->ai_addr)->sin_addr),
197 sizeof(struct sockaddr_in));
198 address_bin.s4.sin_port = htons(port);
199 #ifdef HAVE_SIN_LEN
200 address_bin.s4.sin_len = sizeof(struct sockaddr_in);
201 #endif
202 } else if (res->ai_family == AF_INET6) {
203 debug_print(("ipv6 domain name"s).c_str());
204 std::memcpy(&address_bin.s6.sin6_addr,
205 &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr),
206 sizeof(struct sockaddr_in6));
207 address_bin.s6.sin6_port = htons(port);
208 #ifdef HAVE_SIN6_LEN
209 address_bin.s6.sin6_len = sizeof(struct sockaddr_in6);
210 #endif
211 } else {
212 throw std::logic_error("Unknown address type for domain name.");
214 debug_print(
215 ("Connecting to: "s + my_ip46_address_to_string(address_bin))
216 .c_str());
217 freeaddrinfo(res);
218 } else {
219 throw std::out_of_range("cannot set an address from address="s +
220 address_txt +
221 " and port=" + std::to_string(port));
224 // line 1229 connect TODO
226 void my_ip46_connect(int socket, my_ip46_address remote_addr) {
227 if (remote_addr.ss.ss_family == AF_INET) {
228 if (connect(socket,
229 (struct sockaddr *)&remote_addr,
230 sizeof(struct sockaddr_in))) {
231 perror("my_ip46_connect:connect4");
232 throw std::runtime_error("connect ipv4 failed");
234 } else if (remote_addr.ss.ss_family == AF_INET6) {
235 int const off = 0;
236 setsockopt(
237 socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
238 if (connect(socket,
239 (struct sockaddr *)&remote_addr,
240 sizeof(struct sockaddr_in6))) {
241 perror("my_ip46_connect:connect6");
242 throw std::runtime_error("connect ipv6 failed");
244 } else {
245 debug_print("my_ip46_connect:wrong_family");
246 throw std::logic_error("my_ip46_connect: remote_addr.ss.ss_family not "
247 "AF_INET and AF_INET6");
251 void my_ip46_bind(int socket, my_ip46_address local_addr) {
252 std::cout << "ss_family=" << local_addr.ss.ss_family << std::endl;
253 if (local_addr.ss.ss_family == AF_INET) {
254 if (bind(socket,
255 (const struct sockaddr *)&local_addr,
256 sizeof(struct sockaddr_in))) {
257 perror("my_ip46_bind:ipv4");
258 throw std::runtime_error("bind ipv4 failed");
260 } else if (local_addr.ss.ss_family == AF_INET6) {
261 int const off = 0;
262 setsockopt(
263 socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
264 if (bind(socket,
265 (const struct sockaddr *)&local_addr,
266 sizeof(struct sockaddr_in6))) {
267 perror("my_ip46_bind:ipv6");
268 throw std::runtime_error("bind ipv6 failed");
270 } else {
271 debug_print("my_ip46_bind:wrong_family");
272 throw std::logic_error("my_ip46_bind: local_addr.ss.ss_family not "
273 "AF_INET and AF_INET6");
277 typedef struct pass_info {
278 my_ip46_address server_addr, client_addr;
279 SSL * ssl;
280 int socket_reverse_forward = -1;
281 int socket_direct_forward = -1;
282 my_ip46_address udp_ip_and_port;
283 bool allow_udp_ip_port_from_inbound = true;
284 unsigned int timeout_sec = 10;
285 unsigned int ntimeouts = 3;
286 } pass_info_t;
288 void my_create_thread(
289 #ifdef WIN32
290 (DWORD WINAPI)(*thread_function(LPVOID * info))
291 #else
292 void(*thread_function(void * info))
293 #endif
295 void * info,
296 my_tid_t * tid) {
297 #ifdef WIN32
298 if (CreateThread(
299 NULL, 0, (LPTHREAD_START_ROUTINE)thread_function, info, 0, tid) ==
300 NULL) {
301 exit(-1);
303 #else
304 if (pthread_create(tid, NULL, thread_function, info) != 0) {
305 perror("pthread_create");
306 exit(-1);
308 #endif
311 #ifdef WIN32
312 #define MY_EXIT_THREAD(retval) ExitThread(retval)
313 #else
314 #define MY_EXIT_THREAD(retval) pthread_exit((void *)retval)
315 #endif
317 #define BUFFER_SIZE (1 << 16)
318 #define COOKIE_SECRET_LENGTH 16
320 int verbose = 0;
321 int veryverbose = 0;
322 unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
323 int cookie_initialized = 0;
325 #if WIN32
326 static HANDLE * mutex_buf = NULL;
327 #else
328 static pthread_mutex_t * mutex_buf = NULL;
329 #endif
331 static void locking_function(int mode, int n, const char * file, int line) {
332 if (mode & CRYPTO_LOCK)
333 #ifdef WIN32
334 WaitForSingleObject(mutex_buf[n], INFINITE);
335 else
336 ReleaseMutex(mutex_buf[n]);
337 #else
338 pthread_mutex_lock(&mutex_buf[n]);
339 else
340 pthread_mutex_unlock(&mutex_buf[n]);
341 #endif
344 int THREAD_setup() {
345 int i;
347 #ifdef WIN32
348 mutex_buf = (HANDLE *)malloc(CRYPTO_num_locks() * sizeof(HANDLE));
349 #else
350 mutex_buf = (pthread_mutex_t *)malloc(CRYPTO_num_locks() *
351 sizeof(pthread_mutex_t));
352 #endif
353 if (!mutex_buf)
354 return 0;
355 for (i = 0; i < CRYPTO_num_locks(); i++)
356 #ifdef WIN32
357 mutex_buf[i] = CreateMutex(NULL, FALSE, NULL);
358 #else
359 pthread_mutex_init(&mutex_buf[i], NULL);
360 #endif
361 CRYPTO_set_id_callback(id_thread);
362 CRYPTO_set_locking_callback(locking_function);
363 return 1;
366 int THREAD_cleanup() {
367 int i;
369 if (!mutex_buf)
370 return 0;
372 CRYPTO_set_id_callback(NULL);
373 CRYPTO_set_locking_callback(NULL);
374 for (i = 0; i < CRYPTO_num_locks(); i++)
375 #ifdef WIN32
376 CloseHandle(mutex_buf[i]);
377 #else
378 pthread_mutex_destroy(&mutex_buf[i]);
379 #endif
380 free(mutex_buf);
381 mutex_buf = NULL;
382 return 1;
385 int handle_socket_error() {
386 switch (errno) {
387 case EINTR:
388 /* Interrupted system call.
389 * Just ignore.
391 printf("Interrupted system call!\n");
392 return 1;
393 case EBADF:
394 /* Invalid socket.
395 * Must close connection.
397 printf("Invalid socket!\n");
398 return 0;
399 break;
400 #ifdef EHOSTDOWN
401 case EHOSTDOWN:
402 /* Host is down.
403 * Just ignore, might be an attacker
404 * sending fake ICMP messages.
406 printf("Host is down!\n");
407 return 1;
408 #endif
409 #ifdef ECONNRESET
410 case ECONNRESET:
411 /* Connection reset by peer.
412 * Just ignore, might be an attacker
413 * sending fake ICMP messages.
415 printf("Connection reset by peer!\n");
416 return 1;
417 #endif
418 case ENOMEM:
419 /* Out of memory.
420 * Must close connection.
422 printf("Out of memory!\n");
423 return 0;
424 break;
425 case EACCES:
426 /* Permission denied.
427 * Just ignore, we might be blocked
428 * by some firewall policy. Try again
429 * and hope for the best.
431 printf("Permission denied!\n");
432 return 1;
433 break;
434 default:
435 /* Something unexpected happened */
436 printf("Unexpected error! (errno = %d)\n", errno);
437 perror("Perror message");
438 return 0;
439 break;
441 return 0;
444 int generate_cookie(SSL * ssl,
445 unsigned char * cookie,
446 unsigned int * cookie_len) {
447 unsigned char *buffer, result[EVP_MAX_MD_SIZE];
448 unsigned int length = 0, resultlength;
449 my_ip46_address peer;
451 /* Initialize a random secret */
452 if (!cookie_initialized) {
453 if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH)) {
454 printf("error setting random cookie secret\n");
455 return 0;
457 cookie_initialized = 1;
460 /* Read peer information */
461 (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
463 /* Create buffer with peer's address and port */
464 length = 0;
465 switch (peer.ss.ss_family) {
466 case AF_INET:
467 length += sizeof(struct in_addr);
468 break;
469 case AF_INET6:
470 length += sizeof(struct in6_addr);
471 break;
472 default:
473 OPENSSL_assert(0);
474 break;
476 length += sizeof(in_port_t);
477 buffer = (unsigned char *)OPENSSL_malloc(length);
479 if (buffer == NULL) {
480 printf("out of memory\n");
481 return 0;
484 switch (peer.ss.ss_family) {
485 case AF_INET:
486 std::memcpy(buffer, &peer.s4.sin_port, sizeof(in_port_t));
487 std::memcpy(buffer + sizeof(peer.s4.sin_port),
488 &peer.s4.sin_addr,
489 sizeof(struct in_addr));
490 break;
491 case AF_INET6:
492 std::memcpy(buffer, &peer.s6.sin6_port, sizeof(in_port_t));
493 std::memcpy(buffer + sizeof(in_port_t),
494 &peer.s6.sin6_addr,
495 sizeof(struct in6_addr));
496 break;
497 default:
498 OPENSSL_assert(0);
499 break;
502 /* Calculate HMAC of buffer using the secret */
503 HMAC(EVP_sha1(),
504 (const void *)cookie_secret,
505 COOKIE_SECRET_LENGTH,
506 (const unsigned char *)buffer,
507 length,
508 result,
509 &resultlength);
510 OPENSSL_free(buffer);
512 std::memcpy(cookie, result, resultlength);
513 *cookie_len = resultlength;
515 return 1;
518 int verify_cookie(SSL * ssl,
519 const unsigned char * cookie,
520 unsigned int cookie_len) {
521 unsigned char *buffer, result[EVP_MAX_MD_SIZE];
522 unsigned int length = 0, resultlength;
523 my_ip46_address peer;
525 /* If secret isn't initialized yet, the cookie can't be valid */
526 if (!cookie_initialized)
527 return 0;
529 /* Read peer information */
530 (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
532 /* Create buffer with peer's address and port */
533 length = 0;
534 switch (peer.ss.ss_family) {
535 case AF_INET:
536 length += sizeof(struct in_addr);
537 break;
538 case AF_INET6:
539 length += sizeof(struct in6_addr);
540 break;
541 default:
542 OPENSSL_assert(0);
543 break;
545 length += sizeof(in_port_t);
546 buffer = (unsigned char *)OPENSSL_malloc(length);
548 if (buffer == NULL) {
549 printf("out of memory\n");
550 return 0;
553 switch (peer.ss.ss_family) {
554 case AF_INET:
555 std::memcpy(buffer, &peer.s4.sin_port, sizeof(in_port_t));
556 std::memcpy(buffer + sizeof(in_port_t),
557 &peer.s4.sin_addr,
558 sizeof(struct in_addr));
559 break;
560 case AF_INET6:
561 std::memcpy(buffer, &peer.s6.sin6_port, sizeof(in_port_t));
562 std::memcpy(buffer + sizeof(in_port_t),
563 &peer.s6.sin6_addr,
564 sizeof(struct in6_addr));
565 break;
566 default:
567 OPENSSL_assert(0);
568 break;
571 /* Calculate HMAC of buffer using the secret */
572 HMAC(EVP_sha1(),
573 (const void *)cookie_secret,
574 COOKIE_SECRET_LENGTH,
575 (const unsigned char *)buffer,
576 length,
577 result,
578 &resultlength);
579 OPENSSL_free(buffer);
581 if (cookie_len == resultlength &&
582 memcmp(result, cookie, resultlength) == 0)
583 return 1;
585 return 0;
588 int dtls_verify_callback(int ok, X509_STORE_CTX * ctx) {
589 /* This function should ask the user
590 * if he trusts the received certificate.
591 * Here we always trust.
593 return 1;
596 #define handle_error_en(en, msg) \
597 do { \
598 errno = en; \
599 perror(msg); \
600 exit(EXIT_FAILURE); \
601 } while (0)
603 #ifdef WIN32
604 DWORD WINAPI thread_udp_to_dtls(LPVOID * info)
605 #else
606 void * thread_udp_to_dtls(void * info)
607 #endif
609 debug_print("spawned");
610 int s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
611 debug_print("enabled cancel");
612 if (s != 0)
613 handle_error_en(s, "pthread_setcancelstate: write_dtls");
614 debug_print("handled cancel error");
615 pass_info_t * pinfo = static_cast<pass_info_t *>(info);
616 SSL * ssl = pinfo->ssl;
617 int udp_socket = pinfo->socket_reverse_forward;
618 if (udp_socket < 0)
619 throw std::logic_error("client_reverse_forward_socket is not init");
620 struct sockaddr_storage useless_;
621 struct sockaddr * recvfrom_udp_target =
622 (pinfo->allow_udp_ip_port_from_inbound
623 ? reinterpret_cast<struct sockaddr *>(&(pinfo->udp_ip_and_port.ss))
624 : reinterpret_cast<struct sockaddr *>(&useless_));
626 char dtls_send_buffer[BUFFER_SIZE] = "hello, world";
627 int buffer_len = strlen(dtls_send_buffer);
629 struct timeval t_begin {};
630 gettimeofday(&t_begin, NULL);
631 struct timeval t_end {};
632 while (!(SSL_get_shutdown(ssl))) { // & SSL_RECEIVED_SHUTDOWN
633 gettimeofday(&t_end, NULL);
634 debug_print(("packet processing took "s +
635 std::to_string((t_end.tv_sec - t_begin.tv_sec) * 1000000 +
636 (t_end.tv_usec - t_begin.tv_usec)) +
637 " usec")
638 .c_str());
639 t_begin = t_end;
641 debug_print("-------------------------------------------------------");
642 if (BUFFER_SIZE < 1600)
643 throw std::logic_error("udp_to_dtls:buffer too small="s +
644 std::to_string(BUFFER_SIZE));
645 socklen_t sa_len = sizeof(sockaddr_storage);
647 ssize_t udp_read_len = recvfrom(udp_socket,
648 dtls_send_buffer,
649 BUFFER_SIZE,
651 recvfrom_udp_target,
652 &sa_len);
653 int my_errno = errno;
654 if (udp_read_len < 0) {
655 if (errno == EWOULDBLOCK) {
656 debug_print("udp_to_dtls:Reading from udp socket timed out."
657 " I need to send something like a keepalive?");
658 continue;
659 } else if (errno == ECONNREFUSED) {
660 debug_print(
661 "udp socket has ECONNREFUSED bogus error. (debug it!)");
662 continue;
663 } else if (errno == EINTR) {
664 debug_print(
665 "udp socket returned EINTR. dropping datagram. (Debug it!)");
666 continue;
667 } else {
668 auto a =
669 ("unexpected error when reading from udp socket on client, errno="s +
670 std::to_string(errno));
671 debug_print(a.c_str());
672 my_explain_recvfrom_error(my_errno);
673 throw std::runtime_error(a);
676 // if (verbose) {
677 // fprintf(
678 // stderr,
679 // "\nThread %lx: got datagram from %s Size=%zd\n",
680 // id_thread(),
681 // my_ip46_address_to_string(pinfo->server_last_received_udp_addr)
682 // .c_str(),
683 // server_udp_read_len);
684 // }
685 socklen_t dtls_write_len =
686 SSL_write(ssl, dtls_send_buffer, udp_read_len);
687 debug_print("wrote one message");
688 switch (SSL_get_error(ssl, dtls_write_len)) {
689 case SSL_ERROR_NONE:
690 if (verbose) {
691 debug_print((""s + "wrote " + std::to_string(dtls_write_len) +
692 " bytes to dtls")
693 .c_str());
696 break;
697 case SSL_ERROR_WANT_WRITE:
698 // Can't write because of a renegotiation, so
699 // we actually have to retry sending this message...
700 debug_print("SSL_ERROR_WANT_WRITE");
701 break;
702 case SSL_ERROR_WANT_READ:
703 debug_print("SSL_ERROR_WANT_READ");
704 // continue with reading
705 break;
706 case SSL_ERROR_SYSCALL:
707 debug_print("udp_to_dtls:SSL_ERROR_SYSCALL:Socket write error: ");
708 if (!handle_socket_error()) {
709 SSL_shutdown(ssl);
710 MY_EXIT_THREAD(1);
712 break;
713 case SSL_ERROR_SSL:
714 fprintf(stderr, "udp_to_dtls:SSL write error: SSL_ERROR_SSL");
715 fprintf(stderr,
716 "%s (%d)\n",
717 ERR_error_string(ERR_get_error(), dtls_send_buffer),
718 SSL_get_error(ssl, dtls_write_len));
719 MY_EXIT_THREAD(1);
720 break;
721 default:
722 fprintf(stderr, "udp_to_dtls:Unexpected error while writing!\n");
723 MY_EXIT_THREAD(1);
724 break;
727 MY_EXIT_THREAD(0);
730 #ifdef WIN32
731 DWORD WINAPI thread_dtls_to_udp(LPVOID * info)
732 #else
733 void * thread_dtls_to_udp(void * info)
734 #endif
736 // This thread should be reading FROM DTLS, and putting the packets
737 // into the udp socket of the proxied service.
738 debug_print("spawned");
739 int s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
740 debug_print("enabled cancel");
741 if (s != 0)
742 handle_error_en(s, "pthread_setcancelstate: read_dtls");
743 debug_print("handled cancel error");
745 pass_info_t * pinfo = static_cast<pass_info_t *>(info);
746 SSL * ssl = pinfo->ssl;
747 // std::unique_ptr<SSL, int (*)(SSL *)> ssl_guard(ssl, SSL_shutdown);
748 int udp_socket = pinfo->socket_reverse_forward;
749 if (udp_socket < 0)
750 throw std::logic_error("dtls_to_udp:udp socket is not init");
751 int num_timeouts = 0;
752 int const max_timeouts = pinfo->ntimeouts;
753 char dtls_to_udp_buffer[BUFFER_SIZE] = "hello world";
755 struct timeval t_begin {};
756 gettimeofday(&t_begin, NULL);
757 struct timeval t_end {};
759 while (!(SSL_get_shutdown(ssl))) { // & SSL_RECEIVED_SHUTDOWN
760 gettimeofday(&t_end, NULL);
761 debug_print(("Iteration processing took "s +
762 std::to_string((t_end.tv_sec - t_begin.tv_sec) * 1000000 +
763 (t_end.tv_usec - t_begin.tv_usec)) +
764 " usec")
765 .c_str());
766 t_begin = t_end;
768 debug_print(("dtls_to_udp: already saw "s +
769 std::to_string(num_timeouts) + " timeouts")
770 .c_str());
771 if (num_timeouts > max_timeouts) {
772 debug_print(("No data received from dtls for too long: "s +
773 std::to_string(max_timeouts) +
774 " timeouts. Breaking dtls_to_udp loop.")
775 .c_str());
776 // SSL_shutdown(ssl);
777 break;
780 debug_print("-------------------------------------------------------");
781 ssize_t dtls_read_len =
782 SSL_read(ssl, dtls_to_udp_buffer, sizeof(dtls_to_udp_buffer));
784 switch (SSL_get_error(ssl, dtls_read_len)) {
785 case SSL_ERROR_NONE:
786 if (verbose) {
787 debug_print(
788 ("dtls_to_udp read " + std::to_string(dtls_read_len) + " bytes")
789 .c_str());
791 debug_print("Not printing received packet, not implemented.");
792 break;
793 case SSL_ERROR_WANT_READ:
794 // Stop reading on socket timeout, otherwise try again
795 debug_print("DTLS:SSL_ERROR_WANT_READ:on SSL_read().");
796 if (BIO_ctrl(SSL_get_rbio(ssl),
797 BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP,
799 NULL)) {
800 debug_print("Timeout! No packet received from dtls.\n");
801 num_timeouts++;
802 } else {
803 debug_print(
804 "SSL_ERROR_WANT_READ, but where does it come from? TODO");
806 // Just try again
807 continue;
809 case SSL_ERROR_ZERO_RETURN:
810 debug_print("dtls_to_udp:SSL_ERROR_ZERO_RETURN");
811 // Shall we break here? Wtf?
812 continue;
813 case SSL_ERROR_SYSCALL:
814 if (errno == EAGAIN) {
815 // Why does the socket timeout appear here, not in BIO_ctrl?
816 debug_print(
817 "dtls_to_udp:SSL_ERROR_SYSCALL:dtls read error:0: EAGAIN");
818 debug_print(
819 "Received nothing from the server for too long. (EAGAIN) "
820 "Breaking connection. This method is bad, because we "
821 "may be sending data, so the connection is still "
822 "valid, but so far let us make a temporary solution.");
823 num_timeouts++;
824 continue;
826 fprintf(stderr, "dtls_to_udp:SSL_ERROR_SYSCALL:not EAGAIN\n");
827 if (!handle_socket_error()) {
828 debug_print(
829 "dtls_to_udp:SSL_ERROR_SYSCALL:Unhandled syscall socket "
830 "error on reading.");
831 MY_EXIT_THREAD(1);
833 continue;
834 case SSL_ERROR_SSL:
835 debug_print(
836 "dtls_to_udp:SSL_ERROR_SSL:exiting because of SSL read error: ");
837 fprintf(stderr,
838 "%s (%d)\n",
839 ERR_error_string(ERR_get_error(), dtls_to_udp_buffer),
840 SSL_get_error(ssl, dtls_read_len));
841 MY_EXIT_THREAD(1);
842 default:
843 debug_print("dtls_to_udp:Unexpected error while reading!\n");
844 MY_EXIT_THREAD(1);
846 debug_print("Received a message over dtls");
847 // Processed all the reading crap, and ready to do something with the
848 // data in "server_dtls_receive_buffer", of length
849 // dtls_message_len
850 // and we send it to pinfo->server_last_received_udp_addr
851 // So, my datagram is in client_dtls_read_buffer, and the real
852 // length of it is ssl_read_len. So, I need something like:
853 // Sendto_flags(sockfd, dataBuffer, 0, pservaddr, servlen);
854 // This will send that datagram to the 2ping-server.
855 // This should be enough for simplicity.
856 // client_reverse_socket is already bound, so it should
857 // sendto_flagsORwrite(client_reverse_socket,client_dtls_read_buffer,ssl_read_len);
858 // write(client_reverse_socket, client_dtls_read_buffer,
859 // ssl_read_len);
860 //! Why exactly I chose "sendto", I am not very sure.
861 //! I did not want to use write(), because it is not
862 //! socket-specific. And sendmsg is a bit annoying with
863 //! its scatter/gather machinery.
865 if (pinfo->udp_ip_and_port.ss.ss_family == 0) {
866 debug_print(
867 "No return address received yet from client, or the address is "
868 "not given when starting. Dropping datagram.");
869 continue;
871 socklen_t sa_len = sizeof(struct sockaddr_storage);
872 ssize_t dtls_to_udp_write_len;
873 do {
874 dtls_to_udp_write_len = sendto(
875 udp_socket,
876 dtls_to_udp_buffer,
877 dtls_read_len,
879 reinterpret_cast<struct sockaddr *>(&(pinfo->udp_ip_and_port)),
880 sa_len);
881 } while (dtls_to_udp_write_len < 0 && errno == EAGAIN);
882 int my_errno = errno;
883 debug_print(
884 ("ssl_read_len="s + std::to_string(dtls_read_len)).c_str());
885 debug_print(
886 ("udp_write_len="s + std::to_string(dtls_to_udp_write_len)).c_str());
888 if (dtls_to_udp_write_len >= 0 &&
889 dtls_to_udp_write_len == dtls_read_len) {
890 debug_print("Written packet to client socket successfully");
893 if (dtls_to_udp_write_len >= 0 &&
894 dtls_to_udp_write_len != dtls_read_len) {
895 throw std::logic_error("written bytes do not match requested");
898 if (dtls_to_udp_write_len < 0) {
899 debug_print("Writing to client udp socket failed. Let's see why.");
901 if (my_errno == EAGAIN) {
902 debug_print("EAGAIN on writing to udp socket. Why? Dropping "
903 "packet. (this should not happen) TODO.");
904 throw std::logic_error("EAGAIN on writing to udp socket");
907 if (my_errno == ECONNREFUSED) {
908 debug_print("Udp socket has no service running, perhaps, "
909 "crashed, or whatever. Dropping packet.");
910 continue;
913 if (dtls_read_len > SSIZE_MAX) {
914 debug_print("dtls_to_udp:dtls_read_len > SSIZE_MAX. Logic error. "
915 "Terminating.");
916 throw std::logic_error("dtls_read_len > SSIZE_MAX");
919 if (my_errno == EINVAL) {
920 debug_print("UDP: EINVAL. Some argument to sendto is wrong");
921 throw std::logic_error(
922 "UDP: EINVAL. Some argument to sendto is wrong");
924 auto a =
925 "unexpected error when writing to udp socket on client, errno="s +
926 std::to_string(my_errno);
927 debug_print(a.c_str());
928 my_explain_recvfrom_error(my_errno);
929 throw std::runtime_error(a);
932 // SSL_shutdown(ssl);
933 MY_EXIT_THREAD(0);
936 #ifdef WIN32
937 DWORD WINAPI thread_server_handle_dtls_connection(LPVOID * info)
938 #else
939 void * thread_server_handle_dtls_connection(void * info)
940 #endif
942 // Start making a new socket for this particular tls connection.
943 auto myInfoGuard = std::unique_ptr<pass_info_t, void (*)(void *)>(
944 reinterpret_cast<pass_info_t *>(info), free);
945 pass_info_t * pinfo = reinterpret_cast<pass_info_t *>(info);
946 SSL * ssl = pinfo->ssl;
947 auto mySSLGuard = std::unique_ptr<SSL, void (*)(SSL *)>(ssl, SSL_free);
949 int server_dtls_connection_socket;
950 auto mySocketGuard = std::unique_ptr<int, void (*)(int *)>(
951 &server_dtls_connection_socket, closer);
952 if (sizeof(void *) != sizeof(int *))
953 throw std::logic_error("Size of void* too small");
955 // SSL_free(ssl);
956 ssize_t dtls_message_len;
957 char buf[BUFFER_SIZE];
958 char addrbuf[INET6_ADDRSTRLEN];
960 int reading = 0;
961 int ret;
962 const int on = 1, off = 0;
963 struct timeval timeout;
964 int num_timeouts = 0;
965 int const max_timeouts = pinfo->ntimeouts;
966 void * pthread_join_retval = nullptr;
968 #ifndef WIN32
969 pthread_detach(pthread_self());
970 #endif
972 OPENSSL_assert(pinfo->client_addr.ss.ss_family ==
973 pinfo->server_addr.ss.ss_family);
974 debug_print(("pinfo->client_addr.ss.ss_family="s +
975 std::to_string(pinfo->client_addr.ss.ss_family))
976 .c_str());
977 debug_print(("pinfo->server_addr.ss.ss_family="s +
978 std::to_string(pinfo->server_addr.ss.ss_family))
979 .c_str());
980 server_dtls_connection_socket =
981 socket(pinfo->client_addr.ss.ss_family, SOCK_DGRAM, 0);
982 if (server_dtls_connection_socket < 0) {
983 perror("socket");
984 // goto cleanup;
985 MY_EXIT_THREAD(4);
988 #ifdef WIN32
989 setsockopt(server_dtls_connection_socket,
990 SOL_SOCKET,
991 SO_REUSEADDR,
992 (const char *)&on,
993 (socklen_t)sizeof(on));
994 #else
995 setsockopt(server_dtls_connection_socket,
996 SOL_SOCKET,
997 SO_REUSEADDR,
998 (const void *)&on,
999 (socklen_t)sizeof(on));
1000 #if defined(SO_REUSEPORT) && !defined(__linux__)
1001 setsockopt(server_dtls_connection_socket,
1002 SOL_SOCKET,
1003 SO_REUSEPORT,
1004 (const void *)&on,
1005 (socklen_t)sizeof(on));
1006 #endif
1007 #endif
1008 switch (pinfo->client_addr.ss.ss_family) {
1009 case AF_INET:
1010 debug_print("client_addr.ss.ss_family=AF_INET");
1011 break;
1012 case AF_INET6:
1013 debug_print("client_addr.ss.ss_family=AF_INET6");
1014 break;
1015 default:
1016 debug_print("wrong family");
1017 OPENSSL_assert(0);
1019 break;
1021 try {
1022 my_ip46_bind(server_dtls_connection_socket, pinfo->server_addr);
1023 debug_print("Bind worked!");
1024 my_ip46_connect(server_dtls_connection_socket, pinfo->client_addr);
1025 debug_print("Connect worked!");
1026 } catch (std::runtime_error ex) {
1027 debug_print(("Exception!:"s + ex.what()).c_str());
1028 MY_EXIT_THREAD(4);
1029 } catch (...) {
1030 debug_print(("Big exception!"));
1031 exit(1);
1034 /* Set new fd and set BIO to connected */
1035 BIO_set_fd(
1036 SSL_get_rbio(ssl), server_dtls_connection_socket, BIO_NOCLOSE);
1037 BIO_ctrl(SSL_get_rbio(ssl),
1038 BIO_CTRL_DGRAM_SET_CONNECTED,
1040 &pinfo->client_addr.ss);
1042 /* Finish handshake */
1043 do {
1044 ret = SSL_accept(ssl);
1045 } while (ret == 0);
1046 if (ret < 0) {
1047 perror("SSL_accept");
1048 fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), buf));
1049 // goto cleanup;
1050 MY_EXIT_THREAD(2);
1053 /* Set and activate timeouts */
1055 timeout.tv_sec = pinfo->timeout_sec;
1056 timeout.tv_usec = 0;
1057 BIO_ctrl(
1058 SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
1060 #if defined(__OpenBSD__)
1061 BIO_set_buffer_size(SSL_get_rbio(ssl), 2000000);
1062 BIO_set_read_buffer_size(SSL_get_rbio(ssl), 2000000);
1063 #else
1064 BIO_set_buffer_size(SSL_get_rbio(ssl), 20000000);
1065 BIO_set_read_buffer_size(SSL_get_rbio(ssl), 20000000);
1066 #endif
1067 if (verbose) {
1068 if (pinfo->client_addr.ss.ss_family == AF_INET) {
1069 fprintf(stderr,
1070 "\nThread %lx: accepted connection from %s:%d\n",
1071 id_thread(),
1072 inet_ntop(AF_INET,
1073 &pinfo->client_addr.s4.sin_addr,
1074 addrbuf,
1075 INET6_ADDRSTRLEN),
1076 ntohs(pinfo->client_addr.s4.sin_port));
1077 } else {
1078 fprintf(stderr,
1079 "\nThread %lx: accepted connection from %s:%d\n",
1080 id_thread(),
1081 inet_ntop(AF_INET6,
1082 &pinfo->client_addr.s6.sin6_addr,
1083 addrbuf,
1084 INET6_ADDRSTRLEN),
1085 ntohs(pinfo->client_addr.s6.sin6_port));
1089 if (veryverbose && SSL_get_peer_certificate(ssl)) {
1090 fprintf(
1091 stderr,
1092 "------------------------------------------------------------\n");
1093 fflush(stderr);
1094 X509_NAME_print_ex_fp(
1095 stderr,
1096 X509_get_subject_name(SSL_get_peer_certificate(ssl)),
1098 XN_FLAG_MULTILINE);
1099 fflush(stderr);
1100 fprintf(stderr,
1101 "\n\n Cipher: %s",
1102 SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
1103 fprintf(
1104 stderr,
1105 "\n------------------------------------------------------------"
1106 "\n\n");
1107 fflush(stderr);
1109 // my: so here we have established a connection, and are using something
1110 // (let me check what) for reading and writing.
1111 // (1) ssl is used in SSL_get_shutdown,
1112 // (2) buf although buffers are cheap in C++
1113 // This loop will exist in both threads.
1114 debug_print("before two threads");
1115 my_tid_t tid_thread_server_dtls_to_udp;
1116 my_tid_t tid_thread_server_udp_to_dtls;
1117 my_create_thread(
1118 thread_dtls_to_udp, info, &tid_thread_server_dtls_to_udp);
1119 debug_print("created thread for server_dtls_to_udp");
1120 my_create_thread(
1121 thread_udp_to_dtls, info, &tid_thread_server_udp_to_dtls);
1122 debug_print("created thread for server_udp_to_dtls");
1124 pthread_join(tid_thread_server_dtls_to_udp, &pthread_join_retval);
1125 debug_print("joined thread_server_dtls_to_udp");
1126 SSL_shutdown(ssl);
1127 // if (pthread_join_retval != 0) {
1128 // // pthread_cancel(tid_write_thread);
1129 // goto cleanup;
1130 // }
1131 pthread_join(tid_thread_server_udp_to_dtls, &pthread_join_retval);
1132 debug_print("joined thread_server_udp_to_dtls");
1134 // if (pthread_join_retval != 0)
1135 // goto cleanup;
1137 // Here I will have to wait for these threads to finish, or I will
1138 // never call this shutdown, so I cannot self-detach.
1139 // But what happens if this thread should die?
1140 // I guess, if my dispatcher thread receives a new incoming connection,
1141 // it should publish a tid in some std::set , and the two writing-reading
1142 // threads will have to check that std::set instance, and terminate
1143 SSL_shutdown(ssl);
1145 cleanup:
1146 if (verbose)
1147 fprintf(stderr, "Thread %lx: done, connection closed.\n", id_thread());
1148 return 0;
1151 std::pair<int, my_ip46_address>
1152 setup_udp_socket(std::string forward_address,
1153 short forward_port,
1154 std::string local_address,
1155 short local_port) {
1156 // const int on = 1, off = 0;
1157 struct timeval socket_timeout {
1158 5, 0
1160 my_ip46_address local_udp_addr;
1161 if (local_address == ""s) {
1162 local_udp_addr.s6.sin6_family = AF_INET6;
1163 #ifdef HAVE_SIN6_LEN
1164 local_udp_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
1165 #endif
1166 local_udp_addr.s6.sin6_addr = in6addr_any;
1167 local_udp_addr.s6.sin6_port = htons(local_port);
1168 } else {
1169 my_ip46_address_init(
1170 local_udp_addr, local_address.c_str(), local_port);
1172 my_ip46_address forward_addr{};
1173 if (!forward_address.empty()) {
1174 my_ip46_address_init(
1175 forward_addr, forward_address.c_str(), forward_port);
1176 debug_print(("making a socket for communicating with "s +
1177 forward_address + ":" + std::to_string(forward_port))
1178 .c_str());
1180 debug_print(("Making udp socket. udp-local-address="s +
1181 my_ip46_address_to_string(local_udp_addr) +
1182 " forward_addr=" + my_ip46_address_to_string(forward_addr))
1183 .c_str());
1184 int udp_socket = socket(local_udp_addr.ss.ss_family, SOCK_DGRAM, 0);
1185 if (udp_socket < 0) {
1186 perror("server_udp_socket:socket()_fail");
1187 exit(-1);
1189 int const off = 0, on = 1;
1190 #if !defined(__OpenBSD__)
1191 if (setsockopt(
1192 udp_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)) <
1194 throw std::logic_error(
1195 "setup_server_udp_socket failed:setsockopt IPV6_ONLY=off");
1196 #endif
1197 #if defined(__OpenBSD__)
1198 int size = 2000000;
1199 #else
1200 int size = 20000000;
1201 #endif
1202 if (-1 ==
1203 setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)))
1204 throw std::logic_error("cannot set UDP SO_SNDBUF");
1205 if (-1 ==
1206 setsockopt(udp_socket, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
1207 throw std::logic_error("cannot set UDP SO_RCVBUF");
1208 my_ip46_bind(udp_socket, local_udp_addr);
1209 if (setsockopt(udp_socket,
1210 SOL_SOCKET,
1211 SO_RCVTIMEO,
1212 &socket_timeout,
1213 sizeof(socket_timeout)) < 0) {
1214 debug_print("setup_server_udp_socket failed:setsockopt");
1215 throw std::logic_error("setup_server_udp_socket failed:setsockopt");
1217 debug_print("server udp socket succeeded");
1218 return std::make_pair(udp_socket, forward_addr);
1221 void start_server_dtls(int port,
1222 char const * dtls_local_address,
1223 int udp_socket,
1224 my_ip46_address forward_address,
1225 bool allow_update_forward_address,
1226 std::string cert_path,
1227 std::string key_path,
1228 std::string ca_path,
1229 unsigned int dtls_timeout,
1230 unsigned int dtls_ntimeouts) {
1231 int dtls_dispatcher_socket;
1232 my_ip46_address server_addr, client_addr;
1233 my_tid_t tid;
1234 SSL_CTX * ctx;
1235 SSL * ssl;
1236 BIO * bio;
1237 debug_print(("Starting dtls server on "s + dtls_local_address + ":" +
1238 std::to_string(port))
1239 .c_str());
1240 const int on = 1, off = 0;
1242 std::memset(&server_addr, 0, sizeof(struct sockaddr_storage));
1243 if (std::strlen(dtls_local_address) == 0) {
1244 server_addr.s6.sin6_family = AF_INET6;
1245 #ifdef HAVE_SIN6_LEN
1246 server_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
1247 #endif
1248 server_addr.s6.sin6_addr = in6addr_any;
1249 server_addr.s6.sin6_port = htons(port);
1250 } else {
1251 try {
1252 my_ip46_address_init(server_addr, dtls_local_address, port);
1253 } catch (...) {
1254 return;
1258 THREAD_setup();
1259 OpenSSL_add_ssl_algorithms();
1260 SSL_load_error_strings();
1261 ctx = SSL_CTX_new(DTLS_server_method());
1262 /* We accept all ciphers, including NULL.
1263 * Not recommended beyond testing and debugging
1265 SSL_CTX_set_security_level(ctx, 0);
1266 SSL_CTX_set_cipher_list(ctx, "CHACHA20");
1267 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
1269 if (SSL_CTX_load_verify_locations(ctx, ca_path.c_str(), "certs") == 0)
1270 throw std::logic_error("CA directory or file not found.");
1272 if (!SSL_CTX_use_certificate_file(
1273 ctx, cert_path.c_str(), SSL_FILETYPE_PEM))
1274 printf("\nERROR: no certificate found!");
1276 if (!SSL_CTX_use_PrivateKey_file(
1277 ctx, key_path.c_str(), SSL_FILETYPE_PEM))
1278 printf("\nERROR: no private key found!");
1280 if (!SSL_CTX_check_private_key(ctx))
1281 printf("\nERROR: invalid private key!");
1283 /* Client has to authenticate */
1284 SSL_CTX_set_verify(
1285 ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
1286 // dtls_verify_callback);
1288 SSL_CTX_set_read_ahead(ctx, 1);
1289 SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
1290 SSL_CTX_set_cookie_verify_cb(ctx, &verify_cookie);
1292 dtls_dispatcher_socket = socket(server_addr.ss.ss_family, SOCK_DGRAM, 0);
1293 if (dtls_dispatcher_socket < 0) {
1294 perror("dtls_dispatch_socket");
1295 exit(-1);
1297 #if defined(__OpenBSD__)
1298 int size = 2000000;
1299 #else
1300 int size = 20000000;
1301 #endif
1302 if (-1 ==
1303 setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)))
1304 throw std::logic_error("cannot set UDP SO_SNDBUF");
1305 if (-1 ==
1306 setsockopt(udp_socket, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
1307 throw std::logic_error("cannot set UDP SO_RCVBUF");
1309 #ifdef WIN32
1310 setsockopt(dtls_dispatcher_socket,
1311 SOL_SOCKET,
1312 SO_REUSEADDR,
1313 (const char *)&on,
1314 (socklen_t)sizeof(on));
1315 #else
1316 setsockopt(dtls_dispatcher_socket,
1317 SOL_SOCKET,
1318 SO_REUSEADDR,
1319 (const void *)&on,
1320 (socklen_t)sizeof(on));
1321 #if defined(SO_REUSEPORT) && !defined(__linux__)
1322 setsockopt(dtls_dispatcher_socket,
1323 SOL_SOCKET,
1324 SO_REUSEPORT,
1325 (const void *)&on,
1326 (socklen_t)sizeof(on));
1327 #endif
1328 #endif
1329 my_ip46_bind(dtls_dispatcher_socket, server_addr);
1331 while (1) {
1332 debug_print("=============================================");
1334 std::memset(&client_addr, 0, sizeof(struct sockaddr_storage));
1336 /* Create BIO */
1337 bio = BIO_new_dgram(dtls_dispatcher_socket, BIO_NOCLOSE);
1339 /* Set and activate timeouts */
1340 struct timeval timeout;
1341 timeout.tv_sec = dtls_timeout;
1342 timeout.tv_usec = 0;
1343 BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
1344 BIO_set_buffer_size(bio, 2000000);
1345 BIO_set_read_buffer_size(bio, 2000000);
1346 ssl = SSL_new(ctx);
1348 SSL_set_bio(ssl, bio, bio);
1349 SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
1351 while (DTLSv1_listen(ssl, (BIO_ADDR *)&client_addr) <= 0)
1353 pass_info_t * dtls_info;
1354 dtls_info =
1355 reinterpret_cast<pass_info_t *>(malloc(sizeof(pass_info_t)));
1356 std::memcpy(&dtls_info->server_addr,
1357 &server_addr,
1358 sizeof(struct sockaddr_storage));
1359 std::memcpy(&dtls_info->client_addr,
1360 &client_addr,
1361 sizeof(struct sockaddr_storage));
1362 dtls_info->ssl = ssl;
1363 dtls_info->socket_reverse_forward = udp_socket;
1364 dtls_info->udp_ip_and_port = forward_address;
1365 dtls_info->allow_udp_ip_port_from_inbound =
1366 allow_update_forward_address;
1367 dtls_info->timeout_sec = dtls_timeout;
1368 dtls_info->ntimeouts = dtls_ntimeouts;
1370 my_create_thread(
1371 thread_server_handle_dtls_connection, dtls_info, &tid);
1373 THREAD_cleanup();
1376 void start_client_dtls(char const * remote_address,
1377 char const * local_address,
1378 int port,
1379 int client_udp_socket,
1380 my_ip46_address forward_address,
1381 bool allow_update_forward_address,
1382 std::string cert_path,
1383 std::string key_path,
1384 std::string ca_path,
1385 unsigned int dtls_timeout,
1386 unsigned int dtls_ntimeouts) {
1387 int client_dtls_socket;
1388 int ssl_connect_retval;
1389 void * pthread_join_retval = nullptr;
1390 my_ip46_address remote_addr;
1391 my_ip46_address local_addr;
1392 // I will have to somehow prepare a this buffer for writing,
1393 // so that it contains a header with my protocol's metadata.
1394 // The metadata is probably simple:
1395 // {
1396 // bool my_message_or_not_mine;
1397 // float loss;
1398 // float keepalive timeout;
1399 // };
1400 // or something like that.
1401 // char message_buf[BUFFER_SIZE];
1402 // but at the moment I have no header, I just reconnect.
1403 char addrbuf[INET6_ADDRSTRLEN];
1404 socklen_t len;
1405 SSL_CTX * ctx;
1406 SSL * ssl;
1407 BIO * bio;
1408 int reading = 0;
1410 std::memset((void *)&remote_addr, 0, sizeof(struct sockaddr_storage));
1411 std::memset((void *)&local_addr, 0, sizeof(struct sockaddr_storage));
1413 try {
1414 my_ip46_address_init(remote_addr, remote_address, port);
1415 } catch (...) {
1416 return;
1419 client_dtls_socket = socket(remote_addr.ss.ss_family, SOCK_DGRAM, 0);
1420 if (client_dtls_socket < 0) {
1421 perror("client socket");
1422 exit(-1);
1424 auto mySocketGuard =
1425 std::unique_ptr<int, void (*)(int *)>(&client_dtls_socket, closer);
1427 if (strlen(local_address) > 0) {
1428 debug_print("DTLS:Before local bind. ");
1429 try {
1430 my_ip46_address_init(local_addr, local_address, port);
1431 } catch (...) {
1432 return;
1435 OPENSSL_assert(remote_addr.ss.ss_family == local_addr.ss.ss_family);
1436 my_ip46_bind(client_dtls_socket, local_addr); // throws
1437 debug_print("DTLS:Local bind succeeded.");
1440 OpenSSL_add_ssl_algorithms();
1441 SSL_load_error_strings();
1442 ctx = SSL_CTX_new(DTLS_client_method());
1443 // SSL_CTX_set_cipher_list(ctx, "eNULL:!MD5");
1444 SSL_CTX_set_security_level(ctx, 0);
1445 SSL_CTX_set_cipher_list(ctx, "CHACHA20");
1446 if (SSL_CTX_load_verify_locations(ctx, ca_path.c_str(), "certs") == 0)
1447 throw std::logic_error("CA directory not found.");
1449 if (!SSL_CTX_use_certificate_file(
1450 ctx, cert_path.c_str(), SSL_FILETYPE_PEM))
1451 printf("\nERROR: no certificate found!");
1453 if (!SSL_CTX_use_PrivateKey_file(
1454 ctx, key_path.c_str(), SSL_FILETYPE_PEM))
1455 printf("\nERROR: no private key found!");
1457 if (!SSL_CTX_check_private_key(ctx))
1458 printf("\nERROR: invalid private key!");
1460 // client also verifies server
1461 SSL_CTX_set_verify(
1462 ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
1464 SSL_CTX_set_verify_depth(ctx, 2);
1465 SSL_CTX_set_read_ahead(ctx, 1);
1467 ssl = SSL_new(ctx);
1468 std::unique_ptr<SSL, void (*)(SSL *)> ssl_guard(ssl, SSL_free);
1470 /* Create BIO, connect and set to already connected */
1471 bio = BIO_new_dgram(client_dtls_socket, BIO_CLOSE);
1472 debug_print("DTLS: before connect.");
1473 try {
1474 my_ip46_connect(client_dtls_socket, remote_addr);
1475 } catch (std::runtime_error & ex) {
1476 debug_print(("Exception:dtls connect failed: "s + ex.what() +
1477 "ending this attempt.")
1478 .c_str());
1479 return;
1480 } catch (...) {
1481 debug_print("Unknown exception. Dying.");
1483 debug_print("DTLS: connect succeeded.");
1485 BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &remote_addr.ss);
1487 SSL_set_bio(ssl, bio, bio);
1488 debug_print("DTLS: before SSL_connect.");
1489 // Set and activate timeouts
1490 // Maybe we need to
1492 struct timeval timeout;
1493 timeout.tv_sec = dtls_timeout;
1494 timeout.tv_usec = 0;
1495 BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
1496 BIO_set_buffer_size(bio, 2000000);
1497 BIO_set_read_buffer_size(bio, 2000000);
1499 ssl_connect_retval =
1500 SSL_connect(ssl); // TODO: for some reason this doesn't timeout when I
1501 // expect it to.
1502 debug_print("DTLS: after SSL_connect.");
1503 if (ssl_connect_retval <= 0) {
1504 switch (SSL_get_error(ssl, ssl_connect_retval)) {
1505 case SSL_ERROR_ZERO_RETURN:
1506 fprintf(stderr, "SSL_connect failed with SSL_ERROR_ZERO_RETURN\n");
1507 break;
1508 case SSL_ERROR_WANT_READ:
1509 fprintf(stderr, "SSL_connect failed with SSL_ERROR_WANT_READ\n");
1510 break;
1511 case SSL_ERROR_WANT_WRITE:
1512 fprintf(stderr, "SSL_connect failed with SSL_ERROR_WANT_WRITE\n");
1513 break;
1514 case SSL_ERROR_WANT_CONNECT:
1515 fprintf(stderr, "SSL_connect failed with SSL_ERROR_WANT_CONNECT\n");
1516 break;
1517 case SSL_ERROR_WANT_ACCEPT:
1518 fprintf(stderr, "SSL_connect failed with SSL_ERROR_WANT_ACCEPT\n");
1519 break;
1520 case SSL_ERROR_WANT_X509_LOOKUP:
1521 fprintf(stderr,
1522 "SSL_connect failed with SSL_ERROR_WANT_X509_LOOKUP\n");
1523 break;
1524 case SSL_ERROR_SYSCALL:
1525 debug_print("SSL_connect failed with SSL_ERROR_SYSCALL\n");
1526 debug_print("TODO: process this syscall error.");
1527 // sleep(1);
1528 break;
1529 case SSL_ERROR_SSL:
1530 fprintf(stderr, "SSL_connect failed with SSL_ERROR_SSL\n");
1531 break;
1532 default:
1533 fprintf(stderr, "SSL_connect failed with unknown error\n");
1534 break;
1536 // goto cleanup_client;
1537 // exit(EXIT_FAILURE);
1538 debug_print("sleeping 5 seconds");
1539 sleep(5);
1540 debug_print("SSL_connect failed, terminating attempt.");
1541 return;
1544 if (verbose) {
1545 if (remote_addr.ss.ss_family == AF_INET) {
1546 printf(
1547 "\nConnected to %s\n",
1548 inet_ntop(
1549 AF_INET, &remote_addr.s4.sin_addr, addrbuf, INET6_ADDRSTRLEN));
1550 } else {
1551 printf(
1552 "\nConnected to %s\n",
1553 inet_ntop(
1554 AF_INET6, &remote_addr.s6.sin6_addr, addrbuf, INET6_ADDRSTRLEN));
1558 if (veryverbose && SSL_get_peer_certificate(ssl)) {
1559 printf(
1560 "------------------------------------------------------------\n");
1561 X509_NAME_print_ex_fp(
1562 stdout,
1563 X509_get_subject_name(SSL_get_peer_certificate(ssl)),
1565 XN_FLAG_MULTILINE);
1566 printf("\n\n Cipher: %s",
1567 SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
1568 printf("\n------------------------------------------------------------"
1569 "\n\n");
1571 // Okay, here we seem to have obtained all the stuff for reading and
1572 // writing to/from the socket.
1573 // So this while loop should be going on in the two threads.
1575 pass_info_t dtls_info;
1576 std::memcpy(
1577 &dtls_info.server_addr, &remote_addr, sizeof(struct sockaddr_storage));
1578 std::memcpy(
1579 &dtls_info.client_addr, &local_addr, sizeof(struct sockaddr_storage));
1580 dtls_info.ssl = ssl;
1581 dtls_info.socket_reverse_forward = client_udp_socket;
1582 dtls_info.udp_ip_and_port = forward_address;
1583 dtls_info.allow_udp_ip_port_from_inbound = allow_update_forward_address;
1584 dtls_info.timeout_sec = dtls_timeout;
1585 dtls_info.ntimeouts = dtls_ntimeouts;
1587 debug_print("before two threads");
1588 my_tid_t tid_client_dtls_to_udp;
1589 my_tid_t tid_client_udp_to_dtls;
1590 my_create_thread(
1591 thread_dtls_to_udp, &dtls_info, &tid_client_dtls_to_udp);
1592 debug_print("created reading thread");
1593 my_create_thread(
1594 thread_udp_to_dtls, &dtls_info, &tid_client_udp_to_dtls);
1595 debug_print("created writing thread");
1596 pthread_join(tid_client_dtls_to_udp, &pthread_join_retval);
1597 debug_print("joined client_dtls_to_udp thread");
1598 SSL_shutdown(ssl);
1599 pthread_join(tid_client_udp_to_dtls, &pthread_join_retval);
1600 debug_print("joined client_udp_to_dtls thread");
1603 int main(int argc, char ** argv) {
1604 if (EAGAIN != EWOULDBLOCK)
1605 throw std::logic_error("EAGAIN != EWOULDBLOCK, which is an error.");
1606 bool arg_verbose;
1607 // char local_addr[INET6_ADDRSTRLEN+1];
1608 // std::memset(local_addr, 0, INET6_ADDRSTRLEN+1);
1610 popl::OptionParser op("Allowed options");
1611 auto help_option =
1612 op.add<popl::Switch>("h", "help", "produce help message");
1613 auto groff_option = op.add<popl::Switch>(
1614 "", "groff", "produce groff formatted help message");
1615 auto bash_option =
1616 op.add<popl::Switch>("", "bash", "produce bash completion script");
1617 auto verbose_option = op.add<popl::Switch, popl::Attribute::optional>(
1618 "v", "verbose", "be verbose", &arg_verbose);
1619 auto dtls_local_address_option = op.add<popl::Implicit<std::string>>(
1620 "L",
1621 "local-address",
1622 "local dtls address ",
1623 std::string('\0', INET6_ADDRSTRLEN + 1));
1625 auto remote_address_option = op.add<popl::Value<std::string>>(
1626 "R", "remote-address", "remote dtls address");
1627 auto dtls_port_option =
1628 op.add<popl::Implicit<int>>("p",
1629 "port",
1630 "port (default 23232) (TODO: remove or "
1631 "rename. only for compatibility)",
1632 23232);
1634 auto server_or_client_option =
1635 op.add<popl::Value<std::string>>("", "mode", "server or client");
1637 auto udp_forward_address_option = op.add<popl::Implicit<std::string>>(
1639 "forward-address",
1640 "forward address for udp socket. Default means that value will be "
1641 "taken from the last client.",
1642 ""s);
1644 auto udp_local_address_option = op.add<popl::Implicit<std::string>>(
1645 "", "udp-local-address", "local bind address for udp socket.", ""s);
1647 auto udp_forward_port_option = op.add<popl::Implicit<unsigned short>>(
1649 "forward-port",
1650 "UDP packets received over dtls will be forwarded to this address. "
1651 "Default is 0, which means 'get from the last client'",
1654 auto udp_local_port_option = op.add<popl::Implicit<unsigned short>>(
1656 "udp-local-port",
1657 "UDP packets sent to this port will be forwarded to the dtls",
1660 auto udp_get_addr_from_inbound_packets_option =
1661 op.add<popl::Implicit<bool>>(
1663 "udp-get-addr-from-inbound-packets",
1664 "UDP target address-port will be updated from incoming packets. "
1665 "Setting this option to false disables auto-update of address and "
1666 "port.",
1667 true);
1669 auto dtls_public_cert_path_option = op.add<popl::Value<std::string>>(
1670 "", "dtls-public-cert-path", "path to a public cert file");
1672 auto dtls_private_key_path_option = op.add<popl::Value<std::string>>(
1673 "", "dtls-private-key-path", "path to a private key file");
1675 auto dtls_ca_path_option = op.add<popl::Value<std::string>>(
1676 "", "dtls-ca-cert-path", "path to a CA file");
1678 auto dtls_timeout_option = op.add<popl::Implicit<unsigned int>>(
1680 "dtls-timeout",
1681 "How long to wait before timing out. Too short, and your tunnel will "
1682 "not connect on a lossy channel. Too long, and switching between IPs "
1683 "will be a pain. Recommended value 5-10, but you have to experiment.",
1684 30);
1686 auto dtls_ntimeouts_option = op.add<popl::Implicit<unsigned int>>(
1687 "", "dtls-ntimeouts", "break connection after this many timeouts", 3);
1689 try {
1690 op.parse(argc, argv);
1691 if (help_option->count() == 1) {
1692 std::cout << op << "\n";
1693 exit(EXIT_SUCCESS);
1696 if (groff_option->is_set()) {
1697 popl::GroffOptionPrinter option_printer(&op);
1698 std::cout << option_printer.print();
1699 exit(EXIT_SUCCESS);
1702 if (bash_option->is_set()) {
1703 popl::BashCompletionOptionPrinter option_printer(&op,
1704 "popl_example");
1705 std::cout << option_printer.print();
1706 exit(EXIT_SUCCESS);
1708 if (!(server_or_client_option->is_set())) {
1709 std::cerr << "--mode= option must be server or client" << std::endl;
1710 return 1;
1713 if (verbose_option->is_set()) {
1714 verbose = 1;
1715 veryverbose = 1;
1717 } catch (const popl::invalid_option & e) {
1718 std::cerr << "Invalid Option Exception: " << e.what() << "\n";
1719 std::cerr << "error: ";
1720 if (e.error() == popl::invalid_option::Error::missing_argument)
1721 std::cerr << "missing_argument\n";
1722 else if (e.error() == popl::invalid_option::Error::invalid_argument)
1723 std::cerr << "invalid_argument\n";
1724 else if (e.error() == popl::invalid_option::Error::too_many_arguments)
1725 std::cerr << "too_many_arguments\n";
1726 else if (e.error() == popl::invalid_option::Error::missing_option)
1727 std::cerr << "missing_option\n";
1729 if (e.error() == popl::invalid_option::Error::missing_option) {
1730 std::string option_name(
1731 e.option()->name(popl::OptionName::short_name, true));
1732 if (option_name.empty())
1733 option_name = e.option()->name(popl::OptionName::long_name, true);
1734 std::cerr << "option: " << option_name << "\n";
1735 } else {
1736 std::cerr << "option: " << e.option()->name(e.what_name()) << "\n";
1737 std::cerr << "value: " << e.value() << "\n";
1739 std::cout << op << "\n";
1740 return EXIT_FAILURE;
1741 } catch (const std::exception & e) {
1742 std::cerr << "Exception: " << e.what() << "\n";
1743 return EXIT_FAILURE;
1746 if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) {
1747 printf("Warning: OpenSSL version mismatch!\n");
1748 printf("Compiled against %s\n", OPENSSL_VERSION_TEXT);
1749 printf("Linked against %s\n", OpenSSL_version(OPENSSL_VERSION));
1751 if (OpenSSL_version_num() >> 20 != OPENSSL_VERSION_NUMBER >> 20) {
1752 printf(
1753 "Error: Major and minor version numbers must match, exiting.\n");
1754 exit(EXIT_FAILURE);
1756 } else if (verbose) {
1757 printf("Using %s\n", OpenSSL_version(OPENSSL_VERSION));
1760 if (OPENSSL_VERSION_NUMBER < 0x1010102fL) {
1761 printf(
1762 "Error: %s is unsupported, use OpenSSL Version 1.1.1a or higher\n",
1763 OpenSSL_version(OPENSSL_VERSION));
1764 exit(EXIT_FAILURE);
1766 #if WIN32
1767 WSADATA wsaData;
1768 #endif
1769 #ifdef WIN32
1770 WSAStartup(MAKEWORD(2, 2), &wsaData);
1771 #endif
1773 auto [udp_socket, forward_addr] = setup_udp_socket
1774 /**/ (udp_forward_address_option->value().c_str(),
1775 udp_forward_port_option->value(),
1776 udp_local_address_option->value(),
1777 udp_local_port_option->value());
1779 debug_print(("udp_socket="s + std::to_string(udp_socket)).c_str());
1781 if (server_or_client_option->value() == "client") {
1782 while (true) {
1783 debug_print(
1784 "=======================================================");
1785 start_client_dtls(remote_address_option->value().c_str(),
1786 dtls_local_address_option->value().c_str(),
1787 dtls_port_option->value(),
1788 udp_socket,
1789 forward_addr,
1790 udp_get_addr_from_inbound_packets_option->value(),
1791 dtls_public_cert_path_option->value(),
1792 dtls_private_key_path_option->value(),
1793 dtls_ca_path_option->value(),
1794 dtls_timeout_option->value(),
1795 dtls_ntimeouts_option->value());
1796 debug_print("Client dtls connection died. Sleeping and restarting.");
1797 fprintf(stderr, "\n\n");
1798 fflush(stderr);
1799 sleep(1);
1801 } else if (server_or_client_option->value() == "server") {
1802 start_server_dtls(dtls_port_option->value(),
1803 dtls_local_address_option->value().c_str(),
1804 udp_socket,
1805 forward_addr,
1806 udp_get_addr_from_inbound_packets_option->value(),
1807 dtls_public_cert_path_option->value(),
1808 dtls_private_key_path_option->value(),
1809 dtls_ca_path_option->value(),
1810 dtls_timeout_option->value(),
1811 dtls_ntimeouts_option->value());
1813 #ifdef WIN32
1814 WSACleanup();
1815 #endif
1816 return 0;