Add UDP/datagram transport: wire codec, replay window, reassembler, endpoint routing#38
Merged
Merged
Conversation
dc11326 to
e25d9c3
Compare
A separate connectionless datagram transport from the TCP/stream Transport, with its own self-contained wire format: no cross-datagram length prefix and no transmitted nonce (the nonce derives from a per-session prefix and the sequence number), and the full frame header is the AEAD AAD so the AEAD authenticates the epoch and connection index. Adds the per-datagram codec and handshake fragment format (pkg/protocol/datagram_codec.go), a multi-word sliding-bitmap anti-replay window that survives rekeys without reset (pkg/tunnel/replay.go), a bounded handshake-only reassembler with per-source, size, timeout, and global source caps (pkg/tunnel/reassembly.go), and the endpoint with a CSPRNG connection-index registry that demuxes by index rather than source address plus per-source half-open accounting (pkg/tunnel/datagram.go). Datagram parameters live in internal/constants and design notes in docs. Reuses the crypto core (chkem, crypto, and Session secret derivation) unchanged. The reliable handshake, the encrypted data path, the performance pass, and the anti-DoS hardening follow in separate changes. Build, vet, gofmt, and golangci-lint are clean; the module is green under -race; unit tests cover the codec, replay window, reassembler, connection-index registry, and frame routing.
e25d9c3 to
b5c34e8
Compare
The older pinned Codacy CLI crashed internally during SARIF generation (a Scala exception, exit 1), failing the Codacy job on every run even though the workflow sets max-allowed-issues to its maximum to keep findings non-blocking. v4.4.7 is the current release; this re-pins to its commit SHA. No change to our code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft. First slice of the UDP/datagram transport. This PR lands the wire format, the anti-replay window, the handshake reassembler, and the connectionless endpoint with its connection-index routing. The reliable handshake, the encrypted data path, the performance pass, and the DoS/amplification hardening land in follow-up PRs; seams and TODOs in the code mark where they plug in.
The datagram transport is a separate, connectionless transport from the TCP/stream
Transport. It does not reuse the stream framing: length-prefixedio.ReadFulldoes not survive datagram loss/reorder, and the ~1.6 KB post-quantum Hellos exceed a 1500 B MTU. The crypto core (chkem,crypto, andSessionsecret derivation) is reused unchanged. There is no TCP/UDP interop, by design.What this PR contains:
pkg/protocol/datagram_codec.go: self-contained per-datagram wire format. A 14 B common header[type|epoch|recvIndex|seq]plus a handshake fragment extension. No cross-datagram length prefix and no transmitted nonce (the nonce is derived assessionPrefix || seq); the full header is the AEAD AAD, so the epoch and connection index are authenticated. A cookie/retry field is reserved so the later anti-DoS work needs no wire change.pkg/tunnel/replay.go: a multi-word sliding-bitmap anti-replay window (1024 bits) over the monotonic sequence, never reset across rekey.pkg/tunnel/reassembly.go: a bounded, handshake-only fragment reassembler (per-source cap, per-message size cap, timeout, and a global source cap).pkg/tunnel/datagram.go: the endpoint shell and a connection-index registry. CSPRNG-random indices demuxed by index rather than source address, so a session survives NAT rebind/roaming, one address can host many sessions, and the index space resists off-path guessing (regenerated on collision). Plus per-source half-open accounting and the frame-routing seam.internal/constants/constants.go: datagram parameters (1200 B MTU, payload cap, nonce prefix, reassembly/handshake/idle/half-open bounds).docs/: design notes.Security review (pre-merge): parsing, the replay window, the connection-index registry, and the nonce/AAD design were reviewed in depth and are clean (bounds-checked parsing, a correct sliding bitmap, CSPRNG indices allocated under a lock). One finding is fixed here: the reassembler now has a global cap across all sources, because UDP source addresses are spoofable and a per-source cap alone did not bound total memory. Two enforcement items are recorded as TODOs at their seams for the handshake work: gating new half-open sessions through the per-source admission check, and authenticating a CLOSE frame before teardown. Neither is reachable yet (there is no live receive loop).
Planned follow-ups (separate PRs):
Sessionand the encrypted data send/receive path.Verification:
go build ./...,go vet, and gofmt are clean; the full module is green under-race; the codec, replay window, reassembler (including the global cap), and connection-index registry are covered by unit tests.