0070ef25c4
Signed-off-by: Alarig Le Lay <alelay@scaleway.com>
216 lines
6.2 KiB
Bash
Executable file
216 lines
6.2 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
set -e
|
|
|
|
# for iconv below
|
|
export LC_ALL=en_US.utf8
|
|
|
|
# 1st argument must be an ASN registered to peeringdb
|
|
# 2nd argument must be the IPv4 peering address
|
|
# 3rd argument must be the IPv6 peering address
|
|
|
|
if [ ! -f /usr/local/etc/bird-peers-update.conf ]; then
|
|
printf "Write /usr/local/etc/bird-peers-update.conf with at least "
|
|
printf "PDB_API_KEY, IXP_ASN and BIRD_CONF_PATH vars\n"
|
|
exit 1
|
|
else
|
|
. /usr/local/etc/bird-peers-update.conf
|
|
fi
|
|
|
|
PEER_AS=$1
|
|
IPv4=$2
|
|
IPv6=$3
|
|
|
|
if [ -z "${PEER_AS}" -o -z "${IPv4}" -o -z "${IPv6}" ]; then
|
|
echo "1st argument must be an ASN registered to peeringdb"
|
|
echo "2nd argument must be the IPv4 peering address"
|
|
echo "3rd argument must be the IPv6 peering address"
|
|
exit 1
|
|
fi
|
|
|
|
CACHE_DIR=/var/local/cache/peeringdb
|
|
|
|
if [ ! -d "${CACHE_DIR}" ]; then
|
|
mkdir -p "${CACHE_DIR}"
|
|
fi
|
|
|
|
# re-fetch data if it's too old
|
|
if [ -z "$(find ${CACHE_DIR} -mmin -720 -name ${PEER_AS}.json)" ]; then
|
|
curl -s -H 'Authorization: Api-Key '"${PDB_API_KEY}" \
|
|
-X GET "https://www.peeringdb.com/api/net?asn=${PEER_AS}" \
|
|
> "${CACHE_DIR}/${PEER_AS}.json"
|
|
fi
|
|
|
|
# test if the data is valid, -e will exit the script
|
|
jq -r '.data[] | .irr_as_set' "${CACHE_DIR}/${PEER_AS}.json" 1>/dev/null
|
|
|
|
IRRASSET=$(jq -r '.data[] | .irr_as_set' "${CACHE_DIR}/${PEER_AS}.json")
|
|
MAXPREF4=$(jq -r '.data[] | .info_prefixes4' "${CACHE_DIR}/${PEER_AS}.json")
|
|
MAXPREF6=$(jq -r '.data[] | .info_prefixes6' "${CACHE_DIR}/${PEER_AS}.json")
|
|
AS_NAME=$(jq -r '.data[] | .name' "${CACHE_DIR}/${PEER_AS}.json")
|
|
|
|
if [ -z "${IRRASSET}" ]; then
|
|
IRRASSET="AS${PEER_AS}"
|
|
fi
|
|
|
|
# Remove diacritic first as potential question marks will remove afterward
|
|
AS_NAME="$(echo ${AS_NAME} | iconv -f utf-8 -t ascii//TRANSLIT)"
|
|
AS_NAME="$(echo ${AS_NAME} | tr '[:punct:]' '_')"
|
|
AS_NAME="$(echo ${AS_NAME} | tr '[:space:]' '_')"
|
|
AS_NAME="$(echo ${AS_NAME} | tr '[:lower:]' '[:upper:]')"
|
|
AS_NAME="$(echo ${AS_NAME} | sed -E 's/^_+//;s/_+$//;s/_+/_/g')"
|
|
|
|
IPv4_PFL="$(bgpq4 -4 -b -A -l AS${PEER_AS}_v4 -R 24 ${IRRASSET})"
|
|
IPv6_PFL="$(bgpq4 -6 -b -A -l AS${PEER_AS}_v6 -R 48 ${IRRASSET})"
|
|
|
|
if [ -z "${MAXPREF4}" ] || [ ${MAXPREF4} -eq 0 ]; then
|
|
MAXPREF4=$(echo "${IPv4_PFL}" | wc -l)
|
|
fi
|
|
if [ "${MAXPREF4}" -lt 10 ]; then
|
|
MAXPREF4=10
|
|
fi
|
|
if [ -z "${MAXPREF6}" ] || [ ${MAXPREF6} -eq 0 ]; then
|
|
MAXPREF6=$(echo "${IPv6_PFL}" | wc -l)
|
|
fi
|
|
if [ "${MAXPREF6}" -lt 10 ]; then
|
|
MAXPREF6=10
|
|
fi
|
|
|
|
# do we really trust peeringdb? we may want to limit maxpref
|
|
|
|
mkdir -p "${BIRD_CONF_PATH}"/functions
|
|
|
|
# AS16 - AS32 from whois AS47214
|
|
if [ "${PEER_AS}" -gt 65535 ]; then
|
|
# la t'es bien
|
|
eval $(whois AS47214 | awk '/AS32 to AS16/ { print "AS"$5"="$7";" }' | sed -E 's/AS([0-9]+)/\1/g')
|
|
eval COMMU_PEER_AS=\$AS${PEER_AS}
|
|
else
|
|
COMMU_PEER_AS=${PEER_AS}
|
|
fi
|
|
|
|
echo "# generated by $0 $@
|
|
function check_import_${PEER_AS}_ipv4(int peeras; ip nexthop)
|
|
prefix set AS${PEER_AS}_v4;
|
|
{
|
|
${IPv4_PFL}
|
|
|
|
# check if the announced prefix is in the bgpq set
|
|
if net !~ AS${PEER_AS}_v4 then return false;
|
|
|
|
# reject the route if the first as is not the peer
|
|
# or if the nexthop is not the peer as well
|
|
# we also check the rpki status there
|
|
return check_ipv4(peeras, nexthop);
|
|
}
|
|
|
|
filter bgp_filters_${PEER_AS}_out {
|
|
if ! (source = RTS_BGP) then reject;
|
|
if (${IXP_ASN},${COMMU_PEER_AS}) ~ bgp_community then accept;
|
|
if (0,${COMMU_PEER_AS}) ~ bgp_community then reject;
|
|
if (0,${IXP_ASN}) ~ bgp_community then reject;
|
|
if (${IXP_ASN},${IXP_ASN}) ~ bgp_community then accept;
|
|
|
|
else accept;
|
|
}
|
|
" > "${BIRD_CONF_PATH}/functions/${PEER_AS}_v4.conf"
|
|
|
|
mkdir -p "${BIRD_CONF_PATH}"/peers
|
|
|
|
# bird does not support dots in the filters name, it must be dashes
|
|
DASH_IPv4="$(echo ${IPv4} | tr '.' '_')"
|
|
|
|
if [ -f "/usr/local/etc/bird-override/bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv4}.conf" ]; then
|
|
BIRD_OVERRIDE_AFI_V4="include \"/usr/local/etc/bird-override/bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv4}.conf\";"
|
|
else
|
|
BIRD_OVERRIDE_AFI_V4=""
|
|
fi
|
|
|
|
echo "# generated by $0 $@
|
|
filter bgp_filters_${DASH_IPv4}_in_ipv4 {
|
|
if (check_import_${PEER_AS}_ipv4(${PEER_AS}, ${IPv4})) then {
|
|
# Here we can set localpref or remove a prefix, for example
|
|
accept;
|
|
}
|
|
else {
|
|
reject \"Prefix \", net, \" filtered IN from ${IPv4}\";
|
|
}
|
|
}
|
|
|
|
protocol bgp bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv4} from PEERS_IPv4 {
|
|
description \"${AS_NAME} ${IRRASSET}\";
|
|
neighbor ${IPv4} as ${PEER_AS};
|
|
${BIRD_OVERRIDE_AFI_V4}
|
|
|
|
ipv4 {
|
|
receive limit ${MAXPREF4} action restart;
|
|
import limit ${MAXPREF4} action disable;
|
|
import filter bgp_filters_${DASH_IPv4}_in_ipv4;
|
|
export filter bgp_filters_${PEER_AS}_out;
|
|
};
|
|
}
|
|
" > "${BIRD_CONF_PATH}/peers/${PEER_AS}_${IPv4}.conf"
|
|
|
|
echo "# generated by $0 $@
|
|
function check_import_${PEER_AS}_ipv6(int peeras; ip nexthop)
|
|
prefix set AS${PEER_AS}_v6;
|
|
{
|
|
${IPv6_PFL}
|
|
|
|
# check if the announced prefix is in the bgpq set
|
|
if net !~ AS${PEER_AS}_v6 then return false;
|
|
|
|
# reject the route if the first as is not the peer
|
|
# or if the nexthop is not the peer as well
|
|
# we also check the rpki status there
|
|
return check_ipv6(peeras, nexthop);
|
|
}
|
|
" > "${BIRD_CONF_PATH}/functions/${PEER_AS}_v6.conf"
|
|
|
|
# bird does not support semicollons in the filters name, it must be dashes
|
|
DASH_IPv6="$(echo ${IPv6} | tr ':' '_')"
|
|
|
|
if [ -f "/usr/local/etc/bird-override/bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv6}.conf" ]; then
|
|
BIRD_OVERRIDE_AFI_V6="include \"/usr/local/etc/bird-override/bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv6}.conf\";"
|
|
else
|
|
BIRD_OVERRIDE_AFI_V6=""
|
|
fi
|
|
|
|
echo "# generated by $0 $@
|
|
filter bgp_filters_${DASH_IPv6}_in_ipv6 {
|
|
if (check_import_${PEER_AS}_ipv6(${PEER_AS}, ${IPv6})) then {
|
|
# Here we can set localpref or remove a prefix, for example
|
|
accept;
|
|
}
|
|
else {
|
|
reject \"Prefix \", net, \" filtered IN from ${IPv6}\";
|
|
}
|
|
}
|
|
|
|
protocol bgp bgp_${PEER_AS}_${AS_NAME}_${DASH_IPv6} from PEERS_IPv6 {
|
|
description \"${AS_NAME} ${IRRASSET}\";
|
|
neighbor ${IPv6} as ${PEER_AS};
|
|
${BIRD_OVERRIDE_AFI_V6}
|
|
|
|
ipv6 {
|
|
receive limit ${MAXPREF6} action restart;
|
|
import limit ${MAXPREF6} action disable;
|
|
import filter bgp_filters_${DASH_IPv6}_in_ipv6;
|
|
export filter bgp_filters_${PEER_AS}_out;
|
|
};
|
|
}
|
|
" > "${BIRD_CONF_PATH}/peers/${PEER_AS}_${IPv6}.conf"
|
|
|
|
echo "# generated by $0 $@
|
|
function check_import_${PEER_AS}_ipv6(int peeras; ip nexthop)
|
|
prefix set AS${PEER_AS}_v6;
|
|
{
|
|
${IPv6_PFL}
|
|
|
|
if net !~ AS${PEER_AS}_v6 then return false;
|
|
|
|
return check_ipv6(peeras, nexthop);
|
|
}
|
|
" > "${BIRD_CONF_PATH}/functions/${PEER_AS}_v6.conf"
|
|
|