| |
| """ |
| DNS-over-HTTPS resolver for HF Spaces. |
| |
| HF Spaces containers cannot resolve certain domains (e.g. web.whatsapp.com) |
| via the default DNS resolver. This script resolves key domains using |
| Cloudflare DoH (DNS-over-HTTPS) and writes results to a JSON file |
| for the Node.js DNS fix script to consume. |
| |
| Usage: python3 dns-resolve.py [output-file] |
| """ |
|
|
| import json |
| import os |
| import ssl |
| import sys |
| import urllib.request |
|
|
| DOH_ENDPOINTS = [ |
| "https://1.1.1.1/dns-query", |
| "https://8.8.8.8/resolve", |
| "https://dns.google/resolve", |
| ] |
|
|
| |
| DOMAINS = [ |
| |
| "web.whatsapp.com", |
| "g.whatsapp.net", |
| "mmg.whatsapp.net", |
| "pps.whatsapp.net", |
| "static.whatsapp.net", |
| "media.fmed1-1.fna.whatsapp.net", |
| |
| "api.telegram.org", |
| ] |
|
|
|
|
| def resolve_via_doh(domain: str, endpoint: str, timeout: int = 10) -> list[str]: |
| """Resolve a domain via DNS-over-HTTPS, return list of IPv4 addresses.""" |
| url = f"{endpoint}?name={domain}&type=A" |
| req = urllib.request.Request(url, headers={"Accept": "application/dns-json"}) |
|
|
| ctx = ssl.create_default_context() |
| resp = urllib.request.urlopen(req, timeout=timeout, context=ctx) |
| data = json.loads(resp.read().decode()) |
|
|
| ips = [] |
| for answer in data.get("Answer", []): |
| if answer.get("type") == 1: |
| ips.append(answer["data"]) |
| elif answer.get("type") == 5: |
| continue |
| return ips |
|
|
|
|
| def resolve_domain(domain: str) -> list[str]: |
| """Try multiple DoH endpoints until one succeeds.""" |
| for endpoint in DOH_ENDPOINTS: |
| try: |
| ips = resolve_via_doh(domain, endpoint) |
| if ips: |
| return ips |
| except Exception: |
| continue |
| return [] |
|
|
|
|
| def main() -> None: |
| output_file = sys.argv[1] if len(sys.argv) > 1 else "/tmp/dns-resolved.json" |
|
|
| |
| try: |
| import socket |
| socket.getaddrinfo("web.whatsapp.com", 443, socket.AF_INET) |
| socket.getaddrinfo("api.telegram.org", 443, socket.AF_INET) |
| print("[dns] System DNS works for WhatsApp & Telegram — DoH not needed") |
| |
| with open(output_file, "w") as f: |
| json.dump({}, f) |
| return |
| except (socket.gaierror, OSError) as e: |
| print(f"[dns] System DNS failed ({e}) — using DoH fallback") |
|
|
| results = {} |
| for domain in DOMAINS: |
| ips = resolve_domain(domain) |
| if ips: |
| results[domain] = ips[0] |
| print(f"[dns] {domain} -> {ips[0]}") |
| else: |
| print(f"[dns] WARNING: could not resolve {domain}") |
|
|
| with open(output_file, "w") as f: |
| json.dump(results, f, indent=2) |
|
|
| |
| if results: |
| try: |
| with open("/etc/hosts", "a") as f: |
| f.write("\n# === HuggingClaw DoH resolved domains ===\n") |
| for domain, ip in results.items(): |
| f.write(f"{ip} {domain}\n") |
| print(f"[dns] Wrote {len(results)} entries to /etc/hosts") |
| except PermissionError: |
| print("[dns] WARNING: cannot write /etc/hosts (permission denied)") |
|
|
| print(f"[dns] Resolved {len(results)}/{len(DOMAINS)} domains -> {output_file}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|