Commit Graph
10 Commits
Author SHA1 Message Date
Rayhaan JaufeerallyandClaude Fable 5.1 8086aa994f Verify AS paths with ASPAs, over RTR version 2
Origin validation says who may originate a prefix and nothing about the
rest of the path: it does not catch a route leak, nor a hijack that keeps
the right origin at the end of a made-up path. ASPAs, in which a network
lists its providers, do.

bgp-rpki:
- aspa: the ASPAs and the upstream and downstream verification procedures
  of draft-ietf-sidrops-aspa-verification-24, tested against the draft's
  wording as written.
- rtr: protocol version 2 (draft-ietf-sidrops-8210bis-23) with the ASPA
  PDU and the new error codes.
- client: asks for version 2 and falls back to whatever older version the
  cache speaks; keeps ASPAs with the VRPs, applied whole or not at all;
  publishes which customers' ASPAs changed; tells the cache why it is
  being left (Error Report); does not ask one version's serial of another.

Server:
- A peer has a role (provider, customer, peer, route server, route server
  client), which decides how its paths are verified. Without one they are
  not.
- A route whose path is invalid is refused ("ASPA invalid") and held, like
  one with an invalid origin; accept_aspa_invalid exempts a peer.
- When ASPAs change, routes in the table whose path has a changed customer
  on it are verified again, and held routes are released when they pass
  both checks.
- The revalidator finds a route's peer by index instead of searching a
  list for every route.

The status page and API show each peer's role, each route's path validity,
the number of ASPAs and the RTR version in use; bgp_rpki_aspas is on
/metricz.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 14:12:59 +02:00
Rayhaan JaufeerallyandClaude Fable 5.1 bdaf226a16 Validate route origins against the RPKI and refuse invalid routes
With rpki { caches { ... } } in the configuration the server keeps the
validated ROA payloads of a validator and validates every route from a
peer outside its own AS (RFC 6811). An invalid route is refused, unless
its peer has accept_rpki_invalid. Valid and not-found routes are taken;
validity does not otherwise enter route selection.

Validity is not settled when a route arrives: the data changes every few
minutes. The routes follow, without the peer sending anything again.

- A route refused as invalid is held by its session, out of the table.
  When the data changes the session looks at what it holds, and what is
  no longer invalid goes into the table. A held route is the peer's to
  withdraw or replace like any other.
- A route in the table that becomes invalid is found by a task that
  looks through the table when the data changes, at the prefixes the
  changed VRPs cover, and is taken out and held by its session.
- If the data expires because no cache confirms it, nothing is invalid
  any more and everything held is taken.
- A session holds at most 200,000 routes; past that it asks the peer for
  a route refresh when the data changes.

So that the table can be looked through without parsing attributes, an
attribute set's key now has the route's origin AS. Memory per route is
unchanged at 52 bytes on the real table.

Shown: /api/rpki and a section of the status page with the cache, its
state and the age of the data; each route's validity; each peer's count
of held routes. Refusals are recorded under "RPKI invalid". Metrics:
bgp_rpki_vrps and bgp_rpki_updates_total.

Also: Negotiated says whether the peer supports route refresh, and
docs/RFCs.md is brought up to date.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 13:39:40 +02:00
Rayhaan JaufeerallyandClaude Fable 5.1 1f89fb4b13 Add the bgp-rpki crate: route origin validation and an RTR client
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>
2026-10-02 13:28:32 +02:00
Rayhaan JaufeerallyandClaude Fable 5.1 630c175918 Rework the speaker: sans-I/O FSM, sharded table, RFC 7606, ADD-PATH
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>
2026-10-02 12:35:54 +02:00
Rayhaan JaufeerallyandClaude Sonnet 4.6 1ec60255ea feature: BGP server, FSM, Adj-RIB-In actor, and integration tests
- Implement passive-side BGP FSM (OpenSent → OpenConfirm → Established)
  with hold timer, keepalive timer, and NOTIFICATION on expiry
- Add bgp-server crate: config validation, TCP listener accept loop
  (BgpServerBuilder → BgpServer), connection dispatch
- Add bgp-rib crate: Adj-RIB-In actor owning route state with event
  broadcast for streaming consumers and snapshot for introspection
- Wire Adj-RIB-In into FSM: announce/withdraw on UPDATE for both legacy
  IPv4 NLRI fields and MP_REACH/MP_UNREACH path attributes
- Add bgp-integration-tests crate with 15 end-to-end tests covering
  session establishment, timers, UPDATE handling, and RIB introspection
- Fix require_empty! macro bug in open.rs (checked wrong buffer)
- Fix FourByteAsn capability parser returning consumed buffer as remainder
- Fix tracing subscriber not being installed in TracingArgs::install
- Expand docs/RFCs.md with full implementation status across 15 RFCs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 00:21:51 +02:00
Rayhaan Jaufeerally 5ae8f6e249 Cleanup and implementation of Update / Notification parser / serializers. 2026-04-18 12:58:51 +02:00
Rayhaan Jaufeerally dfe066c9ab ops: prepare for v0.0.2 2025-07-27 13:21:38 +02:00
Rayhaan Jaufeerally ab20160014 feature: Implement more path attributes 2025-07-20 15:25:41 +02:00
Rayhaan Jaufeerally 4b130985da Fix cargo.toml package info 2025-04-19 17:28:27 +02:00
Rayhaan Jaufeerally bea504ea8b Initial commit 2025-04-19 17:13:04 +02:00