import urllib.request import urllib.parse import ssl import json import sys sys.stdout.reconfigure(encoding='utf-8') ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE A_RECORDS = [ # Gateways ("gateway", "140.44.4.1"), ("udm", "140.44.4.1"), ("gateway-lan", "14.44.4.1"), ("gateway-mgmt", "140.44.44.1"), ("gateway-storage", "14.10.10.1"), ("gateway-smarthome", "14.4.4.1"), ("gateway-media", "192.168.1.1"), # VIPs ("npm", "140.44.4.70"), ("npm-vip", "140.44.4.70"), ("*", "140.44.4.70"), # Wildcard for all reverse-proxied services ("aero-traefik", "140.44.4.34"), ("space-traefik", "140.44.4.62"), ("dns1", "140.44.4.36"), ("pihole1", "140.44.4.36"), ("dns2", "140.44.4.65"), ("pihole2", "140.44.4.65"), # Storage ("sn-nas", "14.10.10.71"), ("snarfnas", "14.10.10.72"), # Aerodrome Control Plane ("sninfr2lnxctl01", "140.44.4.11"), ("sninfr2lnxctl02", "140.44.4.12"), ("sninfr2lnxctl03", "140.44.4.13"), # Aerodrome Workers ("sninfr2lnxwrk01", "140.44.4.21"), ("sninfr2lnxwrk02", "140.44.4.22"), ("sninfr2lnxwrk03", "140.44.4.23"), ("sninfr2lnxwrk04", "140.44.4.24"), ("sninfr2lnxwrk05", "140.44.4.25"), ("sninfr2lnxwrk06", "140.44.4.26"), ("sninfr2lnxwrk07", "140.44.4.27"), # Spaceport Control Plane ("sninfr0lnxctl01", "140.44.4.41"), ("sninfr0lnxctl02", "140.44.4.42"), ("sninfr0lnxctl03", "140.44.4.43"), ("sninfr0lnxctl04", "140.44.4.44"), # Spaceport Workers ("sninfr0lnxwrk01", "140.44.4.51"), ("sninfr0lnxwrk02", "140.44.4.52"), ("sninfr0lnxwrk03", "140.44.4.53"), ("sninfr0lnxwrk04", "140.44.4.54"), ("sninfr0lnxwrk05", "140.44.4.55"), ("sninfr0lnxwrk06", "140.44.4.56"), # Swarm Node ("sninfr1lnxctl01", "140.44.4.71"), # Harvester ("spacedock", "140.44.4.90"), ] PTR_ZONES = [ "4.44.140.in-addr.arpa", "44.44.140.in-addr.arpa", "10.10.14.in-addr.arpa", "4.44.14.in-addr.arpa", "4.4.14.in-addr.arpa", "1.168.192.in-addr.arpa", ] def get_token(host): url = f"https://{host}/api/user/login?user=admin&pass=snarfnetadmin&includeInfo=true" with urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=8) as resp: return json.loads(resp.read().decode())['token'] def provision_server(host): print(f"\n=======================================================") print(f"Provisioning Technitium on {host}...") token = get_token(host) print(f"Token acquired for {host}") # 1. Create Forward Zone snarfnet.net create_zone_url = f"https://{host}/api/zones/create?token={token}&zone=snarfnet.net&type=Primary" try: with urllib.request.urlopen(urllib.request.Request(create_zone_url), context=ctx, timeout=8) as resp: print(f" ✓ Created forward zone snarfnet.net on {host}") except urllib.error.HTTPError as e: err = e.read().decode() if "already exists" in err: print(f" - Forward zone snarfnet.net already exists on {host}") else: print(f" ✗ Error creating snarfnet.net: {err}") # 2. Create Reverse PTR Zones for z in PTR_ZONES: cz_url = f"https://{host}/api/zones/create?token={token}&zone={z}&type=Primary" try: with urllib.request.urlopen(urllib.request.Request(cz_url), context=ctx, timeout=8) as resp: print(f" ✓ Created reverse zone {z} on {host}") except urllib.error.HTTPError as e: err = e.read().decode() if "already exists" in err: print(f" - Reverse zone {z} already exists on {host}") else: print(f" ✗ Error creating reverse zone {z}: {err}") # 3. Add A records + Auto PTR print(f"\nAdding {len(A_RECORDS)} authoritative records on {host}...") added = 0 for name, ip in A_RECORDS: domain = f"{name}.snarfnet.net" if name != "@" else "snarfnet.net" # Don't create PTR for wildcard use_ptr = "false" if name == "*" else "true" params = { "token": token, "domain": domain, "zone": "snarfnet.net", "type": "A", "ipAddress": ip, "ptr": use_ptr, "overwrite": "true", "ttl": 3600 } add_url = f"https://{host}/api/zones/records/add?{urllib.parse.urlencode(params)}" try: with urllib.request.urlopen(urllib.request.Request(add_url), context=ctx, timeout=8) as resp: added += 1 except Exception as e: print(f" ✗ Failed adding {domain} -> {ip}: {e}") print(f" ✓ Successfully added/updated {added} A and PTR records on {host}") provision_server("dns1.snarfnet.net") provision_server("dns2.snarfnet.net") print("\nDone provisioning both Technitium DNS servers!")