From 217ce9d972df29f3166d31c7a1467ed3f7b5e066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Fri, 16 May 2025 18:10:05 +0800 Subject: [PATCH] =?UTF-8?q?bugfix:=20DoT=E7=9A=84DNS=EF=BC=8C=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=BA=86SNI=E4=BD=86=E6=9C=AA=E7=94=9F=E6=95=88?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mitmproxy/package.json | 1 - packages/mitmproxy/src/lib/dns/base.js | 2 +- packages/mitmproxy/src/lib/dns/https.js | 2 +- packages/mitmproxy/src/lib/dns/tls.js | 5 +- .../src/lib/dns/util/dns-over-tls.js | 81 +++++++++++++++++++ .../mitmproxy/test/dnsTest-abroad-doh-sni.mjs | 2 +- .../mitmproxy/test/dnsTest-abroad-dot-sni.mjs | 40 ++++++++- pnpm-lock.yaml | 10 --- 8 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 packages/mitmproxy/src/lib/dns/util/dns-over-tls.js diff --git a/packages/mitmproxy/package.json b/packages/mitmproxy/package.json index b2d53a3..9367be8 100644 --- a/packages/mitmproxy/package.json +++ b/packages/mitmproxy/package.json @@ -18,7 +18,6 @@ "axios": "^1.7.7", "baidu-aip-sdk": "^4.16.16", "dns-over-http": "^0.2.0", - "dns-over-tls": "^0.0.9", "is-browser": "^2.1.0", "json5": "^2.2.3", "lodash": "^4.17.21", diff --git a/packages/mitmproxy/src/lib/dns/base.js b/packages/mitmproxy/src/lib/dns/base.js index b7dc637..298b73c 100644 --- a/packages/mitmproxy/src/lib/dns/base.js +++ b/packages/mitmproxy/src/lib/dns/base.js @@ -168,7 +168,7 @@ module.exports = class BaseDNS { return new Promise((resolve, reject) => { // 设置超时任务 let isOver = false - const timeout = 6000 + const timeout = 8000 const timeoutId = setTimeout(() => { if (!isOver) { log.error(`[DNS-over-${this.dnsType} '${this.dnsName}'] DNS查询超时, hostname: ${hostname}, sni: ${this.dnsServerName || '无'}, type: ${type}${this.dnsServer ? `, dnsServer: ${this.dnsServer}` : ''}${this.dnsServerPort ? `:${this.dnsServerPort}` : ''}, cost: ${Date.now() - start} ms`) diff --git a/packages/mitmproxy/src/lib/dns/https.js b/packages/mitmproxy/src/lib/dns/https.js index d5e2d76..07f2639 100644 --- a/packages/mitmproxy/src/lib/dns/https.js +++ b/packages/mitmproxy/src/lib/dns/https.js @@ -9,7 +9,7 @@ const dohQueryAsync = promisify(doh.query) function createAgent (dnsServer) { return new (dnsServer.startsWith('https:') ? HttpsAgent : Agent)({ keepAlive: true, - timeout: 20000, + timeout: 4000, }) } diff --git a/packages/mitmproxy/src/lib/dns/tls.js b/packages/mitmproxy/src/lib/dns/tls.js index dfb7024..0194b4a 100644 --- a/packages/mitmproxy/src/lib/dns/tls.js +++ b/packages/mitmproxy/src/lib/dns/tls.js @@ -1,4 +1,4 @@ -const dnstls = require('dns-over-tls') +const dnstls = require('./util/dns-over-tls') const BaseDNS = require('./base') const defaultPort = 853 @@ -16,10 +16,13 @@ module.exports = class DNSOverTLS extends BaseDNS { host: this.dnsServer, port: this.dnsServerPort, servername: this.dnsServerName || this.dnsServer, + rejectUnauthorized: !this.dnsServerName, name: hostname, klass: 'IN', type, + + timeout: 4000, } return dnstls.query(options) diff --git a/packages/mitmproxy/src/lib/dns/util/dns-over-tls.js b/packages/mitmproxy/src/lib/dns/util/dns-over-tls.js new file mode 100644 index 0000000..8194f00 --- /dev/null +++ b/packages/mitmproxy/src/lib/dns/util/dns-over-tls.js @@ -0,0 +1,81 @@ +/** + * 由于组件 `dns-over-tls@0.0.9` 不支持 `rejectUnauthorized` 和 `timeout` 两个参数,所以将源码复制过来,并简化了代码。 + */ +const dnsPacket = require('dns-packet') +const tls_1 = require('node:tls') +const randi = require('random-int') + +const TWO_BYTES = 2 + +function getDnsQuery ({ type, name, klass, id }) { + return { + id, + type: 'query', + flags: dnsPacket.RECURSION_DESIRED, + questions: [{ class: klass, name, type }], + } +} + +function query ({ host, servername, type, name, klass, port, rejectUnauthorized, timeout }) { + return new Promise((resolve, reject) => { + if (!host || !servername || !name) { + throw new Error('At least host, servername and name must be set.') + } + + let response = Buffer.alloc(0) + let packetLength = 0 + const dnsQuery = getDnsQuery({ id: randi(0x0, 0xFFFF), type, name, klass }) + const dnsQueryBuf = dnsPacket.streamEncode(dnsQuery) + const socket = tls_1.connect({ host, port, servername, rejectUnauthorized, timeout }) + + // 超时处理 + let isFinished = false + let interval + if (timeout > 0) { + interval = setInterval(() => { + if (!isFinished) { + socket.destroy((...args) => { + console.info('socket destory callback args:', args) + }) + + reject(new Error('DNS查询超时')) + } + }, timeout) + } + + socket.on('secureConnect', () => socket.write(dnsQueryBuf)) + socket.on('data', (data) => { + if (timeout) { + isFinished = true + clearInterval(interval) + } + + if (response.length === 0) { + packetLength = data.readUInt16BE(0) + if (packetLength < 12) { + reject(new Error('Below DNS minimum packet length (DNS Header is 12 bytes)')) + } + response = Buffer.from(data) + } else { + response = Buffer.concat([response, data]) + } + + if (response.length === packetLength + TWO_BYTES) { + socket.destroy() + resolve(dnsPacket.streamDecode(response)) + } else { + reject(new Error('响应长度不正确')) + } + }) + socket.on('error', (err) => { + if (timeout) { + isFinished = true + clearInterval(interval) + } + reject(err) + }) + }) +} + +exports.query = query +exports.default = { query } diff --git a/packages/mitmproxy/test/dnsTest-abroad-doh-sni.mjs b/packages/mitmproxy/test/dnsTest-abroad-doh-sni.mjs index dec0da7..163bb1c 100644 --- a/packages/mitmproxy/test/dnsTest-abroad-doh-sni.mjs +++ b/packages/mitmproxy/test/dnsTest-abroad-doh-sni.mjs @@ -38,7 +38,7 @@ const hostnames = [ const sni = 'baidu.com' // const sni = '' -console.log(`\n--------------- 测试DoH的SNI功能:共 ${servers.length} 个服务,${hostnames.length} 个域名 ---------------\n`) +console.log(`\n--------------- 测试DoH的SNI功能:共 ${servers.length} 个服务,${hostnames.length} 个域名,SNI: ${sni || '无'} ---------------\n`) let n = 0 let success = 0 diff --git a/packages/mitmproxy/test/dnsTest-abroad-dot-sni.mjs b/packages/mitmproxy/test/dnsTest-abroad-dot-sni.mjs index 1868e16..c6cfddb 100644 --- a/packages/mitmproxy/test/dnsTest-abroad-dot-sni.mjs +++ b/packages/mitmproxy/test/dnsTest-abroad-dot-sni.mjs @@ -2,18 +2,50 @@ import DNSOverTLS from "../src/lib/dns/tls.js"; // 境外DNS的DoT配置sni测试 const servers = [ - '1dot1dot1dot1.cloudflare-dns.com', - 'cloudflare-dns.com', + // 'dot.360.cn', + + '1.1.1.1', // 可直连,无需SNI(有时候可以,有时候不行) 'one.one.one.one', - // '1.1.1.1', // 可直连,无需SNI + 'cloudflare-dns.com', + 'security.cloudflare-dns.com', + 'family.cloudflare-dns.com', + '1dot1dot1dot1.cloudflare-dns.com', 'dot.sb', '185.222.222.222', '45.11.45.11', 'dns.adguard.com', + 'dns.adguard-dns.com', 'dns-family.adguard.com', + 'family.adguard-dns.com', 'dns-unfiltered.adguard.com', + 'unfiltered.adguard-dns.com', + 'dns.bebasid.com', + 'unfiltered.dns.bebasid.com', + 'antivirus.bebasid.com', + 'internetsehat.bebasid.com', + 'family-adblock.bebasid.com', + 'oisd.dns.bebasid.com', + 'hagezi.dns.bebasid.com', + 'dns.cfiec.net', + 'dns.opendns.com', + 'familyshield.opendns.com', + 'sandbox.opendns.com', + 'family-filter-dns.cleanbrowsing.org', + 'adult-filter-dns.cleanbrowsing.org', + 'security-filter-dns.cleanbrowsing.org', + 'p0.freedns.controld.com', + 'p1.freedns.controld.com', + 'p2.freedns.controld.com', + 'p3.freedns.controld.com', + 'dns.decloudus.com', + 'getdnsapi.net', + 'dnsovertls.sinodun.com', + 'dnsovertls1.sinodun.com', + 'dns.de.futuredns.eu.org', + 'dns.us.futuredns.eu.org', + 'unicast.censurfridns.dk', ] const hostnames = [ @@ -23,7 +55,7 @@ const hostnames = [ const sni = 'baidu.com' // const sni = '' -console.log(`\n--------------- 测试DoT的SNI功能:共 ${servers.length} 个服务,${hostnames.length} 个域名 ---------------\n`) +console.log(`\n--------------- 测试DoT的SNI功能:共 ${servers.length} 个服务,${hostnames.length} 个域名,SNI: ${sni || '无'} ---------------\n`) let n = 0 let success = 0 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e46e3cc..6f06d8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,9 +169,6 @@ importers: dns-over-http: specifier: ^0.2.0 version: 0.2.0 - dns-over-tls: - specifier: ^0.0.9 - version: 0.0.9 is-browser: specifier: ^2.1.0 version: 2.1.0 @@ -3045,9 +3042,6 @@ packages: dns-over-http@0.2.0: resolution: {integrity: sha512-K+SyN2L3ljxJ2MFtOv/vRS+3/YEMLvOuH7MrmO5ejaubi4w02/DLqzoK1kBGKlQrT9ND57pbapeDf+ue8AElEA==} - dns-over-tls@0.0.9: - resolution: {integrity: sha512-IdI/Qgku2KQPLtUBsC6HDdK6bWIZADQMOYWtqJzRivV5Z+EDKIVAaC+tWE6lJ9vn11qj5L39ZaIaTj/14Lzgkw==} - dns-packet@4.2.0: resolution: {integrity: sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==} engines: {node: '>=4'} @@ -10553,10 +10547,6 @@ snapshots: transitivePeerDependencies: - supports-color - dns-over-tls@0.0.9: - dependencies: - dns-packet: 5.6.1 - dns-packet@4.2.0: dependencies: ip: 1.1.9