bugfix: DoT的DNS,配置了SNI但未生效的问题修复

develop
王良 2025-05-16 18:10:05 +08:00
parent c18a6241d0
commit 217ce9d972
8 changed files with 124 additions and 19 deletions

View File

@ -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",

View File

@ -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`)

View File

@ -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,
})
}

View File

@ -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)

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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