From ba24ce21db39f898c80863e6afd9179f67280932 Mon Sep 17 00:00:00 2001 From: Blackwhitebear8 Date: Fri, 28 Nov 2025 14:16:18 +0100 Subject: [PATCH] Update pgen.sh --- gen.sh | 207 --------------------------------------- pgen.sh | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+), 207 deletions(-) delete mode 100644 gen.sh create mode 100644 pgen.sh diff --git a/gen.sh b/gen.sh deleted file mode 100644 index 50b0d2e..0000000 --- a/gen.sh +++ /dev/null @@ -1,207 +0,0 @@ -#!/bin/bash -# -# IRR filter updater for the VyOS API -# - -VYOS_HOST="https://api-url" -API_KEY="api-key" -ASN_FILE="/opt/irr-update/asns.txt" -LOG_FILE="/opt/irr-update/irr_updater.log" - -log() { - local message="$1" - echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" | tee -a "$LOG_FILE" -} - -log "==========================================================" -log "Starting IRR filter update process." -log "==========================================================" - -# fetching entries -declare -a current_entries -while read -r entry; do - if [[ ! "$entry" =~ ^# ]] && [[ -n "$entry" ]]; then - current_entries+=("$entry") - fi -done < "$ASN_FILE" - -# ----------------------------------- -# Removing orphaned prefix-lists -# ----------------------------------- -log "Checking for orphaned prefix-lists..." -has_orphaned_lists=false -commands_list_orphans="" - -# get iPv4 lists -ipv4_lists_json=$(curl -s -k --location --request POST "${VYOS_HOST}/retrieve" \ - --form data='{"op":"showConfig","path":["policy","prefix-list"]}' \ - --form key="${API_KEY}" --max-time 300) -ipv4_lists=$(echo "$ipv4_lists_json" | grep -o '"AS[0-9]*V4":' | sed 's/"://;s/"//g') - -for list_name in $ipv4_lists; do - original_asn=$(echo "$list_name" | sed 's/V4$//;s/^AS//') - is_orphaned=true - for entry in "${current_entries[@]}"; do - main_asn=$(echo "$entry" | cut -d':' -f1) - [[ "$main_asn" == "$original_asn" ]] && is_orphaned=false - done - if [ "$is_orphaned" = true ]; then - log "Found orphaned IPv4 prefix-list: $list_name. Adding delete command..." - commands_list_orphans+='{"op":"delete","path":["policy","prefix-list","'"$list_name"'"]},' - has_orphaned_lists=true - fi -done - -# Get iPv6 lists -ipv6_lists_json=$(curl -s -k --location --request POST "${VYOS_HOST}/retrieve" \ - --form data='{"op":"showConfig","path":["policy","prefix-list6"]}' \ - --form key="${API_KEY}" --max-time 300) -ipv6_lists=$(echo "$ipv6_lists_json" | grep -o '"AS[0-9]*V6":' | sed 's/"://;s/"//g') - -for list_name in $ipv6_lists; do - original_asn=$(echo "$list_name" | sed 's/V6$//;s/^AS//') - is_orphaned=true - for entry in "${current_entries[@]}"; do - main_asn=$(echo "$entry" | cut -d':' -f1) - [[ "$main_asn" == "$original_asn" ]] && is_orphaned=false - done - if [ "$is_orphaned" = true ]; then - log "Found orphaned IPv6 prefix-list: $list_name. Adding delete command..." - commands_list_orphans+='{"op":"delete","path":["policy","prefix-list6","'"$list_name"'"]},' - has_orphaned_lists=true - fi -done - -if [ "$has_orphaned_lists" = true ]; then - commands_list_orphans="[${commands_list_orphans::-1}]" - log "Sending delete commands for orphaned lists..." - api_response=$(curl -s -k --location --request POST "${VYOS_HOST}/configure" \ - --form data="${commands_list_orphans}" \ - --form key="${API_KEY}" --max-time 300) - echo "$api_response" | grep -q '"success":true' \ - && log "Deletion successful." \ - || log "Deletion failed. API response: $api_response" -else - log "No orphaned prefix-lists found." -fi - -# ----------------------------------- -# Retrieve prefixes for each entry and execute 'set' and 'delete' -# ----------------------------------- -for entry in "${current_entries[@]}"; do - log "--------------------------------------------------------" - log "Processing entry: $entry" - - declare -a ipv4_prefixes_to_add=() - declare -a ipv6_prefixes_to_add=() - declare -A seen_v4=() - declare -A seen_v6=() - ipv4_rules=10 - ipv6_rules=10 - - main_asn=$(echo "$entry" | cut -d':' -f1) - as_set=$(echo "$entry" | cut -s -d':' -f2-) - - declare -a asns_to_query=() - asns_to_query+=("AS${main_asn}") - if [ -n "$as_set" ]; then - log "Resolving members of AS-Set: $as_set" - resolved_asns=$(bgpq4 -j -t "$as_set" 2>/dev/null | jq -r '.[][]' | sed 's/^/AS/' | sort -u) - for resolved_asn in $resolved_asns; do - asns_to_query+=("$resolved_asn") - done - log "Resolved ASNs: ${asns_to_query[*]}" - fi - - # Make the list unique - asns_to_query=($(echo "${asns_to_query[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) - log "Unique ASNs to query: ${asns_to_query[*]}" - - # Combine ipv4 and ipv6 in one go - for asn_to_query in "${asns_to_query[@]}"; do - log "Fetching prefixes for $asn_to_query..." - - # Retrieve IPv6 for this ASN - bgpq4_output_ipv6_raw=$(bgpq4 -6 -A "$asn_to_query" 2>&1) - if ! echo "$bgpq4_output_ipv6_raw" | grep -q "FATAL ERROR"; then - for prefix_with_length in $(echo "$bgpq4_output_ipv6_raw" | grep -oE '[0-9a-fA-F:]+/[0-9]+'); do - [[ "$prefix_with_length" == "::/0" ]] && continue - [[ -z "${seen_v6[$prefix_with_length]}" ]] && seen_v6[$prefix_with_length]=1 && ipv6_prefixes_to_add+=("$prefix_with_length") - done - fi - - # Retrieve IPv4 for this ASN - bgpq4_output_ipv4_raw=$(bgpq4 -4 -A "$asn_to_query" 2>&1) - if ! echo "$bgpq4_output_ipv4_raw" | grep -q "FATAL ERROR"; then - for prefix_with_length in $(echo "$bgpq4_output_ipv4_raw" | grep -oE '[0-9.]+/[0-9]+'); do - [[ "$prefix_with_length" == "0.0.0.0/0" ]] && continue - [[ -z "${seen_v4[$prefix_with_length]}" ]] && seen_v4[$prefix_with_length]=1 && ipv4_prefixes_to_add+=("$prefix_with_length") - done - fi - done - - # ----------------------------------- - # Retrieve current rules and determine rules to be removed - # ----------------------------------- - commands_list_atomic="" - prefix_list_name_ipv6="AS${main_asn}V6" - prefix_list_name_ipv4="AS${main_asn}V4" - local_has_changes=false - - # First, add the delete commands for the entire prefix list. - commands_list_atomic+='{"op":"delete","path":["policy","prefix-list","'"$prefix_list_name_ipv4"'"]},' - commands_list_atomic+='{"op":"delete","path":["policy","prefix-list6","'"$prefix_list_name_ipv6"'"]},' - local_has_changes=true - - # Then add the new IPv4 rules - for prefix_with_length in "${ipv4_prefixes_to_add[@]}"; do - log "Adding IPv4 rule ${ipv4_rules} for ${prefix_with_length}..." - prefix_len="${prefix_with_length#*/}" - commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$prefix_list_name_ipv4"'","rule","'$ipv4_rules'","action","permit"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$prefix_list_name_ipv4"'","rule","'$ipv4_rules'","prefix","'$prefix_with_length'"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$prefix_list_name_ipv4"'","rule","'$ipv4_rules'","ge","'$prefix_len'"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$prefix_list_name_ipv4"'","rule","'$ipv4_rules'","le","24"]},' - ipv4_rules=$((ipv4_rules+10)) - done - - # Then add the new IPv6 rules - for prefix_with_length in "${ipv6_prefixes_to_add[@]}"; do - log "Adding IPv6 rule ${ipv6_rules} for ${prefix_with_length}..." - prefix_len="${prefix_with_length#*/}" - commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$prefix_list_name_ipv6"'","rule","'$ipv6_rules'","action","permit"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$prefix_list_name_ipv6"'","rule","'$ipv6_rules'","prefix","'$prefix_with_length'"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$prefix_list_name_ipv6"'","rule","'$ipv6_rules'","ge","'$prefix_len'"]},' - commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$prefix_list_name_ipv6"'","rule","'$ipv6_rules'","le","48"]},' - ipv6_rules=$((ipv6_rules+10)) - done - - if [ "$local_has_changes" = true ]; then - commands_list_atomic="[${commands_list_atomic::-1}]" - log "Sending new rules for $entry..." - api_response=$(curl -s -k --location --request POST "${VYOS_HOST}/configure" \ - --form data="${commands_list_atomic}" \ - --form key="${API_KEY}" --max-time 300) - if echo "$api_response" | grep -q '"success": true'; then - log "Update successful for $entry." - else - echo "$commands_list_atomic" > "/tmp/failed-${entry}-payload.json" - log "Update failed for $entry. Payload saved to /tmp/failed-${entry}-payload.json" - fi - else - log "No new prefixes or changes found for $entry." - fi -done - -# Save the config -log "--------------------------------------------------------" -log "Saving configuration..." -api_response=$(curl -s -k --location --request POST "${VYOS_HOST}/config-file" \ - --form data='{"op":"save"}' \ - --form key="${API_KEY}" --max-time 300) -echo "$api_response" | grep -q '"success": true' \ - && log "Configuration saved successfully." \ - || log "Failed to save configuration. API response: $api_response" - -log "==========================================================" -log "IRR filter update process finished." -log "==========================================================" \ No newline at end of file diff --git a/pgen.sh b/pgen.sh new file mode 100644 index 0000000..9651b85 --- /dev/null +++ b/pgen.sh @@ -0,0 +1,296 @@ +#!/bin/bash + +VYOS_HOST="https://vyos-url" +API_KEY="api-key" +ASN_FILE="/opt/irr-update/asns.txt" +LOG_FILE="/opt/irr-update/irr_updater.log" +PEERINGDB_API_KEY="api-key" + +log() { + local message="$1" + echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" | tee -a "$LOG_FILE" +} + +log "==========================================================" +log "Starting IRR filter update process." +log "==========================================================" + +declare -a current_entries +while read -r entry; do + if [[ ! "$entry" =~ ^# ]] && [[ -n "$entry" ]]; then + current_entries+=("$entry") + fi +done < "$ASN_FILE" + +log "--- [PART 1] Processing IRR Prefix-Lists ---" + +log "Checking for orphaned prefix-lists..." +has_orphaned_lists=false +commands_list_orphans="" + +ipv4_lists_json=$(curl -s -k --location --request POST "${VYOS_HOST}/retrieve" \ + --form data='{"op":"showConfig","path":["policy","prefix-list"]}' \ + --form key="${API_KEY}" --max-time 300) +ipv4_lists=$(echo "$ipv4_lists_json" | grep -o '"AS[0-9]*V4":' | sed 's/"://;s/"//g') + +for list_name in $ipv4_lists; do + original_asn=$(echo "$list_name" | sed 's/V4$//;s/^AS//') + is_orphaned=true + for entry in "${current_entries[@]}"; do + main_asn=$(echo "$entry" | cut -d':' -f1) + [[ "$main_asn" == "$original_asn" ]] && is_orphaned=false + done + if [ "$is_orphaned" = true ]; then + log "Found orphaned IPv4 prefix-list: $list_name. Adding delete command..." + commands_list_orphans+='{"op":"delete","path":["policy","prefix-list","'"$list_name"'"]},' + has_orphaned_lists=true + fi +done + +ipv6_lists_json=$(curl -s -k --location --request POST "${VYOS_HOST}/retrieve" \ + --form data='{"op":"showConfig","path":["policy","prefix-list6"]}' \ + --form key="${API_KEY}" --max-time 300) +ipv6_lists=$(echo "$ipv6_lists_json" | grep -o '"AS[0-9]*V6":' | sed 's/"://;s/"//g') + +for list_name in $ipv6_lists; do + original_asn=$(echo "$list_name" | sed 's/V6$//;s/^AS//') + is_orphaned=true + for entry in "${current_entries[@]}"; do + main_asn=$(echo "$entry" | cut -d':' -f1) + [[ "$main_asn" == "$original_asn" ]] && is_orphaned=false + done + if [ "$is_orphaned" = true ]; then + log "Found orphaned IPv6 prefix-list: $list_name. Adding delete command..." + commands_list_orphans+='{"op":"delete","path":["policy","prefix-list6","'"$list_name"'"]},' + has_orphaned_lists=true + fi +done + +if [ "$has_orphaned_lists" = true ]; then + commands_list_orphans="[${commands_list_orphans::-1}]" + curl -s -k --location --request POST "${VYOS_HOST}/configure" \ + --form data="${commands_list_orphans}" --form key="${API_KEY}" --max-time 300 > /dev/null + log "Orphans deleted." +else + log "No orphaned prefix-lists found." +fi + +for entry in "${current_entries[@]}"; do + log "--------------------------------------------------------" + log "Processing entry: $entry" + + main_asn=$(echo "$entry" | cut -d':' -f1) + as_set=$(echo "$entry" | cut -s -d':' -f2-) + + declare -a asns_to_query=() + asns_to_query+=("AS${main_asn}") + if [ -n "$as_set" ]; then + log "Resolving members of AS-Set: $as_set" + resolved_asns=$(bgpq4 -j -t "$as_set" 2>/dev/null | jq -r '.[][]' | sed 's/^/AS/' | sort -u) + for resolved_asn in $resolved_asns; do + asns_to_query+=("$resolved_asn") + done + log "Resolved ASNs: ${asns_to_query[*]}" + fi + asns_to_query=($(echo "${asns_to_query[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + log "Unique ASNs to query: ${asns_to_query[*]}" + + declare -a ipv4_prefixes_to_add=() + declare -a ipv6_prefixes_to_add=() + declare -A seen_v4=() + declare -A seen_v6=() + + for asn_to_query in "${asns_to_query[@]}"; do + log "Fetching prefixes for $asn_to_query..." + + bgpq4_output_ipv6_raw=$(bgpq4 -6 -A "$asn_to_query" 2>&1) + if ! echo "$bgpq4_output_ipv6_raw" | grep -q "FATAL ERROR"; then + for prefix_with_length in $(echo "$bgpq4_output_ipv6_raw" | grep -oE '[0-9a-fA-F:]+/[0-9]+'); do + [[ "$prefix_with_length" == "::/0" ]] && continue + [[ -z "${seen_v6[$prefix_with_length]}" ]] && seen_v6[$prefix_with_length]=1 && ipv6_prefixes_to_add+=("$prefix_with_length") + done + fi + bgpq4_output_ipv4_raw=$(bgpq4 -4 -A "$asn_to_query" 2>&1) + if ! echo "$bgpq4_output_ipv4_raw" | grep -q "FATAL ERROR"; then + for prefix_with_length in $(echo "$bgpq4_output_ipv4_raw" | grep -oE '[0-9.]+/[0-9]+'); do + [[ "$prefix_with_length" == "0.0.0.0/0" ]] && continue + [[ -z "${seen_v4[$prefix_with_length]}" ]] && seen_v4[$prefix_with_length]=1 && ipv4_prefixes_to_add+=("$prefix_with_length") + done + fi + done + + commands_list_atomic="" + pl_v4="AS${main_asn}V4" + pl_v6="AS${main_asn}V6" + local_has_changes=false + + commands_list_atomic+='{"op":"delete","path":["policy","prefix-list","'"$pl_v4"'"]},' + commands_list_atomic+='{"op":"delete","path":["policy","prefix-list6","'"$pl_v6"'"]},' + local_has_changes=true + + rule_id=10 + for p in "${ipv4_prefixes_to_add[@]}"; do + log "Adding IPv4 rule ${rule_id} for ${p}..." + plen="${p#*/}" + commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$pl_v4"'","rule","'$rule_id'","action","permit"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$pl_v4"'","rule","'$rule_id'","prefix","'$p'"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$pl_v4"'","rule","'$rule_id'","le","24"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list","'"$pl_v4"'","rule","'$rule_id'","ge","'$plen'"]},' + rule_id=$((rule_id+10)) + done + + rule_id=10 + for p in "${ipv6_prefixes_to_add[@]}"; do + log "Adding IPv6 rule ${rule_id} for ${p}..." + plen="${p#*/}" + commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$pl_v6"'","rule","'$rule_id'","action","permit"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$pl_v6"'","rule","'$rule_id'","prefix","'$p'"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$pl_v6"'","rule","'$rule_id'","le","48"]},' + commands_list_atomic+='{"op":"set","path":["policy","prefix-list6","'"$pl_v6"'","rule","'$rule_id'","ge","'$plen'"]},' + rule_id=$((rule_id+10)) + done + + if [ "$local_has_changes" = true ]; then + commands_list_atomic="[${commands_list_atomic::-1}]" + log "Sending update for $entry..." + api_response=$(curl -s -k --location --request POST "${VYOS_HOST}/configure" \ + --form data="${commands_list_atomic}" \ + --form key="${API_KEY}" --max-time 300) + + if echo "$api_response" | grep -q '"success": true'; then + log "Update successful for $entry." + else + log "Update failed for $entry. Response: $api_response" + fi + fi +done +log "--- [PART 1] Completed. ---" + + +log "--- [PART 2] Starting Max-Prefix updates (Source: PeeringDB) ---" +log "Checking VRF 'bgp' configuration..." + +vrf_bgp_json=$(curl -s -k --location --request POST "${VYOS_HOST}/retrieve" \ + --form data='{"op":"showConfig","path":["vrf","name","bgp","protocols","bgp"]}' \ + --form key="${API_KEY}" --max-time 300) + +bgp_root=$(echo "$vrf_bgp_json" | jq -c '.data // .') +active_asn=$(echo "$bgp_root" | jq -r 'if has("system-as") then .["system-as"] else (keys[] | select(test("^[0-9]+$"))) end' | head -n 1) + +if [ -z "$active_asn" ] || [ "$active_asn" == "null" ]; then + log "ERROR: Could not find valid BGP configuration in VRF 'bgp'. Stopping Part 2." +else + log "Found BGP in VRF 'bgp' (ASN: $active_asn). Extracting neighbors..." + + neighbor_data=$(echo "$bgp_root" | jq -r --arg asn "$active_asn" ' + if .neighbor then + .neighbor + else + .[$asn].neighbor // empty + end | to_entries[] | + "\(.key)|\(.value["remote-as"])|\(.value["address-family"]["ipv4-unicast"]["maximum-prefix"] // "null")|\(.value["address-family"]["ipv6-unicast"]["maximum-prefix"] // "null")" + ') + + if [ -z "$neighbor_data" ]; then + log "No neighbors found in VRF 'bgp' configuration." + fi + + commands_max_prefix="" + has_max_changes=false + + has_system_as=$(echo "$bgp_root" | jq 'has("system-as")') + if [ "$has_system_as" == "true" ]; then + base_path='"vrf","name","bgp","protocols","bgp"' + else + base_path='"vrf","name","bgp","protocols","bgp","'"$active_asn"'"' + fi + + while IFS='|' read -r neighbor_ip remote_as current_max_v4 current_max_v6; do + if [ -z "$neighbor_ip" ]; then continue; fi + + if [ -z "$remote_as" ] || [ "$remote_as" == "null" ]; then continue; fi + if [ "$remote_as" == "$active_asn" ]; then continue; fi + + log "Checking Neighbor: $neighbor_ip (AS$remote_as)" + + update_v4=false + update_v6=false + + if [ "$current_max_v4" != "null" ]; then + if [ "$current_max_v4" -gt 1 ]; then + update_v4=true + else + log " > IPv4: Limit is $current_max_v4 (Protected). Skipping." + fi + else + log " > IPv4: Limit is not set (Transit). Skipping." + fi + + if [ "$current_max_v6" != "null" ]; then + if [ "$current_max_v6" -gt 1 ]; then + update_v6=true + else + log " > IPv6: Limit is $current_max_v6 (Protected). Skipping." + fi + else + log " > IPv6: Limit is not set (Transit). Skipping." + fi + + if [ "$update_v4" = false ] && [ "$update_v6" = false ]; then + continue + fi + + log " > Querying PeeringDB..." + pdb_response=$(curl -s -G --header "Authorization: Api-Key $PEERINGDB_API_KEY" "https://www.peeringdb.com/api/net" --data-urlencode "asn=$remote_as") + + pdb_v4_count=$(echo "$pdb_response" | jq -r '.data[0].info_prefixes4 // 0') + pdb_v6_count=$(echo "$pdb_response" | jq -r '.data[0].info_prefixes6 // 0') + + log " > PeeringDB Result: IPv4=$pdb_v4_count, IPv6=$pdb_v6_count" + + if [ "$update_v4" = true ]; then + if [ "$pdb_v4_count" -gt 0 ]; then + log " > IPv4: Updating limit $current_max_v4 -> $pdb_v4_count" + commands_max_prefix+='{"op":"set","path":['"$base_path"',"neighbor","'"$neighbor_ip"'","address-family","ipv4-unicast","maximum-prefix","'"$pdb_v4_count"'"]},' + has_max_changes=true + else + log " > IPv4: PeeringDB returned 0/error. Keeping $current_max_v4." + fi + fi + + if [ "$update_v6" = true ]; then + if [ "$pdb_v6_count" -gt 0 ]; then + log " > IPv6: Updating limit $current_max_v6 -> $pdb_v6_count" + commands_max_prefix+='{"op":"set","path":['"$base_path"',"neighbor","'"$neighbor_ip"'","address-family","ipv6-unicast","maximum-prefix","'"$pdb_v6_count"'"]},' + has_max_changes=true + else + log " > IPv6: PeeringDB returned 0/error. Keeping $current_max_v6." + fi + fi + + done <<< "$neighbor_data" + + if [ "$has_max_changes" = true ]; then + commands_max_prefix="[${commands_max_prefix::-1}]" + log "Sending Max-Prefix updates to API..." + api_response=$(curl -s -k --location --request POST "${VYOS_HOST}/configure" \ + --form data="${commands_max_prefix}" \ + --form key="${API_KEY}" --max-time 300) + + echo "$api_response" | grep -q '"success": true' \ + && log "Max-Prefix updates successful." \ + || log "Max-Prefix updates failed: $api_response" + else + log "No max-prefix updates needed." + fi +fi +log "--- [PART 2] Completed. ---" + +log "--------------------------------------------------------" +log "Saving configuration..." +curl -s -k --location --request POST "${VYOS_HOST}/config-file" \ + --form data='{"op":"save"}' --form key="${API_KEY}" --max-time 300 > /dev/null + +log "==========================================================" +log "Process finished." +log "==========================================================" \ No newline at end of file