The work of the speaker-cleanup branch as one commit; the branch keeps the step-by-step history. Sessions - The state machine is a pure function from events to actions, driven by one task per connection. Idle, Connect and Active belong to a dialer that keeps configured peers up with backoff. - Capabilities are negotiated: address families, four-octet AS numbers with AS_TRANS and AS4_PATH, route refresh, ADD-PATH per family and direction. - Collision detection per RFC 4271 section 6.8, by address and identifier. - Connections are taken only from configured peers, a few per address. - A panic in a session is contained and answered with a Cease; a core task that stops shuts the server down with a Cease to every peer. - Writes that make no progress are given up (RFC 9687). Codec - Malformed UPDATEs are handled as RFC 7606 says: treat-as-withdraw, attribute discard, or session reset, with the NOTIFICATION to send. - Address families are open types; any can be named and ignored. - Prefixes are fixed-size values, normalised, with path identifiers. - Lengths are filled in after writing; one definition of each type code. - Property tests and fuzz targets for every decoder. Routing table - Adj-RIBs-In and Loc-RIB in one sharded table that sessions write to directly. Routes are sixteen bytes; attribute sets are interned in wire form. Best-path selection per RFC 4271 section 9.1.2.2 with deterministic MED. - A journal per shard lets followers read changes at their own pace; one that falls behind is resynchronised. - On a RIPE RIS dump of 148 peers and 39.3M routes: loaded in 2.0 s on 12 cores, about 52 bytes a route. Announcing - Originated routes come from the configuration. Each session has its own exporter with an Adj-RIB-Out, so a slow peer delays only itself. - Routes to a peer in our own AS have an empty path and a LOCAL_PREF. Operations - HTTP status page, JSON API, event stream and Prometheus metrics. - Benchmarks on synthetic and real tables. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1.8 KiB
Fuzz targets
Coverage-guided fuzzing of everything that reads input we do not control.
The property tests (cargo test, e.g. crates/packet/tests/properties.rs)
check the same things on generated input and run on every build; these
targets go further by letting libFuzzer follow code coverage for as long as
you leave them running.
| Target | Input |
|---|---|
message |
Raw bytes as they come off a TCP connection |
message_body |
A message body behind a correct header (reaches the body parsers) |
prefix_text |
A prefix as text |
config |
The configuration file |
For the two message targets a finding is either a panic, or a message the decoder accepted that cannot be written and read back as itself.
Running
libFuzzer needs a nightly toolchain and cargo-fuzz:
rustup toolchain install nightly
cargo install cargo-fuzz
Then, from this directory:
cargo +nightly fuzz run message_body corpus/message_body seeds/message_body -- -max_total_time=300
The first directory is the working corpus, which the fuzzer adds to and
which is not checked in. seeds/ holds a few valid inputs to start from.
Leave out -max_total_time to run until interrupted.
When it finds something
The input is saved under artifacts/<target>/. Reproduce it with
cargo +nightly fuzz run message_body artifacts/message_body/crash-...
Fix the bug, and add a unit test with the input next to the code it broke,
so that cargo test keeps it fixed without anyone having to run the fuzzer.