From dfd2db5285d60a78d14dd978484df30c18c375f0 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 9 Nov 2020 00:54:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20dns=E4=BC=98=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/config/index.js | 2 +- packages/core/src/index.js | 2 +- .../core/src/modules/plugin/node/index.js | 1 + packages/core/src/modules/server/index.js | 4 +- packages/gui/src/background.js | 19 ++- packages/gui/src/bridge/index.js | 3 + packages/gui/src/view/event.js | 2 +- packages/gui/src/view/mixins/plugin.js | 20 ++-- packages/gui/src/view/pages/plugin/node.vue | 16 +-- packages/gui/src/view/pages/proxy.vue | 4 +- packages/gui/src/view/pages/server.vue | 26 ++++- packages/mitmproxy/src/lib/dns/base.js | 108 +++++++++++++++--- packages/mitmproxy/src/lib/dns/https.js | 13 ++- packages/mitmproxy/src/lib/dns/index.js | 1 - .../mitmproxy/src/lib/proxy/common/util.js | 6 +- .../proxy/mitmproxy/createConnectHandler.js | 10 +- packages/mitmproxy/test/dnsTest.js | 0 packages/mitmproxy/test/dnsTest.mjs | 23 ++++ 18 files changed, 205 insertions(+), 55 deletions(-) delete mode 100644 packages/mitmproxy/test/dnsTest.js create mode 100644 packages/mitmproxy/test/dnsTest.mjs diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index 4c9e3ec7..9c87c962 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -24,7 +24,7 @@ module.exports = { '.*': { proxy: 'raw.fastgit.org' } }, 'github.githubassets.com': { - '.*': { proxy: 'assets.fastgit.org' } + '.*': { proxy: 'assets.fastgit.org', test: 'https://github.githubassets.com/favicons/favicon.svg' } }, 'customer-stories-feed.github.com': { '.*': { proxy: 'customer-stories-feed.fastgit.org' } diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 90f43a5a..5e60f682 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -8,7 +8,7 @@ process.on('uncaughtException', function (err) { // console.error(err.errno) return } - console.error('uncaughtException',err) + console.error('uncaughtException', err) }) process.on('unhandledRejection', (reason, p) => { diff --git a/packages/core/src/modules/plugin/node/index.js b/packages/core/src/modules/plugin/node/index.js index e924c88b..8ec2fa9f 100644 --- a/packages/core/src/modules/plugin/node/index.js +++ b/packages/core/src/modules/plugin/node/index.js @@ -137,6 +137,7 @@ const NodePlugin = function (context) { ] const ret = await shell.exec(cmds, { type: 'cmd' }) event.fire('status', { key: 'plugin.node.enabled', value: false }) + console.info('关闭【NPM】代理成功') return ret } } diff --git a/packages/core/src/modules/server/index.js b/packages/core/src/modules/server/index.js index 653901f3..fbd01490 100644 --- a/packages/core/src/modules/server/index.js +++ b/packages/core/src/modules/server/index.js @@ -97,9 +97,9 @@ const serverApi = { } }) }, - async restart () { + async restart ({ mitmproxyPath }) { await serverApi.kill() - await serverApi.start() + await serverApi.start({ mitmproxyPath }) }, getServer () { return server diff --git a/packages/gui/src/background.js b/packages/gui/src/background.js index 954fbf55..72739947 100644 --- a/packages/gui/src/background.js +++ b/packages/gui/src/background.js @@ -35,7 +35,7 @@ function setTray (app) { } ] // 设置系统托盘图标 - const iconPath = path.join(__dirname, '../extra/favicon.ico') + const iconPath = path.join(__dirname, '../extra/icons/128x128.png') const appTray = new Tray(iconPath) // 图标的上下文菜单 @@ -44,14 +44,25 @@ function setTray (app) { // 设置托盘悬浮提示 appTray.setToolTip('DevSidecar-开发者边车辅助工具') - // 设置托盘菜单 - appTray.setContextMenu(contextMenu) - // 单击托盘小图标显示应用 appTray.on('click', () => { // 显示主程序 win.show() }) + + // 设置托盘菜单 + // appTray.setContextMenu(contextMenu) + + // appTray.on('double-click', function () { + // console.log('double click') + // win.show() + // }) + appTray.on('right-click', function (event, bounds) { + setTimeout(function () { + appTray.popUpContextMenu(contextMenu) + }, 200) + }) + return appTray } diff --git a/packages/gui/src/bridge/index.js b/packages/gui/src/bridge/index.js index d10aa8ea..236f0cf3 100644 --- a/packages/gui/src/bridge/index.js +++ b/packages/gui/src/bridge/index.js @@ -21,6 +21,9 @@ const localApi = { server: { start () { return DevSidecar.api.server.start({ mitmproxyPath }) + }, + restart () { + return DevSidecar.api.server.restart({ mitmproxyPath }) } }, config: { diff --git a/packages/gui/src/view/event.js b/packages/gui/src/view/event.js index 2eb4cfa0..18763240 100644 --- a/packages/gui/src/view/event.js +++ b/packages/gui/src/view/event.js @@ -22,7 +22,7 @@ function register (app) { } function handleServerStartError (err, app) { - if (err.message.indexOf('listen EADDRINUSE') >= 0) { + if (err.message && err.message.indexOf('listen EADDRINUSE') >= 0) { app.$confirm({ title: '端口被占用,代理服务启动失败', content: '是否要杀掉占用进程?', diff --git a/packages/gui/src/view/mixins/plugin.js b/packages/gui/src/view/mixins/plugin.js index a22fbda8..b5597c7d 100644 --- a/packages/gui/src/view/mixins/plugin.js +++ b/packages/gui/src/view/mixins/plugin.js @@ -10,7 +10,8 @@ export default { config: undefined, status: status, labelCol: { span: 4 }, - wrapperCol: { span: 20 } + wrapperCol: { span: 20 }, + applyLoading: false } }, created () { @@ -27,12 +28,17 @@ export default { } }) }, - apply () { - return this.saveConfig().then(() => { - if (this.applyAfter) { - return this.applyAfter() - } - }) + async apply () { + this.applyLoading = true + await this.applyBefore() + await this.saveConfig() + if (this.applyAfter) { + await this.applyAfter() + } + this.applyLoading = false + }, + async applyBefore () { + }, reloadDefault (key) { this.$api.config.resetDefault(key).then(ret => { diff --git a/packages/gui/src/view/pages/plugin/node.vue b/packages/gui/src/view/pages/plugin/node.vue index 36017be9..773aed35 100644 --- a/packages/gui/src/view/pages/plugin/node.vue +++ b/packages/gui/src/view/pages/plugin/node.vue @@ -59,8 +59,8 @@ @@ -91,13 +91,13 @@ export default { this.npmVariables = ret }) }, - onSwitchRegistry (event) { - return this.setRegistry(event.target.value).then(() => { - this.$message.success('切换成功') - }) + async onSwitchRegistry (event) { + await this.setRegistry(event.target.value) + this.$message.success('切换成功') }, - setRegistry (registry) { - return this.$api.plugin.node.setRegistry(registry) + async setRegistry (registry) { + this.apply() + await this.$api.plugin.node.setRegistry(registry) }, setNpmVariableAll () { this.saveConfig().then(() => { diff --git a/packages/gui/src/view/pages/proxy.vue b/packages/gui/src/view/pages/proxy.vue index d97f195c..d788a46d 100644 --- a/packages/gui/src/view/pages/proxy.vue +++ b/packages/gui/src/view/pages/proxy.vue @@ -21,8 +21,8 @@ diff --git a/packages/gui/src/view/pages/server.vue b/packages/gui/src/view/pages/server.vue index d4bd27f1..4ff2b689 100644 --- a/packages/gui/src/view/pages/server.vue +++ b/packages/gui/src/view/pages/server.vue @@ -69,8 +69,8 @@ @@ -109,8 +109,28 @@ export default { }) } }, - applyAfter () { + async applyBefore () { + const dnsMapping = {} + for (const item of this.dnsMappings) { + if (item.key) { + dnsMapping[item.key] = item.value + } + } + this.config.server.dns.mapping = dnsMapping + }, + async applyAfter () { + if (this.status.server.enabled) { + return this.$api.server.restart() + } + }, + deleteDnsMapping (item, index) { + this.dnsMappings.splice(index, 1) + }, + restoreDefDnsMapping (item, index) { + }, + addDnsMapping () { + this.dnsMappings.unshift({ key: '', value: 'usa' }) } } } diff --git a/packages/mitmproxy/src/lib/dns/base.js b/packages/mitmproxy/src/lib/dns/base.js index dc36080f..5a70932c 100644 --- a/packages/mitmproxy/src/lib/dns/base.js +++ b/packages/mitmproxy/src/lib/dns/base.js @@ -1,11 +1,72 @@ const LRU = require('lru-cache') -const { isIP } = require('validator') +// const { isIP } = require('validator') const getLogger = require('../utils/logger') const logger = getLogger('dns') const cacheSize = 1024 -function _isIP (v) { - return v && isIP(v) +// eslint-disable-next-line no-unused-vars +// function _isIP (v) { +// return v && isIP(v) +// } + +class IpCache { + constructor (hostname) { + this.hostname = hostname + this.count = {} + this.lookupCount = 0 + this.createTime = new Date() + } + + /** + * 获取到新的ipList + * @param ipList + */ + setIpList (ipList) { + this.ip = ipList.shift() + this.ipList = ipList + this.lookupCount++ + this.doCount(this.ip, false) + } + + /** + * 换下一个ip + * @param count + */ + changeNext (count) { + count.keepErrorCount = 0 // 清空连续失败 + if (this.ipList > 0) { + this.ip = this.ipList.shift() + } else { + this.ip = null + } + } + + /** + * 记录使用次数或错误次数 + * @param ip + * @param isError + */ + doCount (ip, isError) { + let count = this.count[ip] + if (count == null) { + count = this.count[ip] = { total: 0, error: 0, keepErrorCount: 0, successRate: 0 } + } + if (isError) { + count.error++ + count.keepErrorCount++ + } else { + count.total++ + } + count.successRate = 1 - (count.error / count.total) + if (isError && this.ip === ip) { + if (count.keepErrorCount >= 5) { + this.changeNext(count) + } + if (count.successRate < 0.51) { + this.changeNext(count) + } + } + } } module.exports = class BaseDNS { @@ -13,30 +74,39 @@ module.exports = class BaseDNS { this.cache = new LRU(cacheSize) } + count (hostname, ip, isError = true) { + const ipCache = this.cache.get(hostname) + if (ipCache) { + ipCache.doCount(ip, isError) + } + } + async lookup (hostname) { try { - let ip = this.cache.get(hostname) - if (ip) { - return ip + let ipCache = this.cache.get(hostname) + if (ipCache) { + if (ipCache.ip != null) { + ipCache.doCount(ipCache.ip, false) + return ipCache.ip + } + } else { + ipCache = new IpCache(hostname) + this.cache.set(hostname, ipCache) } const t = new Date() - - ip = hostname - for (let depth = 0; !_isIP(ip) && depth < 5; depth++) { - ip = await this._lookup(ip).catch(error => { - logger.debug(ip, error) - return ip - }) + let ipList = await this._lookup(hostname) + if (ipList == null) { + // 没有获取到ipv4地址 + ipList = [] } + ipList.push(hostname) // 把原域名加入到统计里去 - if (!_isIP(ip)) { - throw new Error(`BAD IP FORMAT (${ip})`) - } + ipCache.setIpList(ipList) - logger.debug(`[DNS] ${hostname} -> ${ip} (${new Date() - t} ms)`) - this.cache.set(hostname, ip) - return ip + logger.debug(`[DNS] ${hostname} -> ${ipCache.ip} (${new Date() - t} ms)`) + + return ipCache.ip } catch (error) { logger.debug(`[DNS] cannot resolve hostname ${hostname} (${error})`) return hostname diff --git a/packages/mitmproxy/src/lib/dns/https.js b/packages/mitmproxy/src/lib/dns/https.js index a516c080..a827b2d3 100644 --- a/packages/mitmproxy/src/lib/dns/https.js +++ b/packages/mitmproxy/src/lib/dns/https.js @@ -12,6 +12,17 @@ module.exports = class DNSOverHTTPS extends BaseDNS { async _lookup (hostname) { const result = await dohQueryAsync({ url: this.dnsServer }, [{ type: 'A', name: hostname }]) - return result.answers[0].data + if (result.answers.length === 0) { + // 说明没有获取到ip + console.log('该域名没有ip地址解析', hostname) + return [] + } + const ret = result.answers.filter(item => { return item.type === 'A' }).map(item => { return item.data }) + if (ret.length === 0) { + console.log('该域名没有ipv4地址解析', hostname) + } else { + console.log('获取到域名地址:', hostname, JSON.stringify(ret)) + } + return ret } } diff --git a/packages/mitmproxy/src/lib/dns/index.js b/packages/mitmproxy/src/lib/dns/index.js index 275aa23c..08bdbec1 100644 --- a/packages/mitmproxy/src/lib/dns/index.js +++ b/packages/mitmproxy/src/lib/dns/index.js @@ -23,7 +23,6 @@ module.exports = { } } if (providerName) { - console.log('匹配到dns:', providerName, hostname) return dnsConfig.providers[providerName] } } diff --git a/packages/mitmproxy/src/lib/proxy/common/util.js b/packages/mitmproxy/src/lib/proxy/common/util.js index 41bde449..0e6d9e38 100644 --- a/packages/mitmproxy/src/lib/proxy/common/util.js +++ b/packages/mitmproxy/src/lib/proxy/common/util.js @@ -6,13 +6,13 @@ const tunnelAgent = require('tunnel-agent') const util = exports const httpsAgent = new HttpsAgent({ keepAlive: true, - timeout: 5000, + timeout: 15000, keepAliveTimeout: 60000, // free socket keepalive for 30 seconds rejectUnauthorized: false }) const httpAgent = new Agent({ keepAlive: true, - timeout: 5000, + timeout: 15000, keepAliveTimeout: 60000 // free socket keepalive for 30 seconds }) let socketId = 0 @@ -34,7 +34,7 @@ util.getOptionsFormRequest = (req, ssl, externalProxy = null) => { try { externalProxyUrl = externalProxy(req, ssl) } catch (e) { - console.error('externalProxy',e) + console.error('externalProxy', e) } } } diff --git a/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js b/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js index 11f37e29..5f1194c9 100644 --- a/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js +++ b/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js @@ -21,7 +21,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, fakeServe const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname) if (dns) { dns.lookup(hostname).then(ip => { - connect(req, cltSocket, head, ip, srvUrl.port) + connect(req, cltSocket, head, ip, srvUrl.port, { dns, hostname, ip }) }) } } @@ -30,7 +30,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, fakeServe } } -function connect (req, cltSocket, head, hostname, port) { +function connect (req, cltSocket, head, hostname, port, isDnsIntercept) { // tunneling https // console.log('connect:', hostname, port) const start = new Date().getTime() @@ -57,6 +57,12 @@ function connect (req, cltSocket, head, hostname, port) { const end = new Date().getTime() console.error('代理连接失败:', e.message, hostname, port, (end - start) + 'ms') cltSocket.destroy() + + if (isDnsIntercept) { + const { dns, ip, hostname } = isDnsIntercept + dns.count(hostname, ip, true) + console.error('记录ip失败次数,用于优选ip:', hostname, ip) + } }) return proxySocket } catch (error) { diff --git a/packages/mitmproxy/test/dnsTest.js b/packages/mitmproxy/test/dnsTest.js deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/mitmproxy/test/dnsTest.mjs b/packages/mitmproxy/test/dnsTest.mjs new file mode 100644 index 00000000..28b67d60 --- /dev/null +++ b/packages/mitmproxy/test/dnsTest.mjs @@ -0,0 +1,23 @@ +import dns from '../src/lib/dns/index.js' + +const dnsProviders = dns.initDNS({ + aliyun: { + type: 'https', + server: 'https://dns.alidns.com/dns-query', + cacheSize: 1000 + }, + usa: { + type: 'https', + server: 'https://cloudflare-dns.com/dns-query', + cacheSize: 1000 + } +}) + +// let hostname = 'www.yonsz.com' +// dnsProviders.usa.lookup(hostname) + +// const hostname = 'api.github.com' +// dnsProviders.usa.lookup(hostname) + +const hostname1 = 'api.github.com' +dnsProviders.aliyun.lookup(hostname1)