Last active
May 7, 2022 09:08
-
-
Save borouhin/880a38d055a53024cd47ecae68f6f9f5 to your computer and use it in GitHub Desktop.
Make Bird 2 config for serving RKN blocked routes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Requires libnet-cidr-lite-perl installed | |
# Best practices | |
set -Eeuo pipefail | |
# Local WAN Interface (using interface, not IP, so that we need not change the script on WAN IP changes) | |
WAN_IFACE='eth0' | |
# Local AS | |
LOCAL_AS='64999' | |
# Peers receiving full non-summarized prefix list. Space delimited, in 'IP/AS' format | |
PEERS_32='XX.XX.XX.XX/65000' | |
# Peers receiving prefix list summarized to /24 subnets. Space delimited, in 'IP/AS' format | |
PEERS_24='XX.XX.XX.XX/65000' | |
# URLs to download prefix lists from, space delimited. Should contain one 'IP/MASK' entry for each line ('/32' for single IPs is optional) | |
LIST_URLS='https://antifilter.download/list/ip.lst https://antifilter.download/list/ipresolve.lst https://antifilter.download/list/subnet.lst' | |
# Individual items to add to prefix lists. Can be single IPv4 IPs, IPv4 subnets in 'IP/MASK' format, autonomous systems ('ASXXX') or FQDNs | |
MANUAL_ITEMS='dav.mailbox.org login.mailbox.org help.mailbox.org rutracker.org AS32934 AS13414' | |
# Temporary file path (deleted after each run). Make sure the path is writable | |
TMP_FILE='/tmp/routes.lst' | |
# BIRD configuration file path | |
CONF_FILE='/etc/bird/bird.conf' | |
# birdc executable | |
BIRDC='/usr/sbin/birdc' | |
# Getting local WAN IPv4 address | |
IP_ADDRESS=`ip address show dev $WAN_IFACE | grep 'inet ' | sed 's/\s*inet \([0-9.]*\)\/.*/\1/'` | |
if [[ ! $IP_ADDRESS =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]] ; then | |
>&2 echo "Error getting IPv4 address of interface $WAN_IFACE" | |
exit 1 | |
fi | |
# Downloading lists from URLs | |
if [[ -e $TMP_FILE ]] ; then | |
rm $TMP_FILE | |
fi | |
IFS=' ' | |
# Curl sends diagnostic data to stderr, so to use this script in crontab, we need extra options and temporary files | |
INDEX=1 | |
for url in $LIST_URLS ; do | |
curl -s -S -L $url -o $TMP_FILE.$INDEX | |
if [ $? != '0' ] ; then | |
>&2 echo "Error retrieving IP list $url" | |
exit 2 | |
fi | |
# For single IPs - add /32 mask | |
cat $TMP_FILE.$INDEX | sed 's/\(^[^/]*$\)/\1\/32/' >>$TMP_FILE | |
rm $TMP_FILE.$INDEX | |
INDEX=$((INDEX+1)) | |
done | |
# Adding manual items. Errors should (hopefully) be dismissed silently | |
IFS=' ' | |
for item in $MANUAL_ITEMS ; do | |
# Subnets, adding as is | |
if [[ $item =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,3}$ ]] ; then | |
echo "$item" >>$TMP_FILE | |
# Single IPs, adding with '/32' mask | |
elif [[ $item =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] ; then | |
echo "$item/32" >>$TMP_FILE | |
# Autonomous systems, add all address ranges within | |
elif [[ $item =~ ^AS[0-9]{1,5}$ ]] ; then | |
whois -h whois.radb.net -- "-i origin $item" | grep 'route:' | awk '{print $2;}' >>$TMP_FILE | |
# Hostnames, resolving A DNS records and adding a single IP for each | |
else | |
RESOLVED_LINES=`host -4 -t A $item` | |
if [ $? == '0' ] ; then | |
IFS=$'\n' | |
for line in $RESOLVED_LINES ; do | |
RESOLVED_IP=`echo $line | sed 's/^[^0-9]*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)/\1/;t;d'` | |
if [[ $RESOLVED_IP != "" ]] ; then | |
echo "$RESOLVED_IP/32" >>$TMP_FILE | |
fi | |
done | |
fi | |
fi | |
done | |
# Summarizing IPs using Perl Net::CIDR::Lite module (lightning fast) | |
# | |
# For full prefix list - just compact it summarizing overlapping or adjacent prefixes, no extra IPs added | |
cat $TMP_FILE | perl -MNet::CIDR::Lite -E 'my $cidr=Net::CIDR::Lite->new; foreach $line(<>) { $cidr->add($line); } foreach my $item($cidr->list) { print "$item\n"; }' >$TMP_FILE.sum32 | |
ERROR_1=$? | |
# For summarized prefix list - first broaden all masks to at least /24, then process the same way | |
cat $TMP_FILE | sed 's/\(.*\/\)3[0-2]$/\124/' | sed 's/\(.*\/\)2[5-9]$/\124/' >$TMP_FILE.raw24 | |
ERROR_2=$? | |
cat $TMP_FILE.raw24 | perl -MNet::CIDR::Lite -E 'my $cidr=Net::CIDR::Lite->new; foreach $line(<>) { $cidr->add($line); } foreach my $item($cidr->list) { print "$item\n"; }' >$TMP_FILE.sum24 | |
ERROR_3=$? | |
rm $TMP_FILE.raw24 | |
rm $TMP_FILE | |
if [[ ($ERROR_1 != '0') || ($ERROR_2 != '0') || ($ERROR_3 != '0') || (! -e $TMP_FILE.sum32) || (! -e $TMP_FILE.sum24) ]] ; then | |
>&2 echo "Error summarizing IPs ($ERROR_1 $ERROR_2 $ERROR_3)" | |
rm $TMP_FILE.sum32 2>/dev/null | |
rm $TMP_FILE.sum24 2>/dev/null | |
exit 3 | |
fi | |
# Config file header | |
cat > $CONF_FILE.new <<- EOM | |
log syslog all; | |
router id $IP_ADDRESS; | |
protocol device { | |
scan time 10; | |
} | |
protocol kernel { | |
ipv4 { | |
export where proto = "static_bgp_32"; | |
import none; | |
}; | |
persist; | |
learn; | |
} | |
protocol static static_bgp_32 { | |
ipv4; | |
EOM | |
# Filling full prefix list | |
IFS=$'\n' | |
for line in `cat $TMP_FILE.sum32` ; do | |
echo " route $line blackhole;" >>$CONF_FILE.new | |
done | |
rm $TMP_FILE.sum32 | |
cat >> $CONF_FILE.new <<- EOM | |
} | |
protocol static static_bgp_24 { | |
ipv4; | |
EOM | |
# Filling summarized prefix list | |
IFS=$'\n' | |
for line in `cat $TMP_FILE.sum24` ; do | |
echo " route $line blackhole;" >>$CONF_FILE.new | |
done | |
rm $TMP_FILE.sum24 | |
# Peer definition templates | |
cat >> $CONF_FILE.new <<- EOM | |
} | |
template bgp PEER { | |
local as $LOCAL_AS; | |
multihop 255; | |
hold time 240; | |
keepalive time 30; | |
rs client; | |
} | |
template bgp PEER_32 from PEER { | |
ipv4 { | |
import none; | |
export where proto = "static_bgp_32"; | |
}; | |
} | |
template bgp PEER_24 from PEER { | |
ipv4 { | |
import none; | |
export where proto = "static_bgp_24"; | |
}; | |
} | |
EOM | |
# Peers receiving full list | |
IFS=' ' | |
for peer in $PEERS_32; do | |
cat >> $CONF_FILE.new <<- EOM | |
protocol bgp from PEER_32 { | |
neighbor `echo $peer | awk -F'/' '{print $1" as "$2";";}'` | |
} | |
EOM | |
done | |
# Peers receiving summarized list | |
IFS=' ' | |
for peer in $PEERS_24; do | |
cat >> $CONF_FILE.new <<- EOM | |
protocol bgp from PEER_24 { | |
neighbor `echo $peer | awk -F'/' '{print $1" as "$2";";}'` | |
} | |
EOM | |
done | |
# Reconfiguring BIRD. Reverting to previous config on error | |
cp $CONF_FILE $CONF_FILE.old | |
mv $CONF_FILE.new $CONF_FILE | |
$BIRDC configure | |
if [ $? != '0' ] ; then | |
>&2 echo "Error reconfiguring BIRD. Reverting to old config" | |
mv $CONF_FILE.old $CONF_FILE | |
$BIRDC configure | |
exit 4 | |
else | |
rm $CONF_FILE.old | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment