#!/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"