bird/bin/irr

207 lines
4.5 KiB
Bash
Executable file

#!/usr/bin/env zsh
local bird_home=${BIRD_HOME:-"/etc/bird"}
local irr_home=${IRR_HOME:-"$bird_home/irr"}
function grep_asns {
command grep -Prohiz 'neighbor\s+\S+\s+as \K([0-9]+|ASN_[A-Z0-9]+)' "$bird_home/peers" \
| tr '\0' ' '
}
function lookup_asn {
if [[ $1 =~ ^[0-9]+$ ]]; then
echo $1
else
command grep -Prohi \
'define\s+'"$1"'\s+=\s+\K[0-9]+' "$bird_home/peers"
fi
}
local -aU as_nums
function find_asns {
local asns=$(grep_asns)
for asn in ${=asns}; do
as_nums+=("$(lookup_asn $asn)")
done
}
find_asns
local _as_set_names=$(command grep -irEoh "as-[a-z0-9-]+|as[0-9]+(:as-[a-z0-9-]+)+" "$bird_home/peers" \
| sort | uniq \
| tr '\n' ' ')
local -a as_set_names; as_set_names=(${=_as_set_names})
# AS-SET -> ASN
function grep_asns_by {
command grep -Prohiz -m 1 \
'(?s)protocol bgp \N+{\n\N*#\s*'"$1"'\s*\n\N*neighbor\s+\S+\s+as \K([0-9]+|ASN_[A-Z0-9]+)' "$bird_home/peers" \
| tr '\0' ' '
}
# AS-SET -> ASN
function find_asn_by {
local asn=$(grep_asns_by "$1" | cut -d' ' -f1)
lookup_asn $asn
}
# AS-SET -> proto
function grep_protos_by {
command grep -Prohiz -m 1 \
'(?s)protocol bgp \S+ from \K\S+(?=\N*{\n\N*#\s*'"$1"'\s*\n)' "$bird_home/peers" \
| tr '\0' ' '
}
function recurse_proto {
local proto="$1"
local count=${2:-"0"}
if [[ $proto =~ ^peer[46]$ ]]; then
echo "$proto"
return 0
fi
# recursion limit
if (( count > 5 )); then return 1; fi
((count++))
recurse_proto $(command grep -Prohi -m 1 'template\s+bgp\s+'"$1"'\s+from\s+\K\S+' /etc/bird) $count
}
# AS-SET -> addr family
function find_versions {
local protos=$(grep_protos_by "$1")
local -aU versions
for proto in ${=protos}; do
local root_proto=$(recurse_proto "$proto")
versions+=("${root_proto#peer}")
if (( ${#versions} >= 2 )); then break; fi
done
echo $versions
}
local -aU unknown
function grep_unknown {
local asns=$(grep_asns_by 'irr:unknown')
for asn in ${=asns}; do
unknown+=("$(lookup_asn $asn)")
done
}
function resolve_invalid {
if (($unknown[(Ie)$1])); then
echo IRR_UNKNOWN
else
echo IRR_INVALID
fi
}
local -A as_sets
for as_set in $as_set_names; do
local asn=$(find_asn_by $as_set)
local versions=$(find_versions $as_set)
for version in ${=versions}; do
echo "resolved as$asn [v$version] -> $as_set"
as_sets[as${asn}_$version]="$as_set"
done
done
mkdir -p "$irr_home"
touch "$irr_home"/{ip4,ip6,asn4,asn6,const,filter}.conf
truncate -s0 "$irr_home"/{ip4,ip6,asn4,asn6,const,filter}.conf
function filter { echo "$@" >> "$irr_home/filter.conf"; }
function get_target {
local asn=$1
local version=$2
local target="${as_sets[as${asn}_$version]}"
if [[ -z "$target" ]]; then
echo as$asn
else
echo "$target"
fi
}
local bgpq4_sources="RIPE,ARIN,APNIC,AFRINIC,LACNIC,RADB"
function irr_asn {
local asn="$1"
local version="$2"
local target=$(get_target $asn $version)
local label="IRR_${asn}_ASN$version"
local entry=$(bgpq4 -S "$bgpq4_sources" -b "$target" -l "define $label" -t)
echo "$entry" >> "$irr_home/asn$version.conf"
filter " if bgp_path.last_nonaggregated !~ $label"
filter " then return $(resolve_invalid $asn);"
}
local -A maxlens
maxlens[4]=24
maxlens[6]=48
function irr_ip {
local asn="$1"
local version="$2"
local target=$(get_target $asn $version)
local label="IRR_${asn}_IP$version"
local maxlen=$maxlens[$version]
local entry=$(bgpq4 -S "$bgpq4_sources" -b "$target" -l "define $label" -"$version" -R $maxlen -m $maxlen)
if [[ -z "$entry" ]]; then
filter " return IRR_UNKNOWN;"
else
echo "$entry" >> "$irr_home/ip$version.conf"
filter " if net ~ $label"
filter " then return IRR_VALID;"
filter " else return $(resolve_invalid $asn);"
fi
}
grep_unknown
echo "unknown: $unknown"
cat >> "$irr_home/const.conf" << EOF
define IRR_VALID = 0;
define IRR_INVALID = 1;
define IRR_UNKNOWN = 2;
EOF
cat >> "$irr_home/filter.conf" << EOF
include "const.conf";
include "asn4.conf";
include "asn6.conf";
include "ip4.conf";
include "ip6.conf";
function irr_status(int dst_asn) -> int
{
case dst_asn {
EOF
for asn in $as_nums; do
echo "generating filter for as$asn"
filter " ${asn}:"
filter " case net.type {"
filter " NET_IP4: {"
irr_asn $asn 4
irr_ip $asn 4
filter " }"
filter " NET_IP6: {"
irr_asn $asn 6
irr_ip $asn 6
filter " }"
filter " }"
done
cat >> "$irr_home/filter.conf" << EOF
else:
return IRR_UNKNOWN;
}
}
EOF