Resetting DTLS server

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Resetting DTLS server

Patrick Herbst
If i setup a DTLS server, the client can connect once and send
messages find.  but if the client restarts and tries to send data, the
server hangs on SSL_read.

I'm assuming the server does not like a clienthello message when it is
expecting application data.

How can the server be made to recover and re-handshake with the
restarted client?
Reply | Threaded
Open this post in threaded view
|

Re: Resetting DTLS server

Michael Richardson


On 2019-11-12 7:38 a.m., Patrick Herbst wrote:
> If i setup a DTLS server, the client can connect once and send
> messages find.  but if the client restarts and tries to send data, the
> server hangs on SSL_read.

How are you handling the sockets on the server?
If you are creating a new 5-tuple [bind/connect] socket on the server
for each client, and the client then reuses it's socket, then it's
trying to speak the old instance on the server. 
> I'm assuming the server does not like a clienthello message when it is
> expecting application data.
>
> How can the server be made to recover and re-handshake with the
> restarted client?

Close the UDP socket on the client and open a new one to get a new
source port.
Does that work?  I'm not terribly happy with this solution, but it does
match what TCP would do.



signature.asc (673 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Resetting DTLS server

Patrick Herbst
On Tue, Nov 12, 2019 at 3:00 AM Michael Richardson <[hidden email]> wrote:

> On 2019-11-12 7:38 a.m., Patrick Herbst wrote:
> > If i setup a DTLS server, the client can connect once and send
> > messages find.  but if the client restarts and tries to send data, the
> > server hangs on SSL_read.
>
> How are you handling the sockets on the server?
> If you are creating a new 5-tuple [bind/connect] socket on the server
> for each client, and the client then reuses it's socket, then it's
> trying to speak the old instance on the server.
> > I'm assuming the server does not like a clienthello message when it is
> > expecting application data.
> >
> > How can the server be made to recover and re-handshake with the
> > restarted client?
>
> Close the UDP socket on the client and open a new one to get a new
> source port.
> Does that work?  I'm not terribly happy with this solution, but it does
> match what TCP would do.
>

In general, here is what i do (assuming only 1 client for proof of
concept, and skipping some mundane steps)
also assuming the client is using the same addr/port, so "connect"
would not make a difference.

s=socket(AF_INET, SOCK_DGRAM, 0);
bind(s, &serverAddr, sizeof(serverAddr));
ssl=SSL_new(ctx);
bio=BIO_new_dgram(s, BIO_NOCLOSE);
SSL_accept(ssl);

while (1) {
  select(FD_SETSIZE, fds, NULL, NULL, NULL);
  if (FD_ISSET(s)) {
    n=SSL_read(ssl, buffer, sizeof(buffer));
    if (n>0) {
      printf("rx: %s\n", buffer);
    } else {
      printf("bad things\n");
    }
  }
}

What happens is form the Server standpoint, it doesn't know when a
client restarts.  When the client does restart, the server blocks on
SSL_read while the internals of the library keep reading packets until
it gets app data... so it ignores another clienthello, but doesn't
notify the server of that condition.

am i missing something? is this worth fixing in the library?  is this
intended behavior?
Reply | Threaded
Open this post in threaded view
|

Re: Resetting DTLS server

Michael Richardson


On 2019-11-12 9:30 p.m., Patrick Herbst wrote:

> On Tue, Nov 12, 2019 at 3:00 AM Michael Richardson <[hidden email]> wrote:
>> Close the UDP socket on the client and open a new one to get a new
>> source port.
>> Does that work?  I'm not terribly happy with this solution, but it does
>> match what TCP would do.
>>
> In general, here is what i do (assuming only 1 client for proof of
> concept, and skipping some mundane steps)
> also assuming the client is using the same addr/port, so "connect"
> would not make a difference.
so you are showing me your server code, correct, and this is for DTLS,
right?
Do you call DTLSv1_accept()?

You don't seem to be creating a new socket anywhere, or calling
connect() on this socket.
I'm not sure I understand your comment above about connect would not be
a difference.
If your DGRAM socket is not connected, how can you send packets back? 
It would be nice
if DTLS code would store the origin of every packet and demux it into
multiple SSL*, but it doesn't work that way.


>
> s=socket(AF_INET, SOCK_DGRAM, 0);
> bind(s, &serverAddr, sizeof(serverAddr));
> ssl=SSL_new(ctx);
> bio=BIO_new_dgram(s, BIO_NOCLOSE);
> SSL_accept(ssl);
>
> while (1) {
>   select(FD_SETSIZE, fds, NULL, NULL, NULL);
>   if (FD_ISSET(s)) {
>     n=SSL_read(ssl, buffer, sizeof(buffer));
>     if (n>0) {
>       printf("rx: %s\n", buffer);
>     } else {
>       printf("bad things\n");
>     }
>   }
> }
>
> What happens is form the Server standpoint, it doesn't know when a
> client restarts.  When the client does restart, the server blocks on
> SSL_read while the internals of the library keep reading packets until
> it gets app data... so it ignores another clienthello, but doesn't
> notify the server of that condition.
>
> am i missing something? is this worth fixing in the library?  is this
> intended behavior?


signature.asc (673 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Resetting DTLS server

Patrick Herbst
On Tue, Nov 12, 2019 at 9:07 AM Michael Richardson <[hidden email]> wrote:
>
> so you are showing me your server code, correct, and this is for DTLS,
> right?
> Do you call DTLSv1_accept()?

Yes, DTLS.  There is no DTLSv1_accept.  SSL_accept should work because
it is based on 'method' and underlying BIO.  I left some steps out of
my example code (i was just hand typing it one the fly, not
copy/paste).

>
> You don't seem to be creating a new socket anywhere, or calling
> connect() on this socket.
> I'm not sure I understand your comment above about connect would not be
> a difference.
> If your DGRAM socket is not connected, how can you send packets back?
> It would be nice
> if DTLS code would store the origin of every packet and demux it into
> multiple SSL*, but it doesn't work that way.

I'm not creating a new socket because it is UDP, and i'm assuming only
one client.  If you use a BIO_new_dgram, then you dont need to
"connect" the UDP socket, the dgram BIO will keep track of the
client's addr.  So because of this behavior, "connect" doesn't change
anything.  I have called "connect" on the sockets in other tests, but
it gives the exact same result.

SSL_accept waits for a 'clienthello', which the underlying dgram BIO
will store the client's addr, so that when SSL_accept writes the
response via the BIO, it'll get sent to the proper address.  My tests
show this working just fine the first time the client connects; the
server handshakes and can read messages.

Even if i were the "connect" the socket to the clients addr, the
client comes up with the same addr/port combination, so the server's
"connected" UDP socket will continue reading mesgs from the client.
BUT it'll get stuck in SSL_read when the client restarts because
SSL_read is not expecting a "clienthello", and the library continues
to try to read more packets.


Here is a more correct version of the code

s=socket(AF_INET, SOCK_DGRAM, 0);
bind(s, &serverAddr, sizeof(serverAddr));
ssl=SSL_new(ctx);
bio=BIO_new_dgram(s, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
SSL_accept(ssl);
// at this point the client is authenticated and handshake is
complete.  ssl's underlying BIO has the clients addr.
while (1) {
  FD_ZERO(&fds);
  FD_SET(s, &fds);
  select(FD_SETSIZE, fds, NULL, NULL, NULL);
  if (FD_ISSET(s)) {
    n=SSL_read(ssl, buffer, sizeof(buffer));
    if (n>0) {
      printf("rx: %s\n", buffer);
    } else {
      printf("bad things\n");
    }
  }
}

> > am i missing something? is this worth fixing in the library?  is this
> > intended behavior?
Reply | Threaded
Open this post in threaded view
|

Re: Resetting DTLS server

Michael Richardson


On 2019-11-12 10:30 p.m., Patrick Herbst wrote:
>
> I'm not creating a new socket because it is UDP, and i'm assuming only
> one client.  If you use a BIO_new_dgram, then you dont need to

You assumed one client, and you got one client.  What's the problem :-)

> Even if i were the "connect" the socket to the clients addr, the
> client comes up with the same addr/port combination, so the server's
> "connected" UDP socket will continue reading mesgs from the client.

I think that it won't work with OpenSSL for more than one DTLS session
to occur on the same 5-tuple pair.
Whether or not that is correct behaviour according to a specification, I
suspect is open to debate.




signature.asc (673 bytes) Download Attachment