Hello Godotters, as part of my August work (sponsored, as always, by Mozilla) I’ve been working on integrating DTLS in Godot.
Sadly, the work is not yet finished (although usable), and since it requires some API changes in
PacketPeerUDP to make it performs well (avoiding extra buffering) it will be pushed to the
But what is DTLS? Why is it important to have? And how will users benefit from it?
DTLS stands for Datagram Transport Layer Security, you can think of it as TLS/SSL but for UDP packets. This is very important, because it allows you to use transparent encryption in real-time applications (like fast-paced multiplayer games).
It prevents abusers from being able to disrupt your match by claiming to be some other players (which is not easy to do, and not always possible, but is something that needs to be considered when using UDP, and thus the
It also allows you to validate that the user connects to the right server when you use a client/server architecture and thus prevent man-in-the-middle attacks (someone faking to be the server, that replay all the data to the real server, but can read/change everything you send).
DTLS in Godot
This first part of the work adds three new classes:
UDPServer: Yep, you got it right, a “server” for UDP. It’s quite different from a
TCPServer, keep reading for more.
DTLSServer: This is a class used to keep the state for DTLS, specifically its cookies (again, keep reading for more).
PacketPeerDTLS: The actual DTLS connection peer, that can be used as a regular packet peer (and will in the future be used by
NetworkedMultiplayerENetto provide transparent encryption for the high level multiplayer).
UDPServer can listen to a specific port/address and accept “connections” as soon as they arrive.
This can be achieved thanks to the fact that UDP can be, in a way, “connected” to a specific address.
It’s not a connection like a TCP one (where you can potentially know if the other peer exists), this is more like a filter, that tells the operating system to ignore all the packets that do not come from a specific address. Each packet received from a new peer will result in a new connection, from that moment on, all the packets coming from the same source will be received by the “connected” peer and not the server.
is_connection_available() is true to get the connected
As mentioned, the
DTLSServer class is used to store the DTLS state. DTLS must use a thing called cookies, to avoid amplification attacks.
In simple terms, for the way UDP works, anyone can send you UDP packets (without the need for a connection), and since one can fake its source (by spoofing, i.e. altering the source filed in the IP protocol), one can force a server to send the reply of the received packet to a different address than the original sender. This is very bad when a protocol has the reply message which is much bigger than the original packet, as this will allow a simple client with low bandwidth to amplify their bandwidth capabilities by exploiting the server.
Ahas limited bandwidth of 1 Mb/s.
Asends a spoofed packet (masquerading as
B) to the server
Z(which has a bandwidth of 100Mb/s).
- The server
Zsends the reply to
B, but the reply is much bigger (e.g. 10 times bigger) than the data sent by
Acan, with its 1 Mb/s, force server
Bof packets with a 10 Mb/s bandwidth (1 Mb/s from
Atimes 10 for the reply size).
Only when the clients sends their requests with the received cookie, will the server start to send bigger packets.
This way, when
A sends the spoofed packet, it will not receive the cookie (which
B will receive instead) and will not be able to amplify its bandwidth exploiting
Z (since the cookie packet is smaller than the packet sent by
If this seems a bit confusing, it’s because it’s actually a pretty twisted kind of attack. But you don’t have to worry about it, because the
DTLSServer class does the job for you :)
This class has 2 interesting methods:
setup, to generate the state (and where you set the RSA key and certificate), and
take_connection that accepts a connected PacketPeerUDP (from
UDPServer) and will return a
PacketPeerDTLS in the “connecting” state when the cookie is correct, or in the “error” state when the cookie is missing or not known.
PacketPeerDTLS is the core class of the whole DTLS implementation in Godot, the one that provides access to the actual data transfer functionalities.
There are two ways of getting a working
DTLSServeras explained above.
PacketPeerUDPand then pass it to the
Remember to call
PacketPeerDTLS.poll frequently, and at some point it will reach the “connected” state. At that point, you can start transfer data and it will be automatically encrypted.
Consideration, further work
First of all, I’m sorry it took me so long to publish this report. It has been a crazy few months between the upcoming
3.2 release, the Godot Sprint, GodotCon, and the nerd flu that got us there.
I had stopped working on this feature to focus on improvements and fixes for
3.2 but I will get on it again in the coming month (November) working on the integration with
NetworkedMultiplayerENet so that the high level multiplayer can benefit from this technology.
Stay tuned for more on DTLS, and for the report on September/October work (some merged already, some still in the process of being merged).
I will try to speed up my reporting capabilities ;-)
Small project to demo/test the work done so far