What the code-health review found, and what a fuzz target written for it
found in its first seconds.
- A set of attributes with the same attribute twice is refused by the
routing table. Its readers (the selection key, the path, the next hop)
could each take a different one of the two. The decoder never lets one
through; the new fuzz target `attrs` found that the table would.
- bgp_peer_up{peer}, to alert on a peer going away, and bgp_build_info.
Every metric is there from the first scrape. Alerts for a peer down,
hijack attempts and kernel errors are in the README.
- `bgp --check config` validates a configuration without starting, and
`--version` says which build it is. CI runs the first on the example
configuration, which a test now also parses with its commented fields
put in; the example had to learn about the next hop check.
- Path attributes have a module of their own, packet::attributes,
re-exported from packet::message as before.
- policy::From, which shadowed the trait, is RouteSource. The server's
connection, dialer and fsm modules are private. Logging arguments live
in the binary; the server library no longer depends on clap.
- One is_unicast_link_local (the standard library's) instead of two of
our own; SelectionKey::origin(); one place where an Import is made.
- READMEs say what the daemon does today rather than what it did not do
a year ago. Documentation links are checked in CI. Unused dependencies
and bgp_web::serve are gone; the Docker build is --locked and does not
ship the fuzz corpus.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
32 lines
1.1 KiB
Rust
32 lines
1.1 KiB
Rust
//! The routing table's own reading of attribute bytes. A set is kept as
|
|
//! the bytes it came in, and what selection and validation need (the
|
|
//! path, the origin, the next hop) is read straight from them, by code
|
|
//! other than the decoder's. Nothing a peer sends may make that panic,
|
|
//! and what it reads must be what the decoder would have read.
|
|
#![no_main]
|
|
|
|
use bgp_rib::table::AttrStore;
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
let store = AttrStore::new();
|
|
let Some(set) = store.intern_wire(data) else {
|
|
return;
|
|
};
|
|
let key = set.key();
|
|
let mut path = Vec::new();
|
|
let has_set = set.as_path(&mut path);
|
|
let _ = set.next_hop();
|
|
// The origin is the path's last AS, unless a set is in the way.
|
|
if let Some(origin) = key.origin() {
|
|
assert_eq!(path.last(), Some(&origin));
|
|
}
|
|
if !has_set {
|
|
assert_eq!(usize::from(key.as_path_len), path.len());
|
|
}
|
|
// The same bytes are the same set.
|
|
let again = store.intern_wire(data).expect("it was a set a moment ago");
|
|
assert!(std::sync::Arc::ptr_eq(&set, &again));
|
|
let _ = set.attributes();
|
|
});
|