Table | Charts | Pseudocode
Introduction:
This page details the strict filtering happening on the SIX route servers.
When a prefix is advertised, the route server performs a series of tests to decide whether the prefix may be accepted. If a prefix fails to pass any test, it is dropped prior to further tests. One could imagine that a prefix has to "run the gauntlet" before it may be accepted and propagated to route server peers. For each route server instance, the table below lists these tests in the order they occur. The counts in the table reflect the number of unique drops for a test since the start of the UTC day. Clicking a count reveals further details.
The charts below show drops over time, enabling the perception of network events and adoption of industry standards like RPKI.
Drops for a specific ASN can be viewed by adjusting the URL for this page to include "?asn=#" with "#" changed to the ASN of interest.
Pseudocode showing how the SIX performs filtering is also below.
Feel free to email info_a_t_seattleix.net with any bug fixes to the pseudocode or other feedback about this page.
Route server drops since start of UTC day:
Prefix Drop Reason (in order of tests) | rs2.1500.v4 | rs3.1500.v4 | rs2.1500.v6 | rs3.1500.v6 | rs2.9000.v4 | rs3.9000.v4 | rs2.9000.v4new | rs3.9000.v4new | rs2.9000.v6 | rs3.9000.v6 |
---|---|---|---|---|---|---|---|---|---|---|
Not peer AS | ||||||||||
Bad next hop | ||||||||||
Default route | ||||||||||
Local subnet | ||||||||||
Path too long | ||||||||||
Bogon prefix | ||||||||||
Cymru fullbogons prefix | ||||||||||
Too large | ||||||||||
Bogon ASN | ||||||||||
PeeringDB ASN never via RS | ||||||||||
Transit ASN | ||||||||||
RPKI ROA_INVALID adjacent | ||||||||||
RPKI ROA_INVALID transit | ||||||||||
No IRR route object adjacent | ||||||||||
ASN not in as-set | ||||||||||
Prefix not in as-set | ||||||||||
Prefix in as-set but origin ASN IRR mismatch route objects | ||||||||||
Prefix in as-set but no IRR route object for origin ASN | ||||||||||
Total |
#if IPv4 # http://bgpfilterguide.nlnog.net/guides/bogon_prefixes/ define BOGON_PREFIXES = [ 0.0.0.0/8+, # RFC 1122 'this' network 10.0.0.0/8+, # RFC 1918 private space 100.64.0.0/10+, # RFC 6598 Carrier grade nat space 127.0.0.0/8+, # RFC 1122 localhost 169.254.0.0/16+, # RFC 3927 link local 172.16.0.0/12+, # RFC 1918 private space 192.0.2.0/24+, # RFC 5737 TEST-NET-1 192.88.99.0/24+, # RFC 7526 6to4 anycast relay 192.168.0.0/16+, # RFC 1918 private space 198.18.0.0/15+, # RFC 2544 benchmarking 198.51.100.0/24+, # RFC 5737 TEST-NET-2 203.0.113.0/24+, # RFC 5737 TEST-NET-3 224.0.0.0/4+, # multicast 240.0.0.0/4+ ]; # reserved #else # http://www.space.net/~gert/RIPE/ipv6-filters.html # http://bgpfilterguide.nlnog.net/guides/bogon_prefixes/ define BOGON_PREFIXES = [ ::/8+, # RFC 4291 IPv4-compatible, loopback, et al 0100::/64+, # RFC 6666 Discard-Only 2001:2::/48+, # RFC 5180 BMWG 2001:10::/28+, # RFC 4843 ORCHID 2001:db8::/32+, # RFC 3849 documentation 2002::/16+, # RFC 7526 6to4 anycast relay 3ffe::/16+, # RFC 3701 old 6bone fc00::/7+, # RFC 4193 unique local unicast fe80::/10+, # RFC 4291 link local unicast fec0::/10+, # RFC 3879 old site local unicast ff00::/8+ ]; # RFC 4291 multicast #endif # http://as2914.net/bogon_asns/configuration_examples.txt # http://bgpfilterguide.nlnog.net/guides/bogon_asns/ define BOGON_ASNS = [ 0, # RFC 7607 23456, # RFC 4893 AS_TRANS 64496..64511, # RFC 5398 and documentation/example ASNs 64512..65534, # RFC 6996 Private ASNs 65535, # RFC 7300 Last 16 bit ASN 65536..65551, # RFC 5398 and documentation/example ASNs 65552..131071, # IANA reserved ASNs https://www.mail-archive.com/uknof@lists.uknof.org.uk/msg03395.html 4200000000..4294967294, # RFC 6996 Private ASNs 4294967295 ]; # RFC 7300 Last 32 bit ASN # http://bgpfilterguide.nlnog.net/guides/no_transit_leaks/ define TRANSIT_ASNS = [ 174, # Cogent 209, # Qwest (HE carries this on IXPs IPv6 (Jul 12 2018)) 701, # UUNET 702, # UUNET 1239, # Sprint 1299, # Telia 2914, # NTT Communications 3257, # GTT Backbone 3320, # Deutsche Telekom AG (DTAG) 3356, # Level3 3491, # PCCW 3549, # Level3 3561, # Savvis / CenturyLink 4134, # Chinanet 5511, # Orange opentransit 6453, # Tata Communications 6461, # Zayo Bandwidth 6762, # Seabone / Telecom Italia 6830, # Liberty Global 7018 ]; # AT&T function net_local() { #if IPv4 return net ~ [ 206.81.80.0/22+ ]; # matches all sub-prefixes of SIX address space 206.81.80.0/22 # or return net ~ [ 149.112.96.0/22+ ]; # matches all subprefixes of SIX address space 149.112.96.0/22 #else return net ~ [ 2001:504:16::/48+ ]; # matches all sub-prefixes of SIX address space 2001:504:16::/48 #endif } function next_hop_local() { #if IPv4 return bgp_next_hop ~ 206.81.80.0/22; # matches SIX address space 206.81.80.0/22 # or return bgp_next_hop ~ 149.112.96.0/22; # matches SIX address space 149.112.96.0/22 #else return bgp_next_hop ~ 2001:504:16::/48; # matches SIX address space 2001:504:16::/48 #endif } function rt_import(int peeras; prefix set peer_nets; int set peer_asns; prefix set as_set_nets) int path_max; int rpki_roa_valid; { if bgp_path.first != peeras then { print proto, ": ", net, " from ", from, " ", bgp_path, ": bgp_path.first(", bgp_path.first, ") != peeras(", peeras, ")! Dropping."; return false; } if ! next_hop_local() then { print proto, ": ", net, " from ", from, " ", bgp_path, ": bgp_next_hop(", bgp_next_hop, ") not local! Dropping."; return false; } #if IPv4 # Avoid 0.0.0.0/X if net.ip = 0.0.0.0 then { print proto, ": ", net, " from ", from, " ", bgp_path, ": net.ip = 0.0.0.0! Dropping."; return false; } #else # Avoid ::/X if net.ip = :: then { print proto, ": ", net, " from ", from, " ", bgp_path, ": net.ip = ::! Dropping."; return false; } #endif if net_local() then { print proto, ": ", net, " from ", from, " ", bgp_path, ": net_local() returned true! Dropping."; return false; } path_max = 128; if bgp_path.len > path_max then { print proto, ": ", net, " from ", from, " ", bgp_path, ": bgp_path.len(", bgp_path.len, ") > ", path_max, "! Dropping."; return false; # limit AS_PATH length (to prevent problems with misconfigured routers # propagating too long path and buggy routers crashing on that) } if net ~ BOGON_PREFIXES then { print proto, ": ", net, " from ", from, " ", bgp_path, ": matches bogon_prefixes! Dropping."; return false; } if net ~ CYMRU_FULLBOGONS_PREFIXES then { print proto, ": ", net, " from ", from, " ", bgp_path, ": matches cymru_fullbogons_prefixes! Dropping."; return false; } #if IPv4 if net.len < 8 then { print proto, ": ", net, " from ", from, " ", bgp_path, ": net.len < 8! Dropping."; return false; } #else if net.len < 19 then { print proto, ": ", net, " from ", from, " ", bgp_path, ": net.len < 19! Dropping."; return false; } #endif if bgp_path ~ BOGON_ASNS then { print proto, ": ", net, " from ", from, " ", bgp_path, ": matches bogon_ASNs! Dropping."; return false; } if bgp_path ~ PDB_NEVER_VIA_ROUTE_SERVERS_ASNS then { print proto, ": ", net, " from ", from, " ", bgp_path, ": matches pdb_never_via_route_servers_ASNs! Dropping."; return false; } if bgp_path ~ TRANSIT_ASNS then { print proto, ": ", net, " from ", from, " ", bgp_path, ": matches transit_ASNs! Dropping."; return false; } rpki_roa_valid = 0; case roa_check(ROAS, net, bgp_path.last_nonaggregated) { ROA_INVALID: if bgp_path.last_nonaggregated = peeras then { print proto, ": ", net, " from ", from, " ", bgp_path, ": RPKI ROA_INVALID! Dropping."; } else { print proto, ": ", net, " from ", from, " ", bgp_path, ": RPKI ROA_INVALID! Transit_dropping."; } return false; ROA_VALID: rpki_roa_valid = 1; } if bgp_path.last_nonaggregated = peeras then { # IRR route object verification is not needed when RPKI ROA is valid. if 0 = rpki_roa_valid then { # Route is from peer ASN, so just check peer prefix list. if ! (net ~ peer_nets) then { print proto, ": ", net, " from ", from, " ", bgp_path, ": no IRR route object found! Dropping."; return false; } } } else { # Route is not from peer ASN, so check peer ASN list. if ! (bgp_path.last_nonaggregated ~ peer_asns) then { print proto, ": ", net, " from ", from, " ", bgp_path, ": AS", bgp_path.last_nonaggregated, " not member of IRR as-set object! Dropping."; return false; } # IRR route object verification is not needed when RPKI ROA is valid. if 0 = rpki_roa_valid then { # Route is not from peer ASN, so check peer as-set prefix list. if ! (net ~ as_set_nets) then { print proto, ": ", net, " from ", from, " ", bgp_path, ": no IRR route object with matching origin found! Transit_dropping."; return false; } # The IRR-based ROAs table we use here must include all prefixes, both from # adjacent ASN and downstream ASNs. # # ROA_VALID: if there is a matching ROA # ROA_INVALID: if there are some relevant ROAs but none of them match # ROA_UNKNOWN: if there is no relevant ROA # # We test for ROA_INVALID and ROA_UNKNOWN here, and return false if either happens, # because to get here means the following: # # - this prefix is from a non-adjacent ASN # - the last ASN is in the as-set # - the prefix is in the as-set # # so what we are testing here is to make sure the prefix has the correct AS origin. # A return of ROA_INVALID or ROA_UNKNOWN means it does not. # # ROA_UNKNOWN can happen if the IRR as-set prefix list includes a covering prefix, # but none of the perceived ASNs has an IRR entry for the prefix. # case roa_check(IRR, net, bgp_path.last_nonaggregated) { ROA_INVALID: print proto, ": ", net, " from ", from, " ", bgp_path, ": no IRR route object with matching origin found (ROA_INVALID)! Transit_dropping."; return false; ROA_UNKNOWN: print proto, ": ", net, " from ", from, " ", bgp_path, ": no IRR route object with matching origin found (ROA_UNKNOWN)! Transit_dropping."; return false; } } } return true; }