Skip to content

Commit 7282098

Browse files
feature: 1)新增 UDPTCP 类型的DNS服务;2)修复 TLS 类型的DNS服务地址配置不生效的问题;3)删除 ipaddress 类型的DNS。
1 parent 982fa53 commit 7282098

File tree

15 files changed

+413
-213
lines changed

15 files changed

+413
-213
lines changed

packages/mitmproxy/src/lib/dns/base.js

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
const LRUCache = require('lru-cache')
22
const log = require('../../utils/util.log.server')
3+
const matchUtil = require('../../utils/util.match')
34
const { DynamicChoice } = require('../choice/index')
45

5-
const cacheSize = 1024
6+
function mapToList (ipMap) {
7+
const ipList = []
8+
for (const key in ipMap) {
9+
if (ipMap[key]) { // 配置为 ture 时才生效
10+
ipList.push(key)
11+
}
12+
}
13+
return ipList
14+
}
15+
16+
const defaultCacheSize = 1024
617

718
class IpCache extends DynamicChoice {
819
constructor (hostname) {
@@ -22,10 +33,12 @@ class IpCache extends DynamicChoice {
2233
}
2334

2435
module.exports = class BaseDNS {
25-
constructor (dnsName) {
36+
constructor (dnsName, dnsType, cacheSize, preSetIpList) {
2637
this.dnsName = dnsName
38+
this.dnsType = dnsType
39+
this.preSetIpList = preSetIpList
2740
this.cache = new LRUCache({
28-
maxSize: cacheSize,
41+
maxSize: (cacheSize > 0 ? cacheSize : defaultCacheSize),
2942
sizeCalculation: () => {
3043
return 1
3144
},
@@ -53,20 +66,63 @@ module.exports = class BaseDNS {
5366
}
5467

5568
const t = new Date()
56-
let ipList = await this._lookup(hostname)
69+
let ipList = await this._lookupInternal(hostname)
5770
if (ipList == null) {
5871
// 没有获取到ipv4地址
5972
ipList = []
6073
}
6174
ipList.push(hostname) // 把原域名加入到统计里去
6275

6376
ipCache.setBackupList(ipList)
64-
log.info(`[DNS '${this.dnsName}']: ${hostname}${ipCache.value} (${new Date() - t} ms), ipList: ${JSON.stringify(ipList)}, ipCache:`, JSON.stringify(ipCache))
77+
log.info(`[DNS-over-${this.dnsType} '${this.dnsName}'] ${hostname}${ipCache.value} (${new Date() - t} ms), ipList: ${JSON.stringify(ipList)}, ipCache:`, JSON.stringify(ipCache))
6578

6679
return ipCache.value
6780
} catch (error) {
68-
log.error(`[DNS '${this.dnsName}'] cannot resolve hostname ${hostname}, error:`, error)
81+
log.error(`[DNS-over-${this.dnsType} '${this.dnsName}'] cannot resolve hostname ${hostname}, error:`, error)
6982
return hostname
7083
}
7184
}
85+
86+
async _lookupInternal (hostname) {
87+
// 获取当前域名的预设IP列表
88+
let hostnamePreSetIpList = matchUtil.matchHostname(this.preSetIpList, hostname, `matched preSetIpList(${this.dnsName})`)
89+
if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) {
90+
if (hostnamePreSetIpList.length > 0) {
91+
hostnamePreSetIpList = hostnamePreSetIpList.slice()
92+
} else {
93+
hostnamePreSetIpList = mapToList(hostnamePreSetIpList)
94+
}
95+
96+
if (hostnamePreSetIpList.length > 0) {
97+
hostnamePreSetIpList.isPreSet = true
98+
log.info(`[DNS-over-${this.dnsType} '${this.dnsName}'] 获取到该域名的预设IP列表: ${hostname} - ${JSON.stringify(hostnamePreSetIpList)}`)
99+
return hostnamePreSetIpList
100+
}
101+
}
102+
103+
return await this._lookup(hostname)
104+
}
105+
106+
async _lookup (hostname) {
107+
const start = Date.now()
108+
try {
109+
const response = await this._doDnsQuery(hostname)
110+
const cost = Date.now() - start
111+
if (response == null || response.answers == null || response.answers.length == null || response.answers.length === 0) {
112+
// 说明没有获取到ip
113+
log.warn(`[DNS-over-${this.dnsType} '${this.dnsName}'] 没有该域名的IP地址: ${hostname}, cost: ${cost} ms, response:`, response)
114+
return []
115+
}
116+
const ret = response.answers.filter(item => item.type === 'A').map(item => item.data)
117+
if (ret.length === 0) {
118+
log.info(`[DNS-over-${this.dnsType} '${this.dnsName}'] 没有该域名的IPv4地址: ${hostname}, cost: ${cost} ms`)
119+
} else {
120+
log.info(`[DNS-over-${this.dnsType} '${this.dnsName}'] 获取到该域名的IPv4地址: ${hostname} - ${JSON.stringify(ret)}, cost: ${cost} ms`)
121+
}
122+
return ret
123+
} catch (e) {
124+
log.error(`[DNS-over-${this.dnsType} '${this.dnsName}'] DNS query error, hostname: ${hostname}${this.dnsServer ? `, dnsServer: ${this.dnsServer}` : ''}, cost: ${Date.now() - start} ms, error:`, e)
125+
return []
126+
}
127+
}
72128
}
Lines changed: 4 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,16 @@
11
const { promisify } = require('node:util')
22
const doh = require('dns-over-http')
3-
const log = require('../../utils/util.log.server')
4-
const matchUtil = require('../../utils/util.match')
53
const BaseDNS = require('./base')
64

75
const dohQueryAsync = promisify(doh.query)
86

9-
function mapToList (ipMap) {
10-
const ipList = []
11-
for (const key in ipMap) {
12-
if (ipMap[key]) { // 配置为 ture 时才生效
13-
ipList.push(key)
14-
}
15-
}
16-
return ipList
17-
}
18-
197
module.exports = class DNSOverHTTPS extends BaseDNS {
20-
constructor (dnsName, dnsServer, preSetIpList) {
21-
super(dnsName)
8+
constructor (dnsName, cacheSize, preSetIpList, dnsServer) {
9+
super(dnsName, 'HTTPS', cacheSize, preSetIpList)
2210
this.dnsServer = dnsServer
23-
this.preSetIpList = preSetIpList
2411
}
2512

26-
async _lookup (hostname) {
27-
// 获取当前域名的预设IP列表
28-
let hostnamePreSetIpList = matchUtil.matchHostname(this.preSetIpList, hostname, 'matched preSetIpList')
29-
if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) {
30-
if (hostnamePreSetIpList.length > 0) {
31-
hostnamePreSetIpList = hostnamePreSetIpList.slice()
32-
} else {
33-
hostnamePreSetIpList = mapToList(hostnamePreSetIpList)
34-
}
35-
36-
if (hostnamePreSetIpList.length > 0) {
37-
hostnamePreSetIpList.isPreSet = true
38-
return hostnamePreSetIpList
39-
}
40-
}
41-
42-
// 未预设当前域名的IP列表,则从dns服务器获取
43-
const start = new Date()
44-
try {
45-
const result = await dohQueryAsync({ url: this.dnsServer }, [{ type: 'A', name: hostname }])
46-
const cost = new Date() - start
47-
if (result.answers.length === 0) {
48-
// 说明没有获取到ip
49-
log.info(`DNS '${this.dnsName}' 没有该域名的IP地址: ${hostname}, cost: ${cost} ms`)
50-
return []
51-
}
52-
const ret = result.answers.filter(item => item.type === 'A').map(item => item.data)
53-
if (ret.length === 0) {
54-
log.info(`DNS '${this.dnsName}' 没有该域名的IPv4地址: ${hostname}, cost: ${cost} ms`)
55-
} else {
56-
log.info(`DNS '${this.dnsName}' 获取到该域名的IPv4地址: ${hostname} ${JSON.stringify(ret)}, cost: ${cost} ms`)
57-
}
58-
return ret
59-
} catch (e) {
60-
log.warn(`DNS query error: ${hostname}, dns: ${this.dnsName}, dnsServer: ${this.dnsServer}, cost: ${new Date() - start} ms, error:`, e)
61-
return []
62-
}
13+
async _doDnsQuery (hostname) {
14+
return await dohQueryAsync({ url: this.dnsServer }, [{ type: 'A', name: hostname }])
6315
}
6416
}

packages/mitmproxy/src/lib/dns/index.js

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const matchUtil = require('../../utils/util.match')
2-
const DNSOverHTTPS = require('./https.js')
3-
const DNSOverIpAddress = require('./ipaddress.js')
42
const DNSOverPreSetIpList = require('./preset.js')
3+
const DNSOverHTTPS = require('./https.js')
54
const DNSOverTLS = require('./tls.js')
5+
const DNSOverTCP = require('./tcp.js')
6+
const DNSOverUDP = require('./udp.js')
67

78
module.exports = {
89
initDNS (dnsProviders, preSetIpList) {
@@ -12,17 +13,65 @@ module.exports = {
1213
for (const provider in dnsProviders) {
1314
const conf = dnsProviders[provider]
1415

15-
if (conf.type === 'ipaddress') {
16-
dnsMap[provider] = new DNSOverIpAddress(provider)
17-
} else if (conf.type === 'https') {
18-
dnsMap[provider] = new DNSOverHTTPS(provider, conf.server, preSetIpList)
16+
// 获取DNS服务器
17+
let server = conf.server || conf.host
18+
if (server != null) {
19+
server = server.replace(/\s+/, '')
20+
}
21+
if (!server) {
22+
continue
23+
}
24+
25+
// 获取DNS类型
26+
let type = conf.type
27+
if (type == null) {
28+
if (server.startsWith('https://') || server.startsWith('http://')) {
29+
type = 'https'
30+
} else if (server.startsWith('tls://')) {
31+
type = 'tls'
32+
} else if (server.startsWith('tcp://')) {
33+
type = 'tcp'
34+
} else if (server.includes('://') && !server.startsWith('udp://')) {
35+
throw new Error(`Unknown type DNS: ${server}, provider: ${provider}`)
36+
} else {
37+
type = 'udp'
38+
}
1939
} else {
20-
dnsMap[provider] = new DNSOverTLS(provider)
40+
type = type.replace(/\s+/, '').toLowerCase()
2141
}
2242

23-
// 设置DNS名称到name属性中
24-
dnsMap[provider].name = provider
25-
dnsMap[provider].type = conf.type
43+
// 创建DNS对象
44+
if (type === 'https' || type === 'doh' || type === 'dns-over-https') {
45+
if (!server.includes('/')) {
46+
server = `https://${server}/dns-query`
47+
}
48+
49+
// 基于 https
50+
dnsMap[provider] = new DNSOverHTTPS(provider, conf.cacheSize, preSetIpList, server)
51+
} else {
52+
// 获取DNS端口
53+
let port = conf.port
54+
55+
// 处理带协议的DNS服务地址
56+
if (server.includes('://')) {
57+
server = server.split('://')[1]
58+
}
59+
// 处理带端口的DNS服务地址
60+
if (port == null && server.includes(':')) {
61+
[server, port] = server.split(':')
62+
}
63+
64+
if (type === 'tls' || type === 'dot' || type === 'dns-over-tls') {
65+
// 基于 tls
66+
dnsMap[provider] = new DNSOverTLS(provider, conf.cacheSize, preSetIpList, server, port, conf.servername)
67+
} else if (type === 'tcp' || type === 'dns-over-tcp') {
68+
// 基于 tcp
69+
dnsMap[provider] = new DNSOverTCP(provider, conf.cacheSize, preSetIpList, server, port)
70+
} else {
71+
// 基于 udp
72+
dnsMap[provider] = new DNSOverUDP(provider, conf.cacheSize, preSetIpList, server, port)
73+
}
74+
}
2675
}
2776

2877
// 创建预设IP的DNS
@@ -31,16 +80,14 @@ module.exports = {
3180
return dnsMap
3281
},
3382
hasDnsLookup (dnsConfig, hostname) {
34-
let providerName = null
35-
3683
// 先匹配 预设IP配置
37-
const hostnamePreSetIpList = matchUtil.matchHostname(dnsConfig.preSetIpList, hostname, 'matched preSetIpList')
84+
const hostnamePreSetIpList = matchUtil.matchHostname(dnsConfig.preSetIpList, hostname, 'matched preSetIpList(hasDnsLookup)')
3885
if (hostnamePreSetIpList) {
3986
return dnsConfig.dnsMap.PreSet
4087
}
4188

4289
// 再匹配 DNS映射配置
43-
providerName = matchUtil.matchHostname(dnsConfig.mapping, hostname, 'get dns providerName')
90+
const providerName = matchUtil.matchHostname(dnsConfig.mapping, hostname, 'get dns providerName')
4491

4592
// 由于DNS中的usa已重命名为cloudflare,所以做以下处理,为了向下兼容
4693
if (providerName === 'usa' && dnsConfig.dnsMap.usa == null && dnsConfig.dnsMap.cloudflare != null) {

packages/mitmproxy/src/lib/dns/ipaddress.js

Lines changed: 0 additions & 38 deletions
This file was deleted.

packages/mitmproxy/src/lib/dns/lookup.js

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,11 @@
1-
const matchUtil = require('../../utils/util.match')
21
const BaseDNS = require('./base')
32

4-
function mapToList (ipMap) {
5-
const ipList = []
6-
for (const key in ipMap) {
7-
if (ipMap[key]) { // 配置为 ture 时才生效
8-
ipList.push(key)
9-
}
10-
}
11-
return ipList
12-
}
13-
143
module.exports = class DNSOverPreSetIpList extends BaseDNS {
154
constructor (preSetIpList) {
16-
super()
17-
this.preSetIpList = preSetIpList
18-
this.name = 'PreSet'
19-
this.type = 'PreSet'
5+
super('PreSet', 'PreSet', null, preSetIpList)
206
}
217

22-
async _lookup (hostname) {
23-
// 获取当前域名的预设IP列表
24-
let hostnamePreSetIpList = matchUtil.matchHostname(this.preSetIpList, hostname, 'matched preSetIpList')
25-
if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) {
26-
if (hostnamePreSetIpList.length > 0) {
27-
hostnamePreSetIpList = hostnamePreSetIpList.slice()
28-
} else {
29-
hostnamePreSetIpList = mapToList(hostnamePreSetIpList)
30-
}
31-
32-
if (hostnamePreSetIpList.length > 0) {
33-
return hostnamePreSetIpList
34-
}
35-
}
36-
37-
// 未预设当前域名的IP列表
8+
async _lookup (_hostname) {
389
return []
3910
}
4011
}

0 commit comments

Comments
 (0)