Skip to content

Route Validation BIRD template

Stefan Plug edited this page Jul 11, 2017 · 27 revisions

This template shows you how you can set up BIRD 1.6.3 Import filters which are commonly used on a Route Server. Obviously this is just an example, but it does show you which filters we think an IXP should filter for.

The bogon ASNs and bogon IP prefixes we use were sourced from: http://bgpfilterguide.nlnog.net/guides

The import filters which are discussed here are:

  • Prefix length
  • IP bogons
  • AS bogons
  • AS path Too Long
  • The first ASN in AS_Path different then the advertising peer
  • The next hop IP is different from the advertising peer IP
  • The advertised prefix belongs to our Peering LAN

Constants

Usually you would like to define your constants somewhere at the beginning of your BIRD configuration so that you can easily turn the knobs of your BIRD configuration.

define RSasn = 65536;
define ipv4MaxPrefLen = 24;                 # RFC 7454  section 6.1.3.  "Prefixes That Are Too Specific"
define ipv6MaxPrefLen = 48;                 # RFC 7454  section 6.1.3.  "Prefixes That Are Too Specific"
define ASMaxPathLen = 64;                   # This number is not a universal truth, but we can assume that a path this long must be the result of a misconfiguration  

Communities showing why a route was filtered

You probably also want to define specific communities which you can add to a route just before you filter them. This enables you to easily identify why a route was filtered with show route filtered all. This does mean that you need to keep filtered routes which is the following command in your peer configurations: import keep filtered on;.

define filteredRoute = 1101;                # (RSasn:1101:reason) This route was filtered
define prefixTooLong = 1;                   # Prefix is too long
define ipBogon = 3;                         # An IP Bogon was detected
define bogonASN = 4;                        # AS path contains a bogon AS
define pathTooLong = 5;                     # AS path length is longer than 64
define firstASNotPeer = 7;                  # First AS in path is not the same as the Peer AS
define nextHopNotPeerIp = 8;                # advertised nexthop address is not the same as the peer
define IXPHijack = 101;                     # IXP prefix hijack

Ranges

Your own IXP peering LAN prefix

Normally you would not want anyone to advertise your peering LAN prefixes to the Internet, it might look a bit silly if you would not filter out your own Peering LAN prefixes when someone announces these to your own Route Server.

In the following example we create a list of all ECIX peering LAN prefixes which we will later use in the actual import filter.

IPv6: define IXP_net = [ 2001:7F8:8::/64, 2001:7f8:8:5::/64, 2001:7f8:8:10::/64, 2001:7f8:8:15::/64, 2001:7f8:8:20::/64, 2001:7f8:8:25::/64, 2001:748:2c:1000::/64 ];

IPv4: define IXP_net = [ 194.146.118.0/24, 194.9.117.0/24, 193.42.155.0/24, 62.69.144.0/23, 62.69.146.0/23, 194.59.190.0/24 ];

IP Bogon definitions

{% if bird6 %}
define ip_bogons = [
    0000::/8+,
    0100::/8+,
    0200::/7+,
    0400::/6+,
    0800::/5+,
    1000::/4+,
    4000::/3+,
    6000::/3+,
    8000::/3+,
    A000::/3+,
    C000::/3+,
    E000::/4+,
    F000::/5+,
    F800::/6+,
    FC00::/7+,
    FE00::/9+,
    FE80::/10+,
    FEC0::/10+,
    FF00::/8+ 
];
{% else %}
define ip_bogons = [
    0.0.0.0/0, 
    0.0.0.0/8+, 
    10.0.0.0/8+, 
    100.64.0.0/10, 
    127.0.0.0/8, 
    192.168.0.0/16+, 
    169.254.0.0/16+, 
    192.0.2.0/24+, 
    172.16.0.0/12+, 
    224.0.0.0/3+, 
    198.51.100.0/24+, 
    198.18.0.0/15+, 
    203.0.113.0/24+, 
    224.0.0.0/4,
    240.0.0.0/4
];

Bogon ASN definition

define asn_bogons = [
    0,                      # RFC 7607
    23456,                  # RFC 4893 AS_TRANS
    64496..64511,           # RFC 5398 and documentation/example ASNs
    64512..65534,           # RFC 6996 Private ASNs
    65535,                  # RFC 6996 Last 16 bit ASN
    65536..65551,           # RFC 5398 and documentation/example ASNs
    65552..131071,          # RFC IANA reserved ASNs
    4200000000..4294967294, # RFC 6996 Private ASNs
    4294967295              # RFC 6996 Last 32 bit ASN
];

Import Functions

function importScrub(int peeras) {

# Remove IP bogons
    if (net ~ ip_bogons) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": Bogon prefix!";
        bgp_large_community.add((RSasn,filteredRoute,ipBogon));
        return false;
    }

#remove prefixes longer then /24 or /64
    {% if bird6 %}
    if (net.len > ipv6MaxPrefLen) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": Prefix is to long: ",net.len,"!";
        bgp_large_community.add((RSasn,filteredRoute,prefixTooLong));
        return false;
    }
    {% else %}
    if (net.len > ipv4MaxPrefLen) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": Prefix is to long: ",net.len,"!";
        bgp_large_community.add((RSasn,filteredRoute,prefixTooLong));
        return false;
    }
    {% endif %}

# Remove Bogon ASNs
    if ( bgp_path ~ asn_bogons ) then {
        print "REJECTING: ",net," received from ",from,": AS path contains a bogon AS: ",bgp_path,"!";
        bgp_large_community.add((RSasn,filteredRoute,bogonASN));
        return false;
    }

# Make sure the AS path length is not ridiculously long
    if (bgp_path.len > ASMaxPathLen) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": AS path length is ridiculously long: ",bgp_path.len,"!";
        bgp_large_community.add((RSasn,filteredRoute,pathTooLong));
        return false;
    }

# Make sure the first AS in AS path is the customer one
    if (bgp_path.first != peeras) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": First AS is not the same as Peer AS: advertised AS (",bgp_path.first,") Peer AS (",peeras,")!";
        bgp_large_community.add((RSasn,filteredRoute,firstASNotPeer))
        return false;
    }

# Removes IXP prefixes annouced by someone else
    if ((bgp_path.first != RSasn) && (net ~ ecix_net)) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": IXP prefix hijack! Peer AS (",peeras,")";
        bgp_large_community.add((RSasn,filteredRoute,IXPHijack));
        return false;
    }

# Make sure BGP nexthop belongs to the router advertising the prefix. 
    if (bgp_next_hop != from) then {
        print "REJECTING: ",net.ip,"/",net.len," received from ",from,": Next hop is not the same as Peer IP address: next hop (",bgp_next_hop,"), peer IP (",from,"), Peer AS (",peeras,")!";
        bgp_large_community.add((RSasn,filteredRoute,nextHopNotPeerIp));
        return false;
    }
    return true;
}

###Process incoming prefix advertisements
function importProcessing( int peeras; int set IRRDB_ASSet; int peerrtt ) {
    if !(importScrub(peeras)) then reject;
    #space for other filter functions such as RPKI and IRRDB filtering
    accept;
}

Peer configuration

protocol bgp 'AS1234' {
    debug {events, states};
    description "PEER AS65537 192.0.2.1 example_corp"; 
    local as RSasn;
    neighbor 1.2.3.4 as 65537;
    rs client;
    passive on;
    enable route refresh on;
    graceful restart on;
    interpret communities off;
    table master;
    secondary;
    export all;
    import where importProcessing(65537);
    import keep filtered on;  
    import limit 16000 action restart;
    password "SuPeRSeCrEt";
}