| "use strict"; |
| console.error("[DNS-FIX] Loaded — DoH resolver + tls/net logging active."); |
| const http = require("http"); |
| const https = require("https"); |
| const { PassThrough } = require("stream"); |
|
|
| const blockedDomains = ["api.telegram.org", "discord.com", "discordapp.com", "web.whatsapp.com"]; |
|
|
| function isBlocked(hostname) { |
| return hostname && blockedDomains.some((d) => hostname === d || hostname.endsWith(`.${d}`)); |
| } |
|
|
| |
| const _origHttpRequest = http.request; |
| const _origHttpsRequest = https.request; |
|
|
| const { AsyncLocalStorage } = require("async_hooks"); |
| const asyncStorage = new AsyncLocalStorage(); |
|
|
| function transparentProxyRequest(protocol, origFn, ...args) { |
| if (asyncStorage.getStore()) { |
| return origFn.apply(this, args); |
| } |
|
|
| let options = args[0]; |
| let callback = args[1]; |
|
|
| if (typeof options === "string") { |
| try { |
| options = new URL(options); |
| } catch { |
| return origFn.apply(this, args); |
| } |
| } else if (options instanceof URL) { |
| |
| } else { |
| |
| options = { ...options }; |
| } |
|
|
| if (typeof callback !== "function" && typeof args[2] === "function") { |
| callback = args[2]; |
| } |
|
|
| const hostname = options.hostname || options.host; |
| const path = options.path || options.pathname || "/"; |
|
|
| if (isBlocked(hostname)) { |
| console.error(`[DNS-FIX] Transparently proxying ${protocol}//${hostname}${path} via fetch()`); |
|
|
| const requestUrl = `${protocol}//${hostname}${path}`; |
| const requestHeaders = { ...options.headers }; |
| |
| const reqStream = new PassThrough(); |
| const resStream = new PassThrough(); |
| |
| let requestBody = Buffer.alloc(0); |
| reqStream.on("data", (chunk) => { |
| requestBody = Buffer.concat([requestBody, chunk]); |
| }); |
|
|
| reqStream.on("finish", () => { |
| asyncStorage.run(true, async () => { |
| try { |
| const fetchRes = await fetch(requestUrl, { |
| method: options.method || "GET", |
| headers: requestHeaders, |
| body: options.method !== "GET" && options.method !== "HEAD" ? requestBody : undefined, |
| redirect: "manual", |
| }); |
|
|
| resStream.statusCode = fetchRes.status; |
| resStream.statusMessage = fetchRes.statusText; |
| resStream.headers = Object.fromEntries(fetchRes.headers.entries()); |
| resStream.rawHeaders = []; |
| for (const [k, v] of fetchRes.headers.entries()) { |
| resStream.rawHeaders.push(k, v); |
| } |
|
|
| if (callback) callback(resStream); |
| reqStream.emit("response", resStream); |
|
|
| if (fetchRes.body) { |
| const reader = fetchRes.body.getReader(); |
| while (true) { |
| const { done, value } = await reader.read(); |
| if (done) break; |
| resStream.write(value); |
| } |
| } |
| resStream.end(); |
| } catch (err) { |
| console.error(`[DNS-FIX] Proxy error for ${requestUrl}: ${err.message}`); |
| reqStream.emit("error", err); |
| } |
| }); |
| }); |
|
|
| reqStream.abort = () => reqStream.destroy(); |
| reqStream.end = (chunk) => { |
| if (chunk) reqStream.write(chunk); |
| reqStream.end(); |
| }; |
| reqStream.setTimeout = (ms, cb) => { if (cb) setTimeout(cb, ms); return reqStream; }; |
| reqStream.setNoDelay = () => reqStream; |
| reqStream.setSocketKeepAlive = () => reqStream; |
|
|
| return reqStream; |
| } |
|
|
| return origFn.apply(this, args); |
| } |
|
|
| http.request = function (...args) { |
| return transparentProxyRequest("http:", _origHttpRequest, ...args); |
| }; |
|
|
| https.request = function (...args) { |
| return transparentProxyRequest("https:", _origHttpsRequest, ...args); |
| }; |
|
|
| http.get = function (...args) { |
| const req = http.request(...args); |
| req.end(); |
| return req; |
| }; |
|
|
| https.get = function (...args) { |
| const req = https.request(...args); |
| req.end(); |
| return req; |
| }; |
|
|