#!/usr/bin/env python3 """Add exposedgays.com to Cloudflare tunnel remote ingress + verify DNS.""" import json import re import time import urllib.error import urllib.request import paramiko PASS = "Bbt9115xty9176!" ACCOUNT = "2599c23bbb1255dbb73e8d34b4115fda" TUNNEL_ID = "03079a26-f14c-4622-b463-ba54a24f7472" HOSTS = ["exposedgays.com", "www.exposedgays.com"] RULES = [ { "hostname": "exposedgays.com", "service": "https://localhost:443", "originRequest": {"noTLSVerify": True}, }, { "hostname": "www.exposedgays.com", "service": "https://localhost:443", "originRequest": {"noTLSVerify": True}, }, ] def get_token(): c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect("10.10.0.1", username="admin", password=PASS, timeout=15) _, o, e = c.exec_command("cat /usr/local/etc/wan-dns-failover.env", timeout=30) o.channel.recv_exit_status() text = (o.read() + e.read()).decode() c.close() return re.search(r"CLOUDFLARE_API_TOKEN=([^\s\"']+)", text).group(1) def cf(token, path, method="GET", data=None): req = urllib.request.Request( f"https://api.cloudflare.com/client/v4{path}", data=json.dumps(data).encode() if data is not None else None, method=method, headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"}, ) try: with urllib.request.urlopen(req, timeout=60) as r: return r.status, json.load(r) except urllib.error.HTTPError as e: return e.code, json.loads(e.read().decode()) def ssh_run(cmd, timeout=90): c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect("10.10.0.10", username="localadministrator", password=PASS, timeout=30) _, o, e = c.exec_command(cmd, timeout=timeout) o.channel.recv_exit_status() out = (o.read() + e.read()).decode(errors="replace") c.close() return out def merge_ingress(ingress): hostnames = {i.get("hostname") for i in ingress if i.get("hostname")} changed = False for rule in RULES: if rule["hostname"] not in hostnames: catch = next((i for i, x in enumerate(ingress) if not x.get("hostname")), len(ingress)) ingress.insert(catch, rule) hostnames.add(rule["hostname"]) changed = True print("added", rule["hostname"]) return ingress, changed def main(): token = get_token() code, body = cf(token, f"/accounts/{ACCOUNT}/cfd_tunnel/{TUNNEL_ID}/configurations") print(f"GET tunnel config HTTP {code}") if not body.get("result"): print(body.get("errors")) return 1 ingress = body["result"].get("config", {}).get("ingress", []) present = [i.get("hostname") for i in ingress if i.get("hostname") in HOSTS] print("exposedgays in remote ingress:", present) ingress, changed = merge_ingress(ingress) if changed: put_code, put = cf( token, f"/accounts/{ACCOUNT}/cfd_tunnel/{TUNNEL_ID}/configurations", "PUT", {"config": {"ingress": ingress, "warp-routing": {"enabled": False}}}, ) print(f"PUT HTTP {put_code} success={put.get('success')} errors={put.get('errors')}") if not put.get("success"): return 1 print(ssh_run(f"echo '{PASS}' | sudo -S systemctl restart cloudflared")) time.sleep(8) print("\n=== verify ===") print( ssh_run( "systemctl is-active cloudflared; " "dig @1.1.1.1 www.exposedgays.com CNAME +short; " "curl -sSI --max-time 20 https://www.exposedgays.com/ | head -12; " "curl -sSL --max-time 20 https://www.exposedgays.com/ | head -c 250" ) ) return 0 if __name__ == "__main__": raise SystemExit(main())