File size: 3,576 Bytes
e7ab5f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12594f7
e7ab5f1
12594f7
e7ab5f1
 
 
 
 
 
12594f7
 
e7ab5f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12594f7
 
e7ab5f1
 
 
 
12594f7
 
e7ab5f1
 
 
 
 
 
 
 
 
 
 
 
 
dad02c1
 
 
 
 
 
 
 
 
 
 
e7ab5f1
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env python3
"""
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",         # Cloudflare
    "https://8.8.8.8/resolve",            # Google
    "https://dns.google/resolve",         # Google (hostname)
]

# Domains that WhatsApp/Baileys and Telegram need to connect to
DOMAINS = [
    # WhatsApp / Baileys
    "web.whatsapp.com",
    "g.whatsapp.net",
    "mmg.whatsapp.net",
    "pps.whatsapp.net",
    "static.whatsapp.net",
    "media.fmed1-1.fna.whatsapp.net",
    # Telegram Bot API
    "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:  # A record
            ips.append(answer["data"])
        elif answer.get("type") == 5:  # CNAME — follow chain
            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"

    # First check if system DNS works at all
    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")
        # Write empty file so dns-fix.cjs knows it's 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)

    # Also write to /etc/hosts so undici/fetch (which bypasses dns.lookup) works
    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()