Files
pleiades/ddns.py

62 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""DDNS updater — keep the proxy hostname pointed at the home WAN IP.
The SOCKS5/HTTP gateway is exposed on the home WAN IP (dynamic Comcast). The
storefront advertises proxy.clean-proxys.thetempleofdoom.com instead of the raw
IP; this updater keeps that A record in sync. DNS-only (proxied=false) because
Cloudflare's orange-cloud cannot carry raw TCP (SOCKS5/HTTP CONNECT).
Runs on CT777 (egresses via the home WAN, so ipify returns the real home IP —
NOT the MacBook's Nord egress). Scheduled by ddns.timer every 15 min.
"""
import json
import requests
CFG = json.load(open("/opt/pleiades/config.json"))
CF = CFG["cloudflare"]
API = "https://api.cloudflare.com/client/v4"
HDR = {"X-Auth-Email": CF["email"], "X-Auth-Key": CF["api_key"],
"Content-Type": "application/json"}
def get_wan_ip():
r = requests.get("https://api.ipify.org", timeout=10)
r.raise_for_status()
return r.text.strip()
def find_record():
r = requests.get(f"{API}/zones/{CF['zone_id']}/dns_records",
params={"name": CF["record_name"], "type": "A"},
headers=HDR, timeout=15)
r.raise_for_status()
recs = r.json().get("result", [])
return recs[0] if recs else None
def main():
wan = get_wan_ip()
rec = find_record()
body = {"type": "A", "name": CF["record_name"], "content": wan,
"ttl": 120, "proxied": False}
if rec is None:
r = requests.post(f"{API}/zones/{CF['zone_id']}/dns_records",
headers=HDR, json=body, timeout=15)
ok = r.json().get("success")
print(f"created {CF['record_name']} -> {wan} (success={ok})")
return
cur = rec.get("content")
if cur == wan:
print(f"no change: {CF['record_name']} -> {wan}")
return
r = requests.put(f"{API}/zones/{CF['zone_id']}/dns_records/{rec['id']}",
headers=HDR, json=body, timeout=15)
ok = r.json().get("success")
print(f"updated {CF['record_name']}: {cur} -> {wan} (success={ok})")
if __name__ == "__main__":
main()