# Lixonet BIRD configuration # This is a templated file that automatically generates values at configuration time # If you edit this file, it will be overwritten. Changes to the general structure of # this configuration file that should be persisted should be committed to Git. # For BIRD 2.0 configuration reference, see: # https://bird.network.cz/?get_doc&f=bird.html&v=20 # For a great example configuration file, see: # https://fossies.org/linux/bird/doc/bird.conf.example # Global variables # See: https://bird.network.cz/?get_doc&v=20&f=bird-3.html#ss3.2 log stderr all; # Using docker; defer logging to stderr (to Docker logs) #debug protocols all; # Enable debugging (this should be switched off in prod) router id ${tinc_peer_address}; timeformat protocol iso long; # See: https://github.com/czerwonk/bird_exporter # Custom routing tables # See: https://bird.network.cz/?get_doc&v=20&f=bird-2.html (recommended read) ipv4 table ${netname:-lixonet}_v4; roa4 table r4; # ROA RPKI # RPKI # See: https://brooks.sh/2019/11/11/validating-bgp-routes-with-rpki-in-bird/ protocol rpki { roa4 { table r4; }; {{ range files "bird/rpki/hosts" }} # {{.}} {{ file (print "bird/rpki/hosts/" .) }} {{ end }} # Time period in seconds between a failed query the next attempt retry keep ${bgp_rpki_retry:-90}; # Tells how long to wait before attempting to poll the cache refresh keep ${bgp_rpki_refresh:-900}; # How long to keep any records locally cached before they are deleted # The "refresh" interval will control how often records are refreshed # and not considered expired. expire keep ${bgp_rpki_expire:-172800}; } # Filters # Define a series of filters for Lixonet routing policies: # - Cannot advertise a route which is in the router subnet: typically 172.x.0.0/24 # See: https://gitlab.labs.nic.cz/labs/bird/wikis/BGP_filtering # For syntax docs, see: https://bird.network.cz/?get_doc&v=16&f=bird-5.html # Returns TRUE if the given prefix is found in a kept RPKI cache. # Returns FALSE if the given prefix is either, # - Valid in the cached RPKI list, or # - RPKI has not yet been established and the route cannot be validated # From BIRD documentation (https://bird.network.cz/?get_doc&v=20&f=bird-5.html): # roa_check: Checks the current route (which should be from BGP to # have AS_PATH argument) in the specified ROA table and returns # ROA_UNKNOWN if there is no relevant ROA, ROA_VALID if there is # a matching ROA, or ROA_INVALID if there are some relevant ROAs # but none of them match. function is_rpki_invalid_v4 () { return roa_check(r4, net, bgp_path.last_nonaggregated) = ROA_INVALID; } # Returns TRUE if the given tested network is the exact global network prefix for # Lixonet. Used to filter the "unreachable" static route we typically static. function is_exact_lixonet_global_v4() { return net ~ [ ${network_address}/${global_prefix:-16} ]; } # Returns TRUE if the given tested network is within the global network prefix for # Lixonet. Used to filter networks outside of this range as they are not within # the global mesh network. function is_lixonet_global_v4() { return net ~ [ ${network_address}/${global_prefix:-16}+ ]; } # Returns TRUE if the given tested network is within the router network prefix for # Lixonet. Used to filter these routes from BGP as Tinc statically assigns them # for us. Helps prevent a security vulnerability of hijacking another router. function is_lixonet_router_v4() { return net ~ [ ${network_address}/${router_prefix:-24}+ ]; } function is_own_route_v4() { {{ if len "${bgp_routes:-}" }}{{ range "$bgp_routes" | split "," }}if net ~ [ {{.}}+ ] then return true; {{ end }}{{ end }} return false; } function is_wireguard_route_v4() { {{ if len "${wg_routes:-}" }}{{ range "$wg_routes" | split "," }}if net ~ [ {{.}}+ ] then return true; {{ end }}{{ end }} return false; } filter bgp_import_filter_v4 { if source ~ [RTS_STATIC] then reject; # Reject our own routes if is_rpki_invalid_v4() then reject; # Reject posions if is_lixonet_router_v4() then reject; # Reject poisons if is_own_route_v4() then reject; # Reject poisons if is_lixonet_global_v4() then accept; # Accept anything else reject; # Reject anything else (non-Lixonet) } filter bgp_export_filter_v4 { if is_lixonet_router_v4() then reject; # Reject poisons if is_exact_lixonet_global_v4() then reject; # Reject the unreachable route if is_lixonet_global_v4() then accept; # Accept anything else reject; # Reject anything else (non-Lixonet) } # In some cases, like WireGuard, we can be a peer to a client which is # available over another "adjacent" VPN layer. In these cases, allow # importing routes that are added to the kernel which fall under the # Wireguard layer filter kernel_import_filter_v4 { if is_own_route_v4() then reject; # Reject unexpected routes if is_wireguard_route_v4() then accept; # Accept WireGuard routes reject; # Reject anything else } filter kernel_export_filter_v4 { #if is_own_route_v4() then reject; # Reject poisons if is_lixonet_global_v4() then accept; # Accept anything else reject; # Reject anything else (non-Lixonet) } # Static routes # Define propagated routes here from the lixonet.conf "routes" variable # Attached to the above "lixonet" routing table; "provide" these routes into it # See how dn42 does it; we're very similar: https://dn42.net/howto/Bird protocol static { ipv4 { table ${netname:-lixonet}_v4; import all; export none; }; # Announce the whole network as unreachable; this returns packets that reach # this router as unreachable (ICMP type=3, code=0) if no more specific route # is defined for the network subnet route ${network_address}/${global_prefix:-16} unreachable; # Announced networks {{ if len "${bgp_routes:-}" }}{{ range "$bgp_routes" | split "," }}route {{.}} via ${internal_gateway}; {{ end }}{{ end }} }; # Device # See: https://bird.network.cz/?get_doc&v=20&f=bird-6.html#ss6.4 # This controls which interfaces BGP, etc. will bind to for communication # This prevents BGP from listening on eth0/off-network protocol device { scan time 10; # Scan the interfaces often interface "${netname:-lixonet}" { preferred ${tinc_peer_address}; }; }; # Direct (unnecessary for Lixonet) # See: https://bird.network.cz/?get_doc&v=20&f=bird-6.html#ss6.5 # Disable automatically generating direct routes to all network interfaces. protocol direct { disabled; # Disable by default }; # Kernel routing table # See: https://bird.network.cz/?get_doc&v=20&f=bird.html#toc6.6 protocol kernel { # Primary routing table learn; # Learn alien routes from the kernel persist; # Don't remove routes on bird shutdown scan time 10; # Scan kernel routing table every 10 seconds ipv4 { table ${netname:-lixonet}_v4; import filter kernel_import_filter_v4; # Import anything we allow from the kernel export filter kernel_export_filter_v4; # Export everything we are told to the kernel }; }; # BFD protocol bfd { interface "${netname:-lixonet}" { min rx interval 1 s; min tx interval 1 s; idle tx interval 5 s; multiplier 5; }; }; # BGP (primary Lixonet routing protocol) # This is a template to use when connecting to other BGP clients on the EE network # This template is applied to ALL neighbors, so consider these global settings that # apply to all neighbors. See "Neighbors" section of this configuration for # individual neighbor configurations where per-neighbor configurations (such as their # ASN) are applied. template bgp lixonet_client { local as ${bgp_asn}; # Local AS advertised to peers source address ${tinc_peer_address}; # What local IP address we use for any outbound TCP # connections on port 179 path metric ${bgp_path_metric:-1}; # 1 = Prefer routes with shorter paths (like Cisco does) # Turn on BFD (bidirectional forwarding detection) bfd on; # BGP channels # See: Channel configuration (BIRD BGP configuration) and the table shown there. # BGP IPv4 channel settings ipv4 { table ${netname:-lixonet}_v4; # Always advertise our own local address as a next hop, even in cases where the # current Next Hop attribute should be used unchanged. # Reason: tinc NEEDS this, otherwise Layer3 inter-routing on the mesh will be broken next hop self ebgp; # aigp (see: http://www.rfc-editor.org/info/rfc7311) # Lixonet default: originate AIGP # This not only allows AIGP attribute propagation, but also new AIGP attributes are # automatically attached to non-BGP routes with valid IGP metric (e.g. ospf_metric1) # as they are exported to the BGP session. # Thank-you, BIRD <3 - mane and nurd aigp ${bgp_aigp:-originate}; # Set filters for both exported (sent) and imported (received) BGP prefixes. # This is explicitly required per RFC 8212, at least on export. # See: https://gitlab.labs.nic.cz/labs/bird/commit/3831b619661d08d935fd78656732cd2f339ff811 export filter bgp_export_filter_v4; import filter bgp_import_filter_v4; }; }; # Neighbors {{ range files "bird/peers" }} {{ if ne . "${tinc_peer_name}" }} protocol bgp {{ . }} from lixonet_client { description "Lixonet BGP link to {{ . }}"; {{ include (print "bird/peers/" .) }} };{{ end }}{{ end }}