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>
81 lines
3.5 KiB
Protocol Buffer Text Format
81 lines
3.5 KiB
Protocol Buffer Text Format
# A worked example; the fields are documented in
|
|
# crates/server/proto/config.proto.
|
|
router_id: "10.0.0.1"
|
|
local_asn: 65000
|
|
|
|
# Where to accept BGP connections. Port 179 needs privileges; pick another
|
|
# port to run unprivileged against a peer that dials a custom port.
|
|
listen_endpoints { address: "127.0.0.1" port: 179 }
|
|
listen_endpoints { address: "::1" port: 179 }
|
|
|
|
# A peer we connect to and accept connections from. Connections from any
|
|
# other address are closed unread, unless accept_unconfigured_peers is set,
|
|
# which is for a closed test network only.
|
|
peers {
|
|
name: "r1"
|
|
endpoint { address: "127.0.0.1" port: 1791 }
|
|
remote_asn: 65001
|
|
hold_time_seconds: 30
|
|
# Offer only these families to the peer. Left out, all are offered.
|
|
address_families: IPV4_UNICAST
|
|
address_families: IPV6_UNICAST
|
|
# Take several routes for a prefix from this peer, if it offers to send
|
|
# them (ADD-PATH). Also ADD_PATH_SEND and ADD_PATH_BOTH. Off by default.
|
|
add_path: ADD_PATH_RECEIVE
|
|
# What the peer is to us: PROVIDER, CUSTOMER, PEER, ROUTE_SERVER or
|
|
# ROUTE_SERVER_CLIENT. With it the peer must not claim to be something
|
|
# else (RFC 9234), routes are marked "only to customer" and leaks of
|
|
# marked routes are refused; and with a validator that has ASPAs, the
|
|
# AS paths of the peer's routes are verified.
|
|
# role: PEER
|
|
# Refuse the peer if its OPEN does not say what it is.
|
|
# require_role: true
|
|
# Which of the peer's routes are taken. Without this block the general
|
|
# checks still apply: no private or reserved prefixes or AS numbers,
|
|
# nothing longer than /24 or /48, no default route, and a path that
|
|
# begins with the peer's AS. This example is a test network that uses
|
|
# exactly such prefixes and AS numbers, so it takes them.
|
|
import {
|
|
# More routes than this ends the session and keeps the peer down
|
|
# for hold_down_seconds (600 unless set).
|
|
max_prefixes: 1000
|
|
accept_bogons: true
|
|
# A route's next hop has to be the peer itself. The test peer of
|
|
# this example is at 127.0.0.1, which nothing can be sent by way
|
|
# of, and names another address; so here any is taken.
|
|
accept_third_party_next_hop: true
|
|
# For a real peer: the prefixes and origin ASes it may announce,
|
|
# as generated from the routing registries.
|
|
# prefixes { prefix: "193.0.0.0/21" max_length: 24 }
|
|
# origin_asns: 3333
|
|
}
|
|
}
|
|
connect_retry_seconds: 5
|
|
|
|
# Let a restarted peer replace a stale Established session immediately
|
|
# (RFC 4271 CollisionDetectEstablishedState). Default false.
|
|
collision_detect_established_state: false
|
|
|
|
# Routes this router originates, announced to every peer.
|
|
originate { prefix: "10.100.0.0/16" }
|
|
originate {
|
|
prefix: "2001:db8:100::/48"
|
|
med: 50
|
|
communities: "65000:100"
|
|
large_communities: "65000:1:2"
|
|
}
|
|
|
|
# Validation with the RPKI: refuse routes whose origin AS is not the one the
|
|
# holder of the addresses authorised, and, from peers with a role, routes
|
|
# whose AS path is a leak. Point it at a validator's RTR server.
|
|
# rpki { caches { address: "127.0.0.1" port: 3323 } }
|
|
|
|
# Put the best route of every prefix in the kernel's routing table, so that
|
|
# this machine forwards by them (Linux; needs CAP_NET_ADMIN). Routes are
|
|
# marked "proto bgp"; table and metric default to 254 (main) and 20.
|
|
# kernel {}
|
|
|
|
# Read-only status page, JSON API and metrics. It has no authentication:
|
|
# keep it on loopback or behind a reverse proxy.
|
|
http_endpoint { address: "127.0.0.1" port: 8080 }
|