Route filter generation for Mikrotik RouterOS via IRR

A while back I posted about routing filter generation via bgpq3 for Cisco (ios and XR) and Juniper JunOS based routers. I have received a number of emails in last few months about automated filter generation for Mikrotik routeros. Since Mikrotik’s CCRs are getting quite popular across small to mid-sized ISPs. So this blog post is about ways for generating filter config for a given ASN via IRR. One can use such logic with some kind of remote login mechanism like rancid (look for mtlogin here). I tried building around bgpq3 but it seems more easy with another popular tool in the domain called IRR Power Tools. Once IRR Power Tools (IRRPT) is setup, it allows us to fetch prefixes based via Internet Routing Registries and also aggregates them.   So, for instance, let’s pick AS54456:

anurag@tools:~/irrpt$ bin/irrpt\_fetch 54456
Processing AS54456 (Record 1)
   - Importing /home/anurag/irrpt/db/54456                   version 1.1
   - Importing /home/anurag/irrpt/db/54456.4                 version 1.1
   - Importing /home/anurag/irrpt/db/54456.6                 version 1.1
   - Importing /home/anurag/irrpt/db/54456.agg               version 1.1
   - Importing /home/anurag/irrpt/db/54456.4.agg             version 1.1
   - Importing /home/anurag/irrpt/db/54456.6.agg             version 1.1
Completed processing of 1 IRR object(s).
anurag@tools:~/irrpt$

So now we have got prefixes and this includes both basic route objects as well as aggregates.

anurag@tools:~/irrpt$ cat /home/anurag/irrpt/db/54456.4
199.116.76.0/24
199.116.77.0/24
199.116.78.0/24
199.116.79.0/24
anurag@tools:~/irrpt$
anurag@tools:~/irrpt$ cat /home/anurag/irrpt/db/54456.4.agg
199.116.76.0/22
anurag@tools:~/irrpt$

It offers a nice interface for generation of config for Cisco, Juniper, Extreme, Foundry and Force10. Example:

anurag@tools:~/irrpt/bin$ ./irrpt\_pfxgen -f cisco 54456
conf t
no ip prefix-list CUSTOMER:54456
no ipv6 prefix-list CUSTOMERv6:54456
ip prefix-list CUSTOMER:54456 permit 199.116.76.0/22 le 24
end
write mem
anurag@tools:~/irrpt/bin$
anurag@tools:~/irrpt/bin$
anurag@tools:~/irrpt/bin$ ./irrpt\_pfxgen -f juniper 54456
policy-options {
    replace: policy-statement CUSTOMER:54456 {
        term prefixes {
            from {
                route-filter 199.116.76.0/22 upto /24;
            }
            then next policy;
        }
        then reject;
    }
}
policy-options {
    replace: policy-statement CUSTOMERv6:54456 {
        term prefixes {
            from {
            }
            then next policy;
        }
        then reject;
    }
}
anurag@tools:~/irrpt/bin$

So I put a routeros instance in a VM to test and create config from their CLI. Config looks something like this:

[admin@MikroTik] > routing filter add chain=Cloudaccess prefix=199.116.76.0/22 prefix-length=22-24 action=accept
[admin@MikroTik] > routing filter add chain=Cloudaccess  action=reject
[admin@MikroTik] >

This seems logical and can be scripted. So one can have a script to read the aggregate file and if aggregate says /24 one can put it directly in the filter else allow filter up to /24 from whatever range the pool starts and similar logic in IPv6. So here’s the script:

#!/bin/bash
# Script for generating BGP filter for Mikrotik RouterOS
# Input name of chain via $1 and ASN via $2
irrpt=/home/anurag/irrpt
# Grab latest filters via RADB / other IRRs using IRRPT
echo "Grabbing prefixes for AS$2"
php $irrpt/bin/irrpt_fetch $2
echo "***Start of Mikrotik routeros config below***"
# IPv4 config part
cat $irrpt/db/$2.4.agg | while read prefix
do
masklength=`echo $prefix|awk -F '/' '{print $2}'`
if [ "$masklength" -eq 24 ]
	then
	# Prefix is a /24 - generating config without defining prefix length
	echo "routing filter add chain=$1-IPv4 prefix=$prefix action=accept"
elif [ "$masklength" -lt 24 ]
	then
	# Prefix is greater than /24 - generating config with prefix length upto /24
	echo "routing filter add chain=$1-IPv4 prefix=$prefix prefix-length=$masklength-24 action=accept"
fi
done
# Last entry for denial of pools
echo "routing filter add chain=$1-IPv4 action=reject"
cat $irrpt/db/$2.6.agg | while read prefix6
do
masklength6=`echo $prefix6|awk -F '/' '{print $2}'`
if [ "$masklength6" -eq 48 ]
	then
	# Prefix is a /48 - generating config without defining prefix length
	echo "routing filter add chain=$1-IPv6 prefix=$prefix6 action=accept"
elif [ "$masklength6" -lt 48 ]
	then
	# Prefix is greater than /48 - generating config with prefix length upto /48
	echo "routing filter add chain=$1-IPv6 prefix=$prefix6 prefix-length=$masklength6-48 action=accept"
fi
done
# Last entry for denial of pools
echo "routing filter add chain=$1-IPv6 action=reject"
echo "***End of Mikrotik routeros config***"

So the script works except with a small bug in IPv6 aggregation which is the issue with IRRPT and I have reported same on their GitHub project page here.   An example of the script in progress for Cloudaccess AS54456:

anurag@tools:~/irrpt$ ./routeros.sh Cloudaccess 54456
Grabbing prefixes for AS54456
Processing AS54456 (Record 1)
Completed processing of 1 IRR object(s).
***Start of Mikrotik routeros config below***
routing filter add chain=Cloudaccess-IPv4 prefix=199.116.76.0/22 prefix-length=22-24 action=accept
routing filter add chain=Cloudaccess-IPv4 action=reject
routing filter add chain=Cloudaccess-IPv6 action=reject
***End of Mikrotik routeros config***
anurag@tools:~/irrpt$

Here’s another example of it in action with NPCI’s AS132351

anurag@tools:~/irrpt$ ./routeros.sh NPCI 132351
Grabbing prefixes for AS132351
Processing AS132351 (Record 1)
   - Importing /home/anurag/irrpt/db/132351                  version 1.1
   - Importing /home/anurag/irrpt/db/132351.4                version 1.1
   - Importing /home/anurag/irrpt/db/132351.6                version 1.1
   - Importing /home/anurag/irrpt/db/132351.agg              version 1.1
   - Importing /home/anurag/irrpt/db/132351.4.agg            version 1.1
   - Importing /home/anurag/irrpt/db/132351.6.agg            version 1.1
Completed processing of 1 IRR object(s).
***Start of Mikrotik routeros config below***
routing filter add chain=NPCI-IPv4 prefix=103.14.160.0/22 prefix-length=22-24 action=accept
routing filter add chain=NPCI-IPv4 action=reject
routing filter add chain=NPCI-IPv6 prefix=2001:df0:2f0::/46 prefix-length=46-48 action=accept
routing filter add chain=NPCI-IPv6 action=reject
***End of Mikrotik routeros config***
anurag@tools:~/irrpt$

Thinking to automate? ** The config between start and end can be pasted directly in CLI with Mikrotik. I would not recommend using it for manual filtering of any larger network. Automated filtering where filters are generated regularly makes sense but manual filtering without automation can be damaging. One can use a script like this for connecting to smaller networks. Also, IRRPR offers diff management via CVS (I hope they come up with git on that part) and it comes with an option to trigger email update so Network admins can know when to manually update. I would prefer that for non-commit based platforms since with Cisco ios or Mikrotik routeros it can be tricky to auto update prefix list. If one does no ip prefix list before triggering update it will cause a major noticeable impact. So ideal way to manage that on non-commit based devices would be to maintain a list of prefixes separately in the plain text file or a database and diff it against old one & only push for changes. Do-able and should be preferred that way instead of deleting and re-adding the whole list while automating.

Time to get back to work! 😄