diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index e932fa01..3d9114b1 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -157,6 +157,9 @@ module.exports = { 'pay.weixin.qq.com': true, 'www.baidu.com': true }, + sniList: { + 'github.com': 'baidu.com' + }, dns: { providers: { aliyun: { diff --git a/packages/core/src/shell/scripts/set-system-proxy/index.js b/packages/core/src/shell/scripts/set-system-proxy/index.js index b09b3020..d593877f 100644 --- a/packages/core/src/shell/scripts/set-system-proxy/index.js +++ b/packages/core/src/shell/scripts/set-system-proxy/index.js @@ -122,7 +122,26 @@ const executor = { } }, async linux (exec, params) { - throw Error('暂未实现此功能') + if (params != null) { + const { ip, port } = params + // const local = 'localhost, 127.0.0.0/8, ::1' + + const setProxyCmd = [ + 'gsettings set org.gnome.system.proxy mode manual', + `gsettings set org.gnome.system.proxy.https port ${port}`, + `gsettings set org.gnome.system.proxy.https host ${ip}`, + `gsettings set org.gnome.system.proxy.http port ${port}`, + `gsettings set org.gnome.system.proxy.http host ${ip}` + // `gsettings set org.gnome.system.proxy ignore-hosts "${local}"` + ] + + await exec(setProxyCmd) + } else { + const setProxyCmd = [ + 'gsettings set org.gnome.system.proxy mode none' + ] + await exec(setProxyCmd) + } }, async mac (exec, params) { // exec = _exec diff --git a/packages/core/src/shell/scripts/setup-ca.js b/packages/core/src/shell/scripts/setup-ca.js index b283d6ca..4af30f42 100644 --- a/packages/core/src/shell/scripts/setup-ca.js +++ b/packages/core/src/shell/scripts/setup-ca.js @@ -8,9 +8,9 @@ const executor = { return true }, async linux (exec, { certPath }) { - const cmds = ['open "' + certPath + '"'] + const cmds = [`sudo cp ${certPath} /usr/local/share/ca-certificates`, 'sudo update-ca-certificates '] // eslint-disable-next-line no-unused-vars - const ret = await exec(cmds, { type: 'cmd' }) + const ret = await exec(cmds) return true }, async mac (exec, { certPath }) { diff --git a/packages/core/src/shell/shell.js b/packages/core/src/shell/shell.js index 73037337..80699c7d 100644 --- a/packages/core/src/shell/shell.js +++ b/packages/core/src/shell/shell.js @@ -21,7 +21,7 @@ class LinuxSystemShell extends SystemShell { cmds = [cmds] } for (const cmd of cmds) { - await childExec(cmd) + await _childExec(cmd, { shell: '/bin/bash' }) } } } @@ -33,7 +33,7 @@ class DarwinSystemShell extends SystemShell { } let ret for (const cmd of cmds) { - ret = await childExec(cmd) + ret = await _childExec(cmd) } return ret } @@ -76,13 +76,31 @@ class WindowsSystemShell extends SystemShell { } } +function _childExec (composeCmds, options = {}) { + return new Promise((resolve, reject) => { + const childProcess = require('child_process') + log.info('shell:', composeCmds) + childProcess.exec(composeCmds, options, function (error, stdout, stderr) { + if (error) { + log.error('cmd 命令执行错误:', composeCmds, stderr) + reject(new Error(stderr)) + } else { + // log.info('cmd 命令完成:', stdout) + resolve(stdout) + } + // log.info('关闭 cmd') + // ps.kill('SIGINT') + }) + }) +} + function childExec (composeCmds) { return new Promise((resolve, reject) => { - var encoding = 'cp936' var binaryEncoding = 'binary' const childProcess = require('child_process') + log.info('shell:', composeCmds) childProcess.exec(composeCmds, { encoding: binaryEncoding }, function (error, stdout, stderr) { if (error) { // console.log('------', decoder.decode(stderr)) @@ -120,6 +138,7 @@ function getSystemPlatform () { case 'linux': return 'linux' case 'win32': + return 'windows' case 'win64': return 'windows' case 'unknown os': diff --git a/packages/core/yarn.lock b/packages/core/yarn.lock index ea6eb7c6..5c88eb2e 100644 --- a/packages/core/yarn.lock +++ b/packages/core/yarn.lock @@ -93,10 +93,10 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@docmirror/mitmproxy@^1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@docmirror/mitmproxy/-/mitmproxy-1.5.0.tgz#16b9a956542a56f9889cd0c69c08a33d06d77ab8" - integrity sha512-H17TAqKmvzCMSTO6VGTC6kKQskjk1gEJZYsU2ijziZU0XEC96ObG0TWOnsdKh2PhmwDLwxS9cUyb1hpYilLreQ== +"@docmirror/mitmproxy@^1.5.1": + version "1.5.1" + resolved "https://registry.nlark.com/@docmirror/mitmproxy/download/@docmirror/mitmproxy-1.5.1.tgz#357142a41b89266491c3519a7528b9b83dc30c85" + integrity sha1-NXFCpBuJJmSRw1GadSi5uD3DDIU= dependencies: agentkeepalive "^2.1.1" axios "^0.21.1" diff --git a/packages/gui/package.json b/packages/gui/package.json index 131f3a14..13c7636f 100644 --- a/packages/gui/package.json +++ b/packages/gui/package.json @@ -79,4 +79,4 @@ ], "__npminstall_done": false, "gitHead": "3566cd6d33cbe782d91e408d6f174dd826b2790f" -} +} \ No newline at end of file diff --git a/packages/gui/public/setup-linux.png b/packages/gui/public/setup-linux.png new file mode 100755 index 00000000..64d49ed7 Binary files /dev/null and b/packages/gui/public/setup-linux.png differ diff --git a/packages/gui/src/background.js b/packages/gui/src/background.js index dec9ad6a..00b5d4fc 100644 --- a/packages/gui/src/background.js +++ b/packages/gui/src/background.js @@ -75,6 +75,21 @@ function setTray (app) { return appTray } +function isLinux () { + const platform = DevSidecar.api.shell.getSystemPlatform() + return platform === 'linux' +} + +function hideWin () { + if (win) { + if (isLinux()) { + win.minimize() + } else { + win.hide() + } + } +} + function createWindow () { // Create the browser window. @@ -113,7 +128,7 @@ function createWindow () { } if (startHideWindow) { - win.hide() + hideWin() } win.on('closed', async (e) => { @@ -124,7 +139,7 @@ function createWindow () { win.on('close', (e) => { if (!forceClose) { e.preventDefault() - win.hide() + hideWin() } }) } diff --git a/packages/gui/src/view/components/setup-ca.vue b/packages/gui/src/view/components/setup-ca.vue index 282f3845..a379fbf9 100644 --- a/packages/gui/src/view/components/setup-ca.vue +++ b/packages/gui/src/view/components/setup-ca.vue @@ -21,13 +21,16 @@ 2、然后按如下图步骤将随机生成的根证书设置为始终信任
3、可能需要重新启动应用和浏览器才能生效
+ - @@ -59,6 +62,8 @@ export default { setupImage () { if (this.systemPlatform === 'mac') { return '/setup-mac.png' + } else if (this.systemPlatform === 'linux') { + return '/setup-linux.png' } else { return '/setup.png' } @@ -75,6 +80,9 @@ export default { }, async doSetup () { this.$emit('setup') + if (this.systemPlatform === 'linux') { + this.$message.success('根证书已成功安装到系统证书库(注意:浏览器仍然需要手动安装)') + } } } } diff --git a/packages/gui/src/view/pages/server.vue b/packages/gui/src/view/pages/server.vue index f8877163..faa94808 100644 --- a/packages/gui/src/view/pages/server.vue +++ b/packages/gui/src/view/pages/server.vue @@ -80,11 +80,9 @@ -
-
这里配置哪些域名需要通过国外DNS服务器获取IP进行访问
@@ -110,10 +108,31 @@ @click="restoreDefDnsMapping(item,index)">
-
- + + + +
这里配置哪些域名要修改sni
+
+ + + +
+ + + + + + + + + + + + +
+
@@ -207,7 +226,8 @@ export default { wrapperCol: { span: 20 }, dnsMappings: [], speedTestList: [], - whiteList: [] + whiteList: [], + sniList: [] } }, created () { @@ -249,6 +269,7 @@ export default { ready () { this.initDnsMapping() this.initWhiteList() + this.initSniList() if (this.config.server.dns.speedTest.dnsProviders) { this.speedDns = this.config.server.dns.speedTest.dnsProviders } @@ -256,6 +277,7 @@ export default { async applyBefore () { this.submitDnsMapping() this.submitWhiteList() + this.submitSniList() }, async applyAfter () { if (this.status.server.enabled) { @@ -320,6 +342,35 @@ export default { this.whiteList.unshift({ key: '', value: true }) }, + // sniList + initSniList () { + this.sniList = [] + for (const key in this.config.server.sniList) { + const value = this.config.server.sniList[key] + this.sniList.push({ + key, value + }) + } + }, + submitSniList () { + const sniList = {} + for (const item of this.sniList) { + if (item.key) { + sniList[item.key] = item.value + } + } + this.config.server.sniList = sniList + }, + deleteSniList (item, index) { + this.sniList.splice(index, 1) + }, + restoreDefSniList (item, index) { + + }, + addSniList () { + this.sniList.unshift({ key: '', value: true }) + }, + async openLog () { const dir = await this.$api.info.getConfigDir() this.$api.ipc.openPath(dir + '/logs/') diff --git a/packages/gui/yarn.lock b/packages/gui/yarn.lock index 711b89fa..67400b4a 100644 --- a/packages/gui/yarn.lock +++ b/packages/gui/yarn.lock @@ -1507,10 +1507,10 @@ resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-14.11.8.tgz" integrity sha1-/iAS8jVeTOCLykSus6u7Ic+I0z8= -"@types/node@^12.0.12": - version "12.20.6" - resolved "https://registry.npmjs.org/@types/node/-/node-12.20.6.tgz" - integrity sha512-sRVq8d+ApGslmkE9e3i+D3gFGk7aZHAT+G4cIpIEdLJYPsWiSPwcAnJEjddLQQDqV3Ra2jOclX/Sv6YrvGYiWA== +"@types/node@^14.6.2": + version "14.17.9" + resolved "https://registry.nlark.com/@types/node/download/@types/node-14.17.9.tgz?cache=0&sync_timestamp=1628719497956&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.17.9.tgz#b97c057e6138adb7b720df2bd0264b03c9f504fd" + integrity sha1-uXwFfmE4rbe3IN8r0CZLA8n1BP0= "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -4651,13 +4651,13 @@ electron-updater@^4.3.5: lodash.isequal "^4.5.0" semver "^7.3.2" -electron@10.4.2: - version "10.4.2" - resolved "https://registry.nlark.com/electron/download/electron-10.4.2.tgz?cache=0&sync_timestamp=1620442447118&other_urls=https%3A%2F%2Fregistry.nlark.com%2Felectron%2Fdownload%2Felectron-10.4.2.tgz#2322a72f1e653e023250be91f3dd8d27662e3805" - integrity sha1-IyKnLx5lPgIyUL6R892NJ2YuOAU= +electron@^13.1.9: + version "13.1.9" + resolved "https://registry.nlark.com/electron/download/electron-13.1.9.tgz#668e2632b81e9fa21edfd32876282d3e2ff7fd76" + integrity sha1-Zo4mMrgen6Ie39ModigtPi/3/XY= dependencies: "@electron/get" "^1.0.1" - "@types/node" "^12.0.12" + "@types/node" "^14.6.2" extract-zip "^1.0.3" elliptic@^6.5.3: diff --git a/packages/mitmproxy/src/index.js b/packages/mitmproxy/src/index.js index aede43e9..010c9393 100644 --- a/packages/mitmproxy/src/index.js +++ b/packages/mitmproxy/src/index.js @@ -34,6 +34,10 @@ function registerProcessListener () { log.info('Unhandled Rejection at: Promise', p, 'err:', err) // application specific logging, throwing an error, or other logic here }) + + process.on('exit', function (code) { + log.info('代理服务进程被关闭:', code) + }) } const api = { diff --git a/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js b/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js index 53598371..514c61a2 100644 --- a/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js +++ b/packages/mitmproxy/src/lib/proxy/mitmproxy/createConnectHandler.js @@ -5,7 +5,7 @@ const log = require('../../../utils/util.log') const DnsUtil = require('../../dns/index') const localIP = '127.0.0.1' const defaultDns = require('dns') - +const matchUtil = require('../../../utils/util.match') const speedTest = require('../../speed/index.js') function isSslConnect (sslConnectInterceptors, req, cltSocket, head) { @@ -19,7 +19,7 @@ function isSslConnect (sslConnectInterceptors, req, cltSocket, head) { } // create connectHandler function -module.exports = function createConnectHandler (sslConnectInterceptor, middlewares, fakeServerCenter, dnsConfig) { +module.exports = function createConnectHandler (sslConnectInterceptor, middlewares, fakeServerCenter, dnsConfig, sniConfig) { // return const sslConnectInterceptors = [] sslConnectInterceptors.push(sslConnectInterceptor) @@ -28,6 +28,9 @@ module.exports = function createConnectHandler (sslConnectInterceptor, middlewar sslConnectInterceptors.push(middleware.sslConnectInterceptor) } } + + console.log('sni config', sniConfig) + const sniRegexpMap = matchUtil.domainMapRegexply(sniConfig) return function connectHandler (req, cltSocket, head) { // eslint-disable-next-line node/no-deprecated-api const srvUrl = url.parse(`https://${req.url}`) @@ -40,21 +43,28 @@ module.exports = function createConnectHandler (sslConnectInterceptor, middlewar log.error('getServerPromise', e) }) } else { - connect(req, cltSocket, head, hostname, srvUrl.port, dnsConfig) + connect(req, cltSocket, head, hostname, srvUrl.port, dnsConfig, sniRegexpMap) } } } -function connect (req, cltSocket, head, hostname, port, dnsConfig) { +function connect (req, cltSocket, head, hostname, port, dnsConfig, sniRegexpMap) { // tunneling https // log.info('connect:', hostname, port) const start = new Date().getTime() let isDnsIntercept = null + const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname) + console.log('replaceSni', replaceSni, sniRegexpMap) + let servername = null + if (replaceSni) { + servername = replaceSni + } try { const options = { port, host: hostname, - connectTimeout: 10000 + connectTimeout: 10000, + servername } if (dnsConfig) { const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname) diff --git a/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js b/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js index 0edb114d..933cfe08 100644 --- a/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js +++ b/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js @@ -21,7 +21,8 @@ module.exports = { middlewares = [], externalProxy, dnsConfig, - setting + setting, + sniConfig }, callback) { // Don't reject unauthorized // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' @@ -39,25 +40,6 @@ module.exports = { log.info(`CA private key saved in: ${caKeyPath}`) } - // function lookup (hostname, options, callback) { - // const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname) - // if (dns) { - // dns.lookup(hostname).then(ip => { - // // isDnsIntercept = { dns, hostname, ip } - // if (ip !== hostname) { - // log.info(`-----${hostname} use ip:${ip}-----`) - // callback(null, ip, 4) - // } else { - // defaultDns.lookup(hostname, options, callback) - // } - // }) - // } else { - // defaultDns.lookup(hostname, options, callback) - // } - // } - // - // https.globalAgent.lookup = lookup - port = ~~port const speedTestConfig = dnsConfig.speedTest @@ -95,7 +77,8 @@ module.exports = { sslConnectInterceptor, middlewares, fakeServersCenter, - dnsConfig + dnsConfig, + sniConfig ) const server = new http.Server() diff --git a/packages/mitmproxy/src/lib/proxy/tls/tlsUtils.js b/packages/mitmproxy/src/lib/proxy/tls/tlsUtils.js index 2d43ff2e..d0b42ede 100644 --- a/packages/mitmproxy/src/lib/proxy/tls/tlsUtils.js +++ b/packages/mitmproxy/src/lib/proxy/tls/tlsUtils.js @@ -51,11 +51,13 @@ utils.createCA = function (CN) { name: 'basicConstraints', critical: true, cA: true - }, { + }, + { name: 'keyUsage', critical: true, keyCertSign: true - }, { + }, + { name: 'subjectKeyIdentifier' }]) @@ -111,19 +113,19 @@ utils.createFakeCertificateByDomain = function (caKey, caCert, domain) { critical: true, cA: false }, - { - name: 'keyUsage', - critical: true, - digitalSignature: true, - contentCommitment: true, - keyEncipherment: true, - dataEncipherment: true, - keyAgreement: true, - keyCertSign: true, - cRLSign: true, - encipherOnly: true, - decipherOnly: true - }, + // { + // name: 'keyUsage', + // critical: true, + // digitalSignature: true, + // contentCommitment: true, + // keyEncipherment: true, + // dataEncipherment: true, + // keyAgreement: true, + // keyCertSign: true, + // cRLSign: true, + // encipherOnly: true, + // decipherOnly: true + // }, { name: 'subjectAltName', altNames: [{ diff --git a/packages/mitmproxy/src/options.js b/packages/mitmproxy/src/options.js index 3a532f28..7dcfd171 100644 --- a/packages/mitmproxy/src/options.js +++ b/packages/mitmproxy/src/options.js @@ -34,6 +34,7 @@ module.exports = (config) => { speedTest: config.dns.speedTest }, setting, + sniConfig: serverConfig.sniList, middlewares, sslConnectInterceptor: (req, cltSocket, head) => { const hostname = req.url.split(':')[0]