Files
ferrix/fuzz/fuzz_targets/netlink.rs
T
Rayhaan JaufeerallyandClaude Fable 5.1 1fc44798b7 Install best routes in the Linux kernel over netlink
New crate bgp-fib. It follows the routing table's best routes and keeps
the kernel's routing table the same, and learns the machine's interfaces
and addresses from the kernel, which is what says whether a next hop can
be reached.

- netlink: the rtnetlink messages used (routes, addresses, links, errors),
  as bytes and back. No I/O; property tested and fuzzed.
- interfaces: what is directly reachable, and from which interface.
- plan: what to ask the kernel for, given the best routes and what the
  kernel has. No I/O; tested against a model kernel.
- kernel (Linux only): the sockets and the task. Requests go in batches;
  routes of ours found at startup are kept if still right and removed if
  not; a change of interfaces has every route worked out again; a clean
  stop removes our routes.

Only routes marked proto bgp with the configured table and metric are
ever touched. A best route is installed if its next hop is a neighbor;
next hops further away are not resolved through other routes yet, and
such prefixes are counted and shown instead.

Configured with `kernel { table metric }`; off by default. The daemon
needs CAP_NET_ADMIN and stops if the kernel refuses it. On shutdown it
closes sessions and then removes its routes.

/api/kernel and the status page show installed, unresolved and refused
counts, the last error and the interfaces; five bgp_kernel_* metrics.

Testing: scripts/kernel-tests.sh runs, in network namespaces of their
own and with only the capabilities the daemon needs, the installer
against `ip route`, the daemon with a peer, and two daemons that route
for each other with pings across over IPv4 and IPv6.
scripts/linux-vm.sh runs that, or anything else, in a Lima VM from
macOS. CI runs the kernel tests and fuzzes the netlink decoder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 15:15:43 +02:00

35 lines
1.2 KiB
Rust

//! Bytes from the kernel's routing socket. The kernel is trusted, but what
//! it sends is read with code of ours, and a daemon that dies on an
//! unusual route stops routing.
#![no_main]
use bgp_fib::netlink::{Change, Message, decode, route_request};
use bytes::BytesMut;
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
let mut rest = data;
// As the daemon reads: one message after another until one is wrong.
while !rest.is_empty() {
let Ok((_, message, used)) = decode(rest) else {
return;
};
assert!(used > 0 && used <= rest.len());
rest = &rest[used..];
let _ = format!("{message:?}");
// A route that was read can be asked for, and what is asked for
// reads back as itself.
if let Message::Route { present, route } = message {
let change = if present {
Change::Replace
} else {
Change::Remove
};
let mut out = BytesMut::new();
route_request(&mut out, 1, change, false, &route);
let (_, again, _) = decode(&out).expect("what is written can be read");
assert_eq!(again, Message::Route { present, route });
}
}
});