The first part of RPKI origin validation (RFC 6811): the data and how it gets here. Nothing uses it yet. VrpTable holds the validated ROA payloads and says whether a route is valid, invalid or not found. It is a binary trie in one allocation with a short cut past the first sixteen levels; a lookup against 600,000 entries takes about 40 ns for random addresses. A table is built once and not changed: when the data changes another takes its place. rtr is the RPKI-to-Router protocol's PDUs (RFC 8210, and version 0 of RFC 6810), as bytes and back, without I/O. Lengths are checked from the header, before the rest of a PDU is waited for. The client keeps the table in step with a validator's cache. It asks for everything once and then for changes, when the cache notifies and at the refresh interval. An answer takes effect only when it is complete and consistent. Each update says which VRPs came or went, so that only the routes they cover need looking at again. A cache that fails is retried and the next one tried; the data is used meanwhile, and dropped if no cache confirms it within the expire interval. A cache that speaks only version 0 is spoken to in version 0. Tests: the cases of RFC 6811, a property test of the trie against the plain definition, round-trip and hostile-input properties for the codec, a fuzz target, and the client against a scripted cache. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
28 lines
1.0 KiB
Rust
28 lines
1.0 KiB
Rust
//! Bytes from an RPKI cache: a stream of RTR PDUs. A cache is trusted for
|
|
//! its data, not to be free of bugs or to be the cache we meant to reach.
|
|
#![no_main]
|
|
|
|
use bgp_rpki::rtr::Pdu;
|
|
use bytes::BytesMut;
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
let mut rest = data;
|
|
// As the client reads: one PDU after another until one is incomplete
|
|
// or wrong.
|
|
while let Ok(Some((version, pdu, used))) = Pdu::decode(rest) {
|
|
assert!(used >= 8 && used <= rest.len());
|
|
// What was read can be shown and written.
|
|
let _ = format!("{pdu:?}");
|
|
let mut out = BytesMut::new();
|
|
pdu.encode(version, &mut out);
|
|
// And what is written reads back as itself. A router key is read
|
|
// only to be skipped, and an error report is written without the
|
|
// PDU it complains about.
|
|
if !matches!(pdu, Pdu::RouterKey | Pdu::ErrorReport { .. }) {
|
|
assert_eq!(Pdu::decode(&out), Ok(Some((version, pdu, out.len()))));
|
|
}
|
|
rest = &rest[used..];
|
|
}
|
|
});
|