netcode.rs
netcode is a secure client/server protocol for multiplayer games built on top of UDP.
This is a Rust implementation of the netcode 1.02 standard. It is a from-scratch port of the reference C implementation, written in idiomatic Rust, and interoperates on the wire with other conforming implementations.
Design
Real-time multiplayer games typically use UDP instead of TCP, because head of line blocking delays more recent packets while waiting for older dropped packets to be resent. The problem is that if you want to use UDP, it doesn't provide any concept of connection, so you have to build all this yourself, which is a lot of work!
netcode fixes this by providing a minimal and secure connection-oriented protocol on top of UDP, so you can quickly get to exchanging unreliable unordered packets and get busy building the rest of your game network protocol.
Features
- Secure client connection with connect tokens. Only clients you authorize can connect to your server. This is perfect for a game where you perform matchmaking in a web backend then send clients to connect to a server.
- Client slot system. Servers have n slots for clients. Clients are assigned to a slot when they connect to the server and are quickly denied connection if all slots are taken.
- Fast clean disconnect on client or server side of connection to quickly open up the slot for a new client, plus timeouts for hard disconnects.
- Encrypted and signed packets. Packets cannot be tampered with or read by parties not involved in the connection. Cryptography is performed by the pure Rust RustCrypto ChaCha20-Poly1305 implementation.
- Many security features including protection against maliciously crafted packets, packet replay attacks and packet amplification attacks.
- Support for both IPv4 and IPv6 connections.
- No unsafe code.
Wire compatibility
This implementation is binary compatible with the reference C implementation, and that compatibility is enforced mechanically on every change:
- Golden test vectors.
tests/vectors/holds every token and packet type as written by the reference C implementation from fixed inputs. The tests insrc/wire_compat.rsassert this implementation produces byte-identical output — including AEAD ciphertext and authentication tags — and reads the C bytes back to the same values. They run in everycargo test. - Live interoperability. CI builds the reference C implementation and runs
tests/c_interop.rs: a C server accepting a connection from this client, and this server accepting a connection from the C client, each exchanging encrypted payloads in both directions for longer than the connect token timeout.
If either layer fails, the change breaks interoperability with other netcode implementations and must not merge.
Usage
Add the crate to your project:
cargo add netcode-official
The package is published as netcode-official; the library target is named netcode, so code says use netcode::... and will not need to change if the package later moves to the netcode name on crates.io.
Start by generating a random 32 byte private key. Do not share your private key with anybody.
Especially, do not include your private key in your client executable!
let private_key = generate_key;
Create a server with the private key and the public address clients connect to:
let server_address = "127.0.0.1:40000".parse.unwrap;
let mut server = new
.expect;
Then start the server with the number of client slots you want:
server.start.expect;
To connect a client, your client should hit a REST API to your backend that returns a connect token. Generate one with the same private key the server holds:
let connect_token = generate_connect_token?;
Using a connect token secures your server so that only clients authorized with your backend can connect:
let mut client = new?;
client.connect?;
Drive the client and server from your game loop, passing in the current time in seconds:
client.update;
server.update;
Once the client connects it is assigned a client index and can exchange encrypted and signed packets with the server:
if client.state == Connected
while let Some = server.receive_packet
For more details please see examples/client.rs, examples/server.rs and examples/client_server.rs, which you can run with:
cargo run --example client_server
Source Code
This repository holds the implementation of netcode in Rust, ported from the reference C implementation.
Differences from the C implementation:
- Addresses are
std::net::SocketAddrand errors areResult, so the parse/error-code APIs have no equivalent. - Payloads are received as
Vec<u8>, so there is no free-packet API. - Server connect and disconnect callbacks are replaced by a polled event queue:
server.next_event(). - The network simulator, loopback clients, dual-stack servers and packet tagging are not (yet) ported.
If you'd like to create your own implementation of netcode, please read the netcode 1.02 standard, and see IMPLEMENTERS.md for findings other implementations should check themselves against. This implementation includes those fixes: the replay protection already-received test is written in the overflow-free subtraction form, and there is a regression test locking down the nonce construction.
Development
cargo test # unit, wire-compatibility and integration tests
cargo fmt --check # formatting
cargo clippy --all-targets -- -D warnings # lints
cargo +nightly fuzz run fuzz_read_packet # coverage-guided fuzzing (cargo install cargo-fuzz)
CI runs the test suite on Linux, macOS and Windows (stable and beta Rust), checks formatting, clippy, rustdoc, the minimum supported Rust version (1.85), dependency licenses and security advisories with cargo-deny, live interoperability against the reference C implementation, and smoke-fuzzes the untrusted input surface with the harnesses in fuzz/.
To run the interoperability tests locally, build the reference C implementation and point the tests at its example binaries:
NETCODE_C_SERVER=path/to/netcode/build/bin/server \
NETCODE_C_CLIENT=path/to/netcode/build/bin/client \
cargo test --test c_interop -- --ignored --test-threads=1
Author
The author of this library is Glenn Fiedler.
Other open source libraries by the same author include: netcode (C reference implementation), reliable, serialize, and yojimbo.
If you find this software useful, please consider sponsoring it. Thanks!