41 lines
1.7 KiB
Python
41 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Update the gateway vhosts' trusted ranges, retaining the last valid configuration on failure."""
|
|
import ipaddress
|
|
import os
|
|
import pathlib
|
|
import subprocess
|
|
|
|
target = pathlib.Path("/etc/nginx/dpl-cloudflare-realip.conf")
|
|
ranges = []
|
|
for version in (4, 6):
|
|
result = subprocess.run(["curl", "-4", "--fail", "--silent", "--show-error", "--max-time", "30",
|
|
f"https://www.cloudflare.com/ips-v{version}"], check=True, capture_output=True, text=True)
|
|
nets = [ipaddress.ip_network(line.strip(), strict=True) for line in result.stdout.splitlines() if line.strip()]
|
|
assert 5 <= len(nets) <= 100 if version == 4 else 2 <= len(nets) <= 100, "Unexpected range count"
|
|
assert all(n.version == version and n.prefixlen >= (8 if version == 4 else 16) for n in nets), "Invalid trust range"
|
|
ranges.extend(str(n) for n in nets)
|
|
assert len(ranges) == len(set(ranges)), "Duplicate ranges"
|
|
data = ("# DPL only: synchronized from Cloudflare official lists.\n" +
|
|
"".join(f"set_real_ip_from {n};\n" for n in ranges) +
|
|
"real_ip_header CF-Connecting-IP;\nreal_ip_recursive off;\n").encode()
|
|
old = target.read_bytes() if target.exists() else None
|
|
if old == data:
|
|
print("Cloudflare trust ranges unchanged")
|
|
raise SystemExit
|
|
temporary = target.with_suffix(".conf.new")
|
|
temporary.write_bytes(data)
|
|
temporary.chmod(0o644)
|
|
os.replace(temporary, target)
|
|
try:
|
|
subprocess.run(["nginx", "-t"], check=True)
|
|
subprocess.run(["systemctl", "reload", "nginx"], check=True)
|
|
except Exception:
|
|
if old is None:
|
|
target.unlink()
|
|
else:
|
|
temporary.write_bytes(old)
|
|
temporary.chmod(0o644)
|
|
os.replace(temporary, target)
|
|
raise
|
|
print(f"DPL Cloudflare trust ranges updated: {len(ranges)} ranges")
|