207 lines
4.5 KiB
Bash
Executable file
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
|