manage-ipset.sh 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/bin/bash
  2. # Requires: pvesh (Proxmox), dig (dnsutils)
  3. check_deps() {
  4. missing=()
  5. command -v pvesh >/dev/null 2>&1 || missing+=("pvesh")
  6. command -v dig >/dev/null 2>&1 || missing+=("dnsutils")
  7. if [ ${#missing[@]} -gt 0 ]; then
  8. echo "ERROR: missing dependencies: ${missing[*]}"
  9. exit 1
  10. fi
  11. }
  12. check_deps
  13. create_ipset() {
  14. ipset=$1
  15. comment="auto-generated $(date -Iseconds)"
  16. if ! pvesh get "/cluster/firewall/ipset/${ipset}" &>/dev/null; then
  17. echo "creating $ipset"
  18. pvesh create /cluster/firewall/ipset --name "${ipset}" --comment "$comment"
  19. else
  20. pvesh create /cluster/firewall/ipset --name "${ipset}" --rename "${ipset}" --comment "$comment"
  21. fi
  22. }
  23. manage_ipset() {
  24. ipset=$1
  25. shift
  26. hostnames=("$@")
  27. declare -A dns_ips
  28. max_rounds=50
  29. for hostname in "${hostnames[@]}"; do
  30. stale=0
  31. for ((round=1; round<=max_rounds; round++)); do
  32. dns4=$(dig +short "$hostname" A 2>/dev/null)
  33. dns6=$(dig +short "$hostname" AAAA 2>/dev/null)
  34. added=0
  35. while read -r ip; do
  36. if [ -n "$ip" ] && [ -z "${dns_ips[$ip]}" ]; then
  37. dns_ips[$ip]=1
  38. added=1
  39. fi
  40. done < <(echo -e "${dns4}\n${dns6}" | grep -v '^;' | grep -v '^$')
  41. if [ "$added" -eq 1 ]; then
  42. stale=0
  43. else
  44. stale=$((stale + 1))
  45. [ "$stale" -ge 10 ] && break
  46. fi
  47. done
  48. done
  49. if [ ${#dns_ips[@]} -eq 0 ]; then
  50. echo "WARNING: no DNS results for ${hostnames[*]}, skipping"
  51. return 1
  52. fi
  53. declare -A ipset_ips
  54. if existing=$(pvesh get "/cluster/firewall/ipset/$ipset" --output-format json 2>/dev/null) && [ -n "$existing" ]; then
  55. ip_list=$(echo "$existing" | grep -o '"cidr"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*"([^"]*)"/\1/' | sed 's|/[0-9]*$||')
  56. while read -r ip; do
  57. [ -n "$ip" ] && ipset_ips[$ip]=1
  58. done < <(echo "$ip_list" | sort -u)
  59. fi
  60. for ip in "${!dns_ips[@]}"; do
  61. if [ -z "${ipset_ips[$ip]}" ]; then
  62. echo "ADD: $ip"
  63. pvesh create "/cluster/firewall/ipset/$ipset" --cidr "$ip"
  64. fi
  65. done
  66. for ip in "${!ipset_ips[@]}"; do
  67. if [ -z "${dns_ips[$ip]}" ]; then
  68. echo "DEL: $ip"
  69. pvesh delete "/cluster/firewall/ipset/$ipset/$ip"
  70. fi
  71. done
  72. }
  73. if [ $# -lt 2 ]; then
  74. echo "Usage: $0 <ipset> <hostname> [hostname ...]"
  75. exit 1
  76. fi
  77. create_ipset "$1"
  78. manage_ipset "$@"