Update dns-fix.js
Browse files- dns-fix.js +44 -13
dns-fix.js
CHANGED
|
@@ -14,15 +14,25 @@
|
|
| 14 |
const dns = require("dns");
|
| 15 |
const https = require("https");
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
// In-memory cache for runtime DoH resolutions
|
| 18 |
-
const runtimeCache = new Map(); // hostname -> {
|
| 19 |
|
| 20 |
-
// DNS-over-HTTPS resolver
|
| 21 |
function dohResolve(hostname, callback) {
|
| 22 |
-
// Check runtime cache
|
| 23 |
const cached = runtimeCache.get(hostname);
|
| 24 |
if (cached && cached.expiry > Date.now()) {
|
| 25 |
-
return callback(null, cached.
|
| 26 |
}
|
| 27 |
|
| 28 |
const url = `https://1.1.1.1/dns-query?name=${encodeURIComponent(hostname)}&type=A`;
|
|
@@ -39,10 +49,15 @@ function dohResolve(hostname, callback) {
|
|
| 39 |
if (aRecords.length === 0) {
|
| 40 |
return callback(new Error(`DoH: no A record for ${hostname}`));
|
| 41 |
}
|
| 42 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
const ttl = Math.max((aRecords[0].TTL || 300) * 1000, 60000);
|
| 44 |
-
runtimeCache.set(hostname, {
|
| 45 |
-
callback(null,
|
| 46 |
} catch (e) {
|
| 47 |
callback(new Error(`DoH parse error: ${e.message}`));
|
| 48 |
}
|
|
@@ -83,6 +98,24 @@ dns.lookup = function patchedLookup(hostname, options, callback) {
|
|
| 83 |
return origLookup.call(dns, hostname, options, callback);
|
| 84 |
}
|
| 85 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
// 1) Try system DNS first
|
| 87 |
origLookup.call(dns, hostname, options, (err, address, family) => {
|
| 88 |
if (!err && address) {
|
|
@@ -91,14 +124,12 @@ dns.lookup = function patchedLookup(hostname, options, callback) {
|
|
| 91 |
|
| 92 |
// 2) System DNS failed with ENOTFOUND or EAI_AGAIN — fall back to DoH
|
| 93 |
if (err && (err.code === "ENOTFOUND" || err.code === "EAI_AGAIN")) {
|
| 94 |
-
dohResolve(hostname, (dohErr,
|
| 95 |
-
if (dohErr || !
|
| 96 |
return callback(err); // Return original error
|
| 97 |
}
|
| 98 |
-
if (options.all)
|
| 99 |
-
|
| 100 |
-
}
|
| 101 |
-
callback(null, ip, 4);
|
| 102 |
});
|
| 103 |
} else {
|
| 104 |
// Other DNS errors — pass through
|
|
|
|
| 14 |
const dns = require("dns");
|
| 15 |
const https = require("https");
|
| 16 |
|
| 17 |
+
// Domains where system DNS resolves but TCP connections are blocked on HF Spaces
|
| 18 |
+
const FORCED_DOH_DOMAINS = new Set(["api.telegram.org"]);
|
| 19 |
+
|
| 20 |
+
// Last-resort fallback IPs if DoH itself fails
|
| 21 |
+
const FALLBACK_IPS = {
|
| 22 |
+
"api.telegram.org": [
|
| 23 |
+
{ address: "149.154.167.220", family: 4 },
|
| 24 |
+
{ address: "149.154.166.110", family: 4 },
|
| 25 |
+
],
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
// In-memory cache for runtime DoH resolutions
|
| 29 |
+
const runtimeCache = new Map(); // hostname -> { entries, expiry }
|
| 30 |
|
| 31 |
+
// DNS-over-HTTPS resolver — returns all A records, shuffled
|
| 32 |
function dohResolve(hostname, callback) {
|
|
|
|
| 33 |
const cached = runtimeCache.get(hostname);
|
| 34 |
if (cached && cached.expiry > Date.now()) {
|
| 35 |
+
return callback(null, cached.entries);
|
| 36 |
}
|
| 37 |
|
| 38 |
const url = `https://1.1.1.1/dns-query?name=${encodeURIComponent(hostname)}&type=A`;
|
|
|
|
| 49 |
if (aRecords.length === 0) {
|
| 50 |
return callback(new Error(`DoH: no A record for ${hostname}`));
|
| 51 |
}
|
| 52 |
+
const entries = aRecords.map((r) => ({ address: r.data, family: 4 }));
|
| 53 |
+
// Shuffle so retries hit different IPs
|
| 54 |
+
for (let i = entries.length - 1; i > 0; i--) {
|
| 55 |
+
const j = Math.floor(Math.random() * (i + 1));
|
| 56 |
+
[entries[i], entries[j]] = [entries[j], entries[i]];
|
| 57 |
+
}
|
| 58 |
const ttl = Math.max((aRecords[0].TTL || 300) * 1000, 60000);
|
| 59 |
+
runtimeCache.set(hostname, { entries, expiry: Date.now() + ttl });
|
| 60 |
+
callback(null, entries);
|
| 61 |
} catch (e) {
|
| 62 |
callback(new Error(`DoH parse error: ${e.message}`));
|
| 63 |
}
|
|
|
|
| 98 |
return origLookup.call(dns, hostname, options, callback);
|
| 99 |
}
|
| 100 |
|
| 101 |
+
// For domains known to be blocked on HF Spaces, skip system DNS entirely
|
| 102 |
+
if (FORCED_DOH_DOMAINS.has(hostname)) {
|
| 103 |
+
dohResolve(hostname, (dohErr, entries) => {
|
| 104 |
+
if (dohErr || !entries || entries.length === 0) {
|
| 105 |
+
// Last resort: use hardcoded fallback IPs
|
| 106 |
+
const fb = FALLBACK_IPS[hostname];
|
| 107 |
+
if (fb && fb.length > 0) {
|
| 108 |
+
if (options.all) return callback(null, fb);
|
| 109 |
+
return callback(null, fb[0].address, fb[0].family);
|
| 110 |
+
}
|
| 111 |
+
return callback(dohErr || new Error(`No IPs for ${hostname}`));
|
| 112 |
+
}
|
| 113 |
+
if (options.all) return callback(null, entries);
|
| 114 |
+
callback(null, entries[0].address, entries[0].family);
|
| 115 |
+
});
|
| 116 |
+
return;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
// 1) Try system DNS first
|
| 120 |
origLookup.call(dns, hostname, options, (err, address, family) => {
|
| 121 |
if (!err && address) {
|
|
|
|
| 124 |
|
| 125 |
// 2) System DNS failed with ENOTFOUND or EAI_AGAIN — fall back to DoH
|
| 126 |
if (err && (err.code === "ENOTFOUND" || err.code === "EAI_AGAIN")) {
|
| 127 |
+
dohResolve(hostname, (dohErr, entries) => {
|
| 128 |
+
if (dohErr || !entries || entries.length === 0) {
|
| 129 |
return callback(err); // Return original error
|
| 130 |
}
|
| 131 |
+
if (options.all) return callback(null, entries);
|
| 132 |
+
callback(null, entries[0].address, entries[0].family);
|
|
|
|
|
|
|
| 133 |
});
|
| 134 |
} else {
|
| 135 |
// Other DNS errors — pass through
|