This patch adds the function dtls1_listen(SSL *s, struct sockaddr  
*client), as well as the user accessible macro DTLSv1_listen(). It is  
intended to be called with an SSL object with a listening socket.  
Every ClientHello arriving will be answered with a HelloVerifyRequest  
without allocating any memory. When a ClientHello is repeated with a  
valid cookie attached, dtls1_listen() returns after entering the  
peer's address into the given sockaddr structure. The application can  
then create an UDP socket connected to that peer, assign it to the SSL  
object and continue the connection (with a SSL_accept() to complete  
the handshake, since the dtls1_listen returns before sending the  
ServerHello) in a new thread. Then a new SSL object has to be created  
and the listening socket has to be assigned to it, so that following  
connections can be handled.

Here's an example how the server can look like:

---------------------------------------------

/* Create listening socket */
fd = socket(AF_INET, SOCK_DGRAM, 0);

setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on,  
(socklen_t) sizeof(on));
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on,  
(socklen_t) sizeof(on));
bind(fd, (const struct sockaddr *) &server_addr, sizeof(server_addr));

while (1) {
        memset(&client_addr, 0, sizeof(struct sockaddr));

        /* Create new BIO with the listening socket and new SSL object */
        bio = BIO_new_dgram(fd, BIO_NOCLOSE);
        ssl = SSL_new(ctx);

        /* Assign BIO and activate cookie exchange */
        SSL_set_bio(ssl, bio, bio);
        SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
                
        /* Wait for ClientHello with valid cookie (blocking) */
        while (!DTLSv1_listen(ssl, &client_addr));

        /* Pass SSL object and peer info to a new thread */
        info = (struct pass_info*) malloc (sizeof(struct pass_info));
        memcpy(&info->server_addr, &server_addr, sizeof(struct sockaddr));
        memcpy(&info->client_addr, &client_addr, sizeof(struct sockaddr));
        info->ssl = ssl;

        pthread_create( &tid, NULL, connection_thread, info);
}

---------------------------------------------

The new thread can then create a connected socket with the passed  
information and assign the new socket to the existing SSL object to  
continue with a one-to-one connection.

---------------------------------------------

fd = socket(AF_INET, SOCK_DGRAM, 0);

setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on,  
(socklen_t) sizeof(on));
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on,  
(socklen_t) sizeof(on));
bind(fd, (const struct sockaddr *) server_addr, sizeof(struct  
sockaddr));
connect(fd, (struct sockaddr *) client_addr, sizeof(struct sockaddr));

/* Set new fd and set BIO to connected */
BIO_set_fd(SSL_get_rbio(ssl), fd, BIO_NOCLOSE);
BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_CONNECTED, 0,  
client_addr);

/* Finish handshake */
SSL_accept(ssl);

---------------------------------------------

This allows clean multi-threaded applications with UDP, since accept()  
can't be used and a continuous listening socket is necessary to avoid  
the loss of messages until a new listening socket has been created  
after connecting the previous one. It also allows to use the  
HelloVerifyRequest functionallity to avoid denial of service attacks,  
because otherwise resources (connected socket, thread) have to be  
allocated for every new connection to perform a handshake, maybe just  
to await the timeout because the peer doesn't answer.





--- ssl/d1_lib.c        12 Aug 2009 17:30:36 -0000      1.16
+++ ssl/d1_lib.c        3 Sep 2009 09:59:22 -0000
@@ -203,6 +203,9 @@
        case DTLS_CTRL_HANDLE_TIMEOUT:
                ret = dtls1_handle_timeout(s);
                break;
+       case DTLS_CTRL_LISTEN:
+               ret = dtls1_listen(s, parg);
+               break;

        default:
                ret = ssl3_ctrl(s, cmd, larg, parg);
@@ -364,3 +367,17 @@
        gettimeofday(t, NULL);
  #endif
  }
+
+int dtls1_listen(SSL *s, struct sockaddr *client)
+       {
+       int ret;
+
+       SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
+       s->d1->listen = 1;
+
+       ret = SSL_accept(s);
+       if (ret <= 0) return 0;
+       
+       BIO_dgram_get_peer(SSL_get_rbio(s), client);
+       return 1;
+       }

--- ssl/d1_srvr.c       5 Jun 2009 14:59:26 -0000       1.25
+++ ssl/d1_srvr.c       3 Sep 2009 09:59:22 -0000
@@ -279,6 +279,15 @@
                                s->state = SSL3_ST_SW_SRVR_HELLO_A;

                        s->init_num=0;
+
+                       /* If we're just listening, stop here */
+                       if (s->d1->listen && s->state == 
SSL3_ST_SW_SRVR_HELLO_A)
+                               {
+                               ret = 2;
+                               s->d1->listen = 0;
+                               goto end;
+                               }
+                       
                        break;
                        
                case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:

--- ssl/dtls1.h 17 Jun 2009 11:37:44 -0000      1.21
+++ ssl/dtls1.h 3 Sep 2009 09:59:22 -0000
@@ -212,6 +212,9 @@
         */
        record_pqueue buffered_app_data;

+       /* Is set when listening for new connections with dtls1_listen() */
+       unsigned int listen;
+
        unsigned int mtu; /* max DTLS packet size */

        struct hm_header_st w_msg_hdr;

--- ssl/ssl.h   26 Aug 2009 11:51:57 -0000      1.231
+++ ssl/ssl.h   3 Sep 2009 09:59:22 -0000
@@ -1398,11 +1398,14 @@

  #define DTLS_CTRL_GET_TIMEOUT         73
  #define DTLS_CTRL_HANDLE_TIMEOUT      74
+#define DTLS_CTRL_LISTEN                       75

  #define DTLSv1_get_timeout(ssl, arg) \
        SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
  #define DTLSv1_handle_timeout(ssl) \
        SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
+#define DTLSv1_listen(ssl, peer) \
+       SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)

  #define SSL_session_reused(ssl) \
        SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)



Attachment: dtls-listen.patch
Description: Binary data



Reply via email to