optimize: 优化 `util.match.js`,简化配置,同时修复匹配错乱的问题。 (#279)
parent
cf4aa83bd1
commit
3b224a7252
|
@ -29,7 +29,7 @@ function _getConfigPath () {
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir)
|
fs.mkdirSync(dir)
|
||||||
}
|
}
|
||||||
return dir + '/config.json'
|
return path.join(dir, 'config.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
let timer
|
let timer
|
||||||
|
@ -43,7 +43,7 @@ const configApi = {
|
||||||
await configApi.downloadRemoteConfig()
|
await configApi.downloadRemoteConfig()
|
||||||
configApi.reload()
|
configApi.reload()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e)
|
log.error('定时下载远程配置并重载配置失败', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await download()
|
await download()
|
||||||
|
@ -56,10 +56,10 @@ const configApi = {
|
||||||
const remoteConfigUrl = get().app.remoteConfig.url
|
const remoteConfigUrl = get().app.remoteConfig.url
|
||||||
// eslint-disable-next-line handle-callback-err
|
// eslint-disable-next-line handle-callback-err
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
log.info('下载远程配置:', remoteConfigUrl)
|
log.info('开始下载远程配置:', remoteConfigUrl)
|
||||||
request(remoteConfigUrl, (error, response, body) => {
|
request(remoteConfigUrl, (error, response, body) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
log.error('下载远程配置失败', error)
|
log.error('下载远程配置失败, error:', error, ', response:', response, ', body:', body)
|
||||||
reject(error)
|
reject(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ const configApi = {
|
||||||
try {
|
try {
|
||||||
remoteConfig = JSON5.parse(body)
|
remoteConfig = JSON5.parse(body)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('远程配置内容格式不正确:', body)
|
log.error(`远程配置内容格式不正确, url: ${remoteConfigUrl}, body: ${body}`)
|
||||||
remoteConfig = null
|
remoteConfig = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +96,8 @@ const configApi = {
|
||||||
if (get().app.remoteConfig.enabled !== true) {
|
if (get().app.remoteConfig.enabled !== true) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
const path = _getRemoteSavePath()
|
||||||
try {
|
try {
|
||||||
const path = _getRemoteSavePath()
|
|
||||||
if (fs.existsSync(path)) {
|
if (fs.existsSync(path)) {
|
||||||
log.info('读取远程配置文件:', path)
|
log.info('读取远程配置文件:', path)
|
||||||
const file = fs.readFileSync(path)
|
const file = fs.readFileSync(path)
|
||||||
|
@ -106,7 +106,7 @@ const configApi = {
|
||||||
log.warn('远程配置文件不存在:', path)
|
log.warn('远程配置文件不存在:', path)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.warn('远程配置读取失败:', e)
|
log.warn('远程配置读取失败:', path, ', error:', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -229,17 +229,11 @@ module.exports = {
|
||||||
'*.cn': true,
|
'*.cn': true,
|
||||||
'cn.*': true,
|
'cn.*': true,
|
||||||
'*china*': true,
|
'*china*': true,
|
||||||
'dingtalk.com': true,
|
|
||||||
'*.dingtalk.com': true,
|
'*.dingtalk.com': true,
|
||||||
'apple.com': true,
|
|
||||||
'*.apple.com': true,
|
'*.apple.com': true,
|
||||||
'microsoft.com': true,
|
|
||||||
'*.microsoft.com': true,
|
'*.microsoft.com': true,
|
||||||
'alipay.com': true,
|
|
||||||
'*.alipay.com': true,
|
'*.alipay.com': true,
|
||||||
'qq.com': true,
|
|
||||||
'*.qq.com': true,
|
'*.qq.com': true,
|
||||||
'baidu.com': true,
|
|
||||||
'*.baidu.com': true
|
'*.baidu.com': true
|
||||||
},
|
},
|
||||||
sniList: {
|
sniList: {
|
||||||
|
@ -269,21 +263,24 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mapping: {
|
mapping: {
|
||||||
'*github*.com': 'quad9',
|
'*.github.com': 'quad9',
|
||||||
'*github.io': 'quad9',
|
'*.*github*.com': 'quad9',
|
||||||
'*stackoverflow.com': 'quad9',
|
'*.github.io': 'quad9',
|
||||||
|
'*.docker.com': 'quad9',
|
||||||
|
'*.docker*.com': 'quad9',
|
||||||
|
'*.stackoverflow.com': 'quad9',
|
||||||
'*.electronjs.org': 'quad9',
|
'*.electronjs.org': 'quad9',
|
||||||
'*amazonaws.com': 'quad9',
|
'*.amazonaws.com': 'quad9',
|
||||||
'*yarnpkg.com': 'quad9',
|
'*.yarnpkg.com': 'quad9',
|
||||||
'*cloudfront.net': 'quad9',
|
'*.cloudfront.net': 'quad9',
|
||||||
'*cloudflare.com': 'quad9',
|
'*.cloudflare.com': 'quad9',
|
||||||
'img.shields.io': 'quad9',
|
'img.shields.io': 'quad9',
|
||||||
'*.vuepress.vuejs.org': 'quad9',
|
'*.vuepress.vuejs.org': 'quad9',
|
||||||
'gh.docmirror.top': 'quad9',
|
'*.gh.docmirror.top': 'quad9',
|
||||||
'*v2ex.com': 'quad9',
|
'*.v2ex.com': 'quad9',
|
||||||
'*pypi.org': 'quad9',
|
'*.pypi.org': 'quad9',
|
||||||
'*jetbrains.com': 'quad9',
|
'*.jetbrains.com': 'quad9',
|
||||||
'*azureedge.net': 'quad9'
|
'*.azureedge.net': 'quad9'
|
||||||
},
|
},
|
||||||
speedTest: {
|
speedTest: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
|
@ -6,7 +6,7 @@ const NodePlugin = function (context) {
|
||||||
try {
|
try {
|
||||||
await nodeApi.setVariables()
|
await nodeApi.setVariables()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.warn('set variables error', err)
|
log.warn('set variables error:', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ip = '127.0.0.1'
|
const ip = '127.0.0.1'
|
||||||
|
|
|
@ -10,30 +10,31 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
targets: {
|
targets: {
|
||||||
|
'*.github.com': true,
|
||||||
'*github*.com': true,
|
'*github*.com': true,
|
||||||
'*wikimedia.org': true,
|
'*.wikimedia.org': true,
|
||||||
'v2ex.com': true,
|
'*.v2ex.com': true,
|
||||||
'*azureedge.net': true,
|
'*.azureedge.net': true,
|
||||||
'*cloudfront.net': true,
|
'*.cloudfront.net': true,
|
||||||
'*bing.com': true,
|
'*.bing.com': true,
|
||||||
'*discourse-cdn.com': true,
|
'*.discourse-cdn.com': true,
|
||||||
'*gravatar.com': true,
|
'*.gravatar.com': true,
|
||||||
'*docker.com': true,
|
'*.docker.com': true,
|
||||||
'*vueuse.org': true,
|
'*.vueuse.org': true,
|
||||||
'*elastic.co': true,
|
'*.elastic.co': true,
|
||||||
'*optimizely.com': true,
|
'*.optimizely.com': true,
|
||||||
'*stackpathcdn.com': true,
|
'*.stackpathcdn.com': true,
|
||||||
'*fastly.net': true,
|
'*.fastly.net': true,
|
||||||
'*cloudflare.com': true,
|
'*.cloudflare.com': true,
|
||||||
'*233v2.com': true,
|
'*.233v2.com': true,
|
||||||
'*v2fly.org': true,
|
'*.v2fly.org': true,
|
||||||
'*telegram.org': true,
|
'*.telegram.org': true,
|
||||||
'*amazon.com': true,
|
'*.amazon.com': true,
|
||||||
'*googleapis.com': true,
|
'*.googleapis.com': true,
|
||||||
'*.google-analytics.com': true,
|
'*.google-analytics.com': true,
|
||||||
'*cloudflareinsights.com': true,
|
'*.cloudflareinsights.com': true,
|
||||||
'*.intlify.dev': true,
|
'*.intlify.dev': true,
|
||||||
'*segment.io': true,
|
'*.segment.io': true,
|
||||||
'*.shields.io': true,
|
'*.shields.io': true,
|
||||||
'*.jsdelivr.net': true
|
'*.jsdelivr.net': true
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,7 @@ const ProxyPlugin = function (context) {
|
||||||
log.info('关闭系统代理成功')
|
log.info('关闭系统代理成功')
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('关闭系统代理失败', err)
|
log.error('关闭系统代理失败:', err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -86,16 +86,16 @@ const serverApi = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverProcess.on('beforeExit', (code) => {
|
serverProcess.on('beforeExit', (code) => {
|
||||||
log.warn('server process beforeExit', code)
|
log.warn('server process beforeExit, code:', code)
|
||||||
})
|
})
|
||||||
serverProcess.on('SIGPIPE', (code, signal) => {
|
serverProcess.on('SIGPIPE', (code, signal) => {
|
||||||
log.warn('server process SIGPIPE', code, signal)
|
log.warn(`server process SIGPIPE, code: ${code}, signal:`, signal)
|
||||||
})
|
})
|
||||||
serverProcess.on('exit', (code, signal) => {
|
serverProcess.on('exit', (code, signal) => {
|
||||||
log.warn('server process exit', code, signal)
|
log.warn(`server process exit, code: ${code}, signal:`, signal)
|
||||||
})
|
})
|
||||||
serverProcess.on('uncaughtException', (err, origin) => {
|
serverProcess.on('uncaughtException', (err, origin) => {
|
||||||
log.error('server process uncaughtException', err)
|
log.error('server process uncaughtException:', err)
|
||||||
})
|
})
|
||||||
serverProcess.on('message', function (msg) {
|
serverProcess.on('message', function (msg) {
|
||||||
log.info('收到子进程消息', msg.type, msg.event.key, msg.message)
|
log.info('收到子进程消息', msg.type, msg.event.key, msg.message)
|
||||||
|
@ -130,13 +130,13 @@ const serverApi = {
|
||||||
// fireStatus('ing')// 关闭中
|
// fireStatus('ing')// 关闭中
|
||||||
server.close((err) => {
|
server.close((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.warn('close error', err, ',', err.code, ',', err.message, ',', err.errno)
|
log.warn('close error:', err)
|
||||||
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
|
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
|
||||||
log.info('代理服务关闭成功')
|
log.info('代理服务关闭成功')
|
||||||
resolve()
|
resolve()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.warn('代理服务关闭失败', err)
|
log.warn('代理服务关闭失败:', err)
|
||||||
reject(err)
|
reject(err)
|
||||||
} else {
|
} else {
|
||||||
log.info('代理服务关闭成功')
|
log.info('代理服务关闭成功')
|
||||||
|
|
|
@ -3,7 +3,7 @@ const path = require('path')
|
||||||
|
|
||||||
function getExtraPath () {
|
function getExtraPath () {
|
||||||
let extraPath = process.env.DS_EXTRA_PATH
|
let extraPath = process.env.DS_EXTRA_PATH
|
||||||
log.info('extraPath', extraPath)
|
log.info('extraPath:', extraPath)
|
||||||
if (!extraPath) {
|
if (!extraPath) {
|
||||||
extraPath = __dirname
|
extraPath = __dirname
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,10 @@ async function _winSetProxy (exec, ip, port, setEnv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxyPath = extraPath.getProxyExePath()
|
const proxyPath = extraPath.getProxyExePath()
|
||||||
await execFile(proxyPath, ['global', `http=http://${ip}:${port};https=http://${ip}:${port}`, excludeIpStr])
|
const execFun = 'global'
|
||||||
|
const proxyAddr = `http=http://${ip}:${port};https=http://${ip}:${port}`
|
||||||
|
log.info(`执行“设置系统代理”的程序: ${proxyPath} ${execFun} ${proxyAddr} ......(省略排除IP列表)`)
|
||||||
|
await execFile(proxyPath, [execFun, proxyAddr, excludeIpStr])
|
||||||
|
|
||||||
if (setEnv) {
|
if (setEnv) {
|
||||||
log.info('同时设置 https_proxy')
|
log.info('同时设置 https_proxy')
|
||||||
|
@ -71,11 +74,11 @@ const executor = {
|
||||||
const { ip, port, setEnv } = params
|
const { ip, port, setEnv } = params
|
||||||
if (ip == null) {
|
if (ip == null) {
|
||||||
// 清空代理
|
// 清空代理
|
||||||
log.info('关闭代理')
|
log.info('关闭windows系统代理')
|
||||||
return _winUnsetProxy(exec, setEnv)
|
return _winUnsetProxy(exec, setEnv)
|
||||||
} else {
|
} else {
|
||||||
// 设置代理
|
// 设置代理
|
||||||
log.info('设置代理:', ip, port, setEnv)
|
log.info('设置windows系统代理:', ip, port, setEnv)
|
||||||
return _winSetProxy(exec, ip, port, setEnv)
|
return _winSetProxy(exec, ip, port, setEnv)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
const util = require('util')
|
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const childProcess = require('child_process')
|
const childProcess = require('child_process')
|
||||||
const _exec = childProcess.exec
|
|
||||||
const _execFile = childProcess.execFile
|
const _execFile = childProcess.execFile
|
||||||
const exec = util.promisify(_exec)
|
|
||||||
const PowerShell = require('node-powershell')
|
const PowerShell = require('node-powershell')
|
||||||
const log = require('../utils/util.log')
|
const log = require('../utils/util.log')
|
||||||
const fixPath = require('fix-path')
|
const fixPath = require('fix-path')
|
||||||
|
@ -96,8 +93,8 @@ function _childExec (composeCmds, options = {}) {
|
||||||
|
|
||||||
function childExec (composeCmds) {
|
function childExec (composeCmds) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var encoding = 'cp936'
|
const encoding = 'cp936'
|
||||||
var binaryEncoding = 'binary'
|
const binaryEncoding = 'binary'
|
||||||
|
|
||||||
const childProcess = require('child_process')
|
const childProcess = require('child_process')
|
||||||
log.info('shell:', composeCmds)
|
log.info('shell:', composeCmds)
|
||||||
|
|
|
@ -10,18 +10,18 @@
|
||||||
// }
|
// }
|
||||||
// )
|
// )
|
||||||
|
|
||||||
// var process = require('child_process')
|
// const process = require('child_process')
|
||||||
//
|
//
|
||||||
// var cmd = 'set'
|
// const cmd = 'set'
|
||||||
// process.exec(cmd, function (error, stdout, stderr) {
|
// process.exec(cmd, function (error, stdout, stderr) {
|
||||||
// console.log('error:' + error)
|
// console.log('error:' + error)
|
||||||
// console.log('stdout:' + stdout)
|
// console.log('stdout:' + stdout)
|
||||||
// console.log('stderr:' + stderr)
|
// console.log('stderr:' + stderr)
|
||||||
// })
|
// })
|
||||||
|
|
||||||
// var HttpsProxyAgent = require('https-proxy-agent')
|
// const HttpsProxyAgent = require('https-proxy-agent')
|
||||||
// var proxy = 'http://user:pass@xxx.com:port'
|
// const proxy = 'http://user:pass@xxx.com:port'
|
||||||
// var agent = new HttpsProxyAgent(proxy)
|
// const agent = new HttpsProxyAgent(proxy)
|
||||||
// const https = require('https')
|
// const https = require('https')
|
||||||
// https.get('https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js', (res) => {
|
// https.get('https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js', (res) => {
|
||||||
// console.log('状态码:', res.statusCode)
|
// console.log('状态码:', res.statusCode)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
const proxyConfig = require('@docmirror/mitmproxy/config.js')
|
|
||||||
module.exports = {
|
|
||||||
}
|
|
|
@ -81,7 +81,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setHeader('Dev-Sidecar-Cache-Response-Interceptor', 'cacheRes:maxAge=' + maxAge)
|
res.setHeader('Dev-Sidecar-Cache-Response-Interceptor', 'cacheRes:maxAge=' + maxAge)
|
||||||
log.info('[cacheRes]', 'maxAge=' + maxAge)
|
|
||||||
},
|
},
|
||||||
is (interceptOpt) {
|
is (interceptOpt) {
|
||||||
const maxAge = cacheReq.getMaxAge(interceptOpt)
|
const maxAge = cacheReq.getMaxAge(interceptOpt)
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
|
const lodash = require('lodash')
|
||||||
const pac = require('./source/pac')
|
const pac = require('./source/pac')
|
||||||
const matchUtil = require('../../../utils/util.match')
|
const matchUtil = require('../../../utils/util.match')
|
||||||
|
const log = require('../../../utils/util.log')
|
||||||
let pacClient = null
|
let pacClient = null
|
||||||
|
|
||||||
function matched (hostname, regexpMap) {
|
function matched (hostname, overWallTargetMap) {
|
||||||
const ret1 = matchUtil.matchHostname(regexpMap, hostname)
|
const ret1 = matchUtil.matchHostname(overWallTargetMap, hostname, 'matched overwall')
|
||||||
if (ret1) {
|
if (ret1) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -13,9 +15,12 @@ function matched (hostname, regexpMap) {
|
||||||
}
|
}
|
||||||
const ret = pacClient.FindProxyForURL('https://' + hostname, hostname)
|
const ret = pacClient.FindProxyForURL('https://' + hostname, hostname)
|
||||||
if (ret && ret.indexOf('PROXY ') === 0) {
|
if (ret && ret.indexOf('PROXY ') === 0) {
|
||||||
|
log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`)
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
// log.debug(`matchHostname: matched overwall: Not-Matched '${hostname}' -> '${ret}' in pac.txt`)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function createOverWallIntercept (overWallConfig) {
|
module.exports = function createOverWallIntercept (overWallConfig) {
|
||||||
|
@ -36,11 +41,11 @@ module.exports = function createOverWallIntercept (overWallConfig) {
|
||||||
if (keys.length === 0) {
|
if (keys.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const regexpMap = matchUtil.domainMapRegexply(overWallConfig.targets)
|
const overWallTargetMap = matchUtil.domainMapRegexply(overWallConfig.targets)
|
||||||
return {
|
return {
|
||||||
sslConnectInterceptor: (req, cltSocket, head) => {
|
sslConnectInterceptor: (req, cltSocket, head) => {
|
||||||
const hostname = req.url.split(':')[0]
|
const hostname = req.url.split(':')[0]
|
||||||
return matched(hostname, regexpMap)
|
return matched(hostname, overWallTargetMap)
|
||||||
},
|
},
|
||||||
requestIntercept (context, req, res, ssl, next) {
|
requestIntercept (context, req, res, ssl, next) {
|
||||||
const { rOptions, log, RequestCounter } = context
|
const { rOptions, log, RequestCounter } = context
|
||||||
|
@ -48,7 +53,7 @@ module.exports = function createOverWallIntercept (overWallConfig) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const hostname = rOptions.hostname
|
const hostname = rOptions.hostname
|
||||||
if (!matched(hostname, regexpMap)) {
|
if (!matched(hostname, overWallTargetMap)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const cacheKey = '__over_wall_proxy__'
|
const cacheKey = '__over_wall_proxy__'
|
||||||
|
@ -81,6 +86,9 @@ module.exports = function createOverWallIntercept (overWallConfig) {
|
||||||
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : (rOptions.protocol + '//' + proxyTarget)
|
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : (rOptions.protocol + '//' + proxyTarget)
|
||||||
// eslint-disable-next-line node/no-deprecated-api
|
// eslint-disable-next-line node/no-deprecated-api
|
||||||
const URL = url.parse(proxy)
|
const URL = url.parse(proxy)
|
||||||
|
rOptions.origional = lodash.cloneDeep(rOptions) // 备份原始请求参数
|
||||||
|
delete rOptions.origional.agent
|
||||||
|
delete rOptions.origional.headers
|
||||||
rOptions.protocol = URL.protocol
|
rOptions.protocol = URL.protocol
|
||||||
rOptions.hostname = URL.host
|
rOptions.hostname = URL.host
|
||||||
rOptions.host = URL.host
|
rOptions.host = URL.host
|
||||||
|
@ -92,7 +100,7 @@ module.exports = function createOverWallIntercept (overWallConfig) {
|
||||||
if (URL.port == null) {
|
if (URL.port == null) {
|
||||||
rOptions.port = port || (rOptions.protocol === 'https:' ? 443 : 80)
|
rOptions.port = port || (rOptions.protocol === 'https:' ? 443 : 80)
|
||||||
}
|
}
|
||||||
log.info('OverWall:', rOptions.hostname, proxyTarget)
|
log.info('OverWall:', rOptions.hostname, '➜', proxyTarget)
|
||||||
if (context.requestCount) {
|
if (context.requestCount) {
|
||||||
log.debug('OverWall choice:', JSON.stringify(context.requestCount))
|
log.debug('OverWall choice:', JSON.stringify(context.requestCount))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
const net = require('net')
|
const net = require('net')
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
const log = require('../../../utils/util.log')
|
const log = require('../../../utils/util.log')
|
||||||
// const colors = require('colors')
|
|
||||||
const DnsUtil = require('../../dns/index')
|
const DnsUtil = require('../../dns/index')
|
||||||
const localIP = '127.0.0.1'
|
const localIP = '127.0.0.1'
|
||||||
const defaultDns = require('dns')
|
const defaultDns = require('dns')
|
||||||
const matchUtil = require('../../../utils/util.match')
|
const matchUtil = require('../../../utils/util.match')
|
||||||
const speedTest = require('../../speed/index.js')
|
const speedTest = require('../../speed/index.js')
|
||||||
const sniExtract = require('../tls/sniUtil.js')
|
|
||||||
function isSslConnect (sslConnectInterceptors, req, cltSocket, head) {
|
function isSslConnect (sslConnectInterceptors, req, cltSocket, head) {
|
||||||
for (const intercept of sslConnectInterceptors) {
|
for (const intercept of sslConnectInterceptors) {
|
||||||
const ret = intercept(req, cltSocket, head)
|
const ret = intercept(req, cltSocket, head)
|
||||||
|
@ -57,7 +55,7 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig, sniRegexpMap)
|
||||||
// log.info('connect:', hostname, port)
|
// log.info('connect:', hostname, port)
|
||||||
const start = new Date().getTime()
|
const start = new Date().getTime()
|
||||||
let isDnsIntercept = null
|
let isDnsIntercept = null
|
||||||
// const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname)
|
// const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname, 'sni')
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
port,
|
port,
|
||||||
|
|
|
@ -24,17 +24,22 @@ module.exports = (config) => {
|
||||||
if (!overwallConfig.pac.pacFileAbsolutePath) {
|
if (!overwallConfig.pac.pacFileAbsolutePath) {
|
||||||
overwallConfig.pac.pacFileAbsolutePath = path.join(setting.rootDir, overwallConfig.pac.pacFilePath)
|
overwallConfig.pac.pacFileAbsolutePath = path.join(setting.rootDir, overwallConfig.pac.pacFilePath)
|
||||||
}
|
}
|
||||||
const overwallMiddleware = createOverwallMiddleware(overwallConfig)
|
|
||||||
|
// 插件列表
|
||||||
const middlewares = []
|
const middlewares = []
|
||||||
|
|
||||||
|
// 梯子插件:如果启用了,则添加到插件列表中
|
||||||
|
const overwallMiddleware = createOverwallMiddleware(overwallConfig)
|
||||||
if (overwallMiddleware) {
|
if (overwallMiddleware) {
|
||||||
middlewares.push(overwallMiddleware)
|
middlewares.push(overwallMiddleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
host: serverConfig.host,
|
host: serverConfig.host,
|
||||||
port: serverConfig.port,
|
port: serverConfig.port,
|
||||||
dnsConfig: {
|
dnsConfig: {
|
||||||
providers: dnsUtil.initDNS(serverConfig.dns.providers),
|
providers: dnsUtil.initDNS(serverConfig.dns.providers),
|
||||||
mapping: dnsMapping,
|
mapping: matchUtil.domainMapRegexply(dnsMapping),
|
||||||
speedTest: config.dns.speedTest
|
speedTest: config.dns.speedTest
|
||||||
},
|
},
|
||||||
setting,
|
setting,
|
||||||
|
@ -42,13 +47,13 @@ module.exports = (config) => {
|
||||||
middlewares,
|
middlewares,
|
||||||
sslConnectInterceptor: (req, cltSocket, head) => {
|
sslConnectInterceptor: (req, cltSocket, head) => {
|
||||||
const hostname = req.url.split(':')[0]
|
const hostname = req.url.split(':')[0]
|
||||||
const inWhiteList = matchUtil.matchHostname(whiteList, hostname) != null
|
const inWhiteList = matchUtil.matchHostname(whiteList, hostname, 'in whiteList') != null
|
||||||
if (inWhiteList) {
|
if (inWhiteList) {
|
||||||
log.info('白名单域名,不拦截', hostname)
|
log.info('白名单域名,不拦截', hostname)
|
||||||
return false // 所有都不拦截
|
return false // 所有都不拦截
|
||||||
}
|
}
|
||||||
// 配置了拦截的域名,将会被代理
|
// 配置了拦截的域名,将会被代理
|
||||||
const matched = !!matchUtil.matchHostname(intercepts, hostname)
|
const matched = !!matchUtil.matchHostname(intercepts, hostname, 'matched intercepts')
|
||||||
if (matched === true) {
|
if (matched === true) {
|
||||||
return matched // 拦截
|
return matched // 拦截
|
||||||
}
|
}
|
||||||
|
@ -57,7 +62,7 @@ module.exports = (config) => {
|
||||||
createIntercepts: (context) => {
|
createIntercepts: (context) => {
|
||||||
const rOptions = context.rOptions
|
const rOptions = context.rOptions
|
||||||
const hostname = rOptions.hostname
|
const hostname = rOptions.hostname
|
||||||
const interceptOpts = matchUtil.matchHostname(intercepts, hostname)
|
const interceptOpts = matchUtil.matchHostname(intercepts, hostname, 'get interceptOpts')
|
||||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,172 @@
|
||||||
const lodash = require('lodash')
|
const lodash = require('lodash')
|
||||||
|
const log = require('./util.log')
|
||||||
|
|
||||||
function isMatched (url, regexp) {
|
function isMatched (url, regexp) {
|
||||||
return url.match(regexp)
|
return url.match(regexp)
|
||||||
}
|
}
|
||||||
|
|
||||||
function domainRegexply (target) {
|
function domainRegexply (target) {
|
||||||
return target.replace(/\./g, '\\.').replace(/\*/g, '.*')
|
return '^' + target.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'
|
||||||
}
|
}
|
||||||
|
|
||||||
function domainMapRegexply (hostMap) {
|
function domainMapRegexply (hostMap) {
|
||||||
const regexpMap = {}
|
const regexpMap = {}
|
||||||
|
const origin = {} // 用于快速匹配,见matchHostname、matchHostnameAll方法
|
||||||
if (hostMap == null) {
|
if (hostMap == null) {
|
||||||
return regexpMap
|
return regexpMap
|
||||||
}
|
}
|
||||||
lodash.each(hostMap, (value, domain) => {
|
lodash.each(hostMap, (value, domain) => {
|
||||||
if (domain.indexOf('*') >= 0) {
|
if (domain.indexOf('*') >= 0 || domain[0] === '^') {
|
||||||
const regDomain = domainRegexply(domain)
|
const regDomain = domain[0] !== '^' ? domainRegexply(domain) : domain
|
||||||
regexpMap[regDomain] = value
|
regexpMap[regDomain] = value
|
||||||
|
|
||||||
|
if (domain.indexOf('*') === 0 && domain.lastIndexOf('*') === 0) {
|
||||||
|
origin[domain] = value
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
regexpMap[domain] = value
|
origin[domain] = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
regexpMap.origin = origin
|
||||||
return regexpMap
|
return regexpMap
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchHostname (hostMap, hostname) {
|
function matchHostname (hostMap, hostname, action) {
|
||||||
|
// log.error('matchHostname:', action, hostMap)
|
||||||
|
|
||||||
if (hostMap == null) {
|
if (hostMap == null) {
|
||||||
|
log.warn(`matchHostname: ${action}: '${hostname}' Not-Matched, hostMap is null`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const value = hostMap[hostname]
|
if (hostMap.origin == null) {
|
||||||
if (value) {
|
log.warn(`matchHostname: ${action}: '${hostname}' Not-Matched, hostMap.origin is null`)
|
||||||
return value
|
return null
|
||||||
}
|
}
|
||||||
if (!value) {
|
|
||||||
for (const target in hostMap) {
|
// 域名快速匹配:直接匹配 或者 两种前缀通配符匹配
|
||||||
if (target.indexOf('*') < 0) {
|
let value = hostMap.origin[hostname]
|
||||||
continue
|
if (value) {
|
||||||
}
|
log.info(`matchHostname: ${action}: '${hostname}' -> '${hostname}': ${JSON.stringify(value)}`)
|
||||||
// 正则表达式匹配
|
return value // 快速匹配成功
|
||||||
if (hostname.match(target)) {
|
}
|
||||||
return hostMap[target]
|
value = hostMap.origin['*' + hostname]
|
||||||
}
|
if (value) {
|
||||||
|
log.info(`matchHostname: ${action}: '${hostname}' -> '*${hostname}': ${JSON.stringify(value)}`)
|
||||||
|
return value // 快速匹配成功
|
||||||
|
}
|
||||||
|
value = hostMap.origin['*.' + hostname]
|
||||||
|
if (value) {
|
||||||
|
log.info(`matchHostname: ${action}: '${hostname}' -> '*.${hostname}': ${JSON.stringify(value)}`)
|
||||||
|
return value // 快速匹配成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通配符匹配 或 正则表达式匹配
|
||||||
|
for (const target in hostMap) {
|
||||||
|
if (target === 'origin') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (target.indexOf('*') < 0 && target[0] !== '^') {
|
||||||
|
// continue // 不是通配符匹配串,也不是正则表达式,跳过
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 如果是通配符匹配串,转换为正则表达式
|
||||||
|
let regexp = target
|
||||||
|
// if (target[0] !== '^') {
|
||||||
|
// regexp = domainRegexply(regexp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 正则表达式匹配
|
||||||
|
if (hostname.match(regexp)) {
|
||||||
|
value = hostMap[target]
|
||||||
|
log.info(`matchHostname: ${action}: '${hostname}' -> '${target}': ${JSON.stringify(value)}`)
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug(`matchHostname: ${action}: '${hostname}' Not-Matched`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function merge (oldObj, newObj) {
|
||||||
|
return lodash.mergeWith(oldObj, newObj, function (objValue, srcValue) {
|
||||||
|
if (lodash.isArray(objValue)) {
|
||||||
|
return srcValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchHostnameAll (hostMap, hostname, action) {
|
||||||
|
// log.debug('matchHostnameAll:', action, hostMap)
|
||||||
|
|
||||||
|
if (hostMap == null) {
|
||||||
|
log.warn(`matchHostnameAll: ${action}: '${hostname}', hostMap is null`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (hostMap.origin == null) {
|
||||||
|
log.warn(`matchHostnameAll: ${action}: '${hostname}', hostMap.origin is null`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
let values = {}
|
||||||
|
let hasValue = false
|
||||||
|
|
||||||
|
// 域名快速匹配:直接匹配 或者 两种前缀通配符匹配
|
||||||
|
let value = hostMap.origin[hostname]
|
||||||
|
if (value) {
|
||||||
|
log.info(`matchHostnameAll: ${action}: '${hostname}' -> '${hostname}': ${JSON.stringify(value)}`)
|
||||||
|
values = merge(values, value)
|
||||||
|
hasValue = true
|
||||||
|
}
|
||||||
|
value = hostMap.origin['*' + hostname]
|
||||||
|
if (value) {
|
||||||
|
log.info(`matchHostnameAll: ${action}: '${hostname}' -> '*${hostname}': ${JSON.stringify(value)}`)
|
||||||
|
values = merge(values, value)
|
||||||
|
hasValue = true
|
||||||
|
}
|
||||||
|
value = hostMap.origin['*.' + hostname]
|
||||||
|
if (value) {
|
||||||
|
log.info(`matchHostnameAll: ${action}: '${hostname}' -> '*.${hostname}': ${JSON.stringify(value)}`)
|
||||||
|
values = merge(values, value)
|
||||||
|
hasValue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通配符匹配 或 正则表达式匹配
|
||||||
|
for (const target in hostMap) {
|
||||||
|
if (target === 'origin') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (target.indexOf('*') < 0 && target[0] !== '^') {
|
||||||
|
// continue // 不是通配符匹配串,也不是正则表达式,跳过
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 如果是通配符匹配串,转换为正则表达式
|
||||||
|
let regexp = target
|
||||||
|
// if (target[0] !== '^') {
|
||||||
|
// regexp = domainRegexply(regexp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 正则表达式匹配
|
||||||
|
if (hostname.match(regexp)) {
|
||||||
|
value = hostMap[target]
|
||||||
|
// log.info(`matchHostname: ${action}: '${hostname}' -> '${target}': ${JSON.stringify(value)}`)
|
||||||
|
values = merge(values, value)
|
||||||
|
hasValue = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasValue) {
|
||||||
|
log.info(`*matchHostnameAll*: ${action}: '${hostname}':`, JSON.stringify(values))
|
||||||
|
return values
|
||||||
|
} else {
|
||||||
|
log.debug(`*matchHostnameAll*: ${action}: '${hostname}' Not-Matched`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isMatched,
|
isMatched,
|
||||||
domainRegexply,
|
domainRegexply,
|
||||||
domainMapRegexply,
|
domainMapRegexply,
|
||||||
matchHostname
|
matchHostname,
|
||||||
|
matchHostnameAll
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
// 警告:此文件不再使用,仅用于测试,可在 test/matchUtilTest.js 中比对新逻辑与旧逻辑的效果差异
|
||||||
|
|
||||||
|
const lodash = require('lodash')
|
||||||
|
function isMatched (url, regexp) {
|
||||||
|
return url.match(regexp)
|
||||||
|
}
|
||||||
|
|
||||||
|
function domainRegexply (target) {
|
||||||
|
return target.replace(/\./g, '\\.').replace(/\*/g, '.*')
|
||||||
|
}
|
||||||
|
|
||||||
|
function domainMapRegexply (hostMap) {
|
||||||
|
const regexpMap = {}
|
||||||
|
if (hostMap == null) {
|
||||||
|
return regexpMap
|
||||||
|
}
|
||||||
|
lodash.each(hostMap, (value, domain) => {
|
||||||
|
if (domain.indexOf('*') >= 0) {
|
||||||
|
const regDomain = domainRegexply(domain)
|
||||||
|
regexpMap[regDomain] = value
|
||||||
|
} else {
|
||||||
|
regexpMap[domain] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return regexpMap
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchHostname (hostMap, hostname) {
|
||||||
|
if (hostMap == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const value = hostMap[hostname]
|
||||||
|
if (value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (!value) {
|
||||||
|
for (const target in hostMap) {
|
||||||
|
if (target.indexOf('*') < 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 正则表达式匹配
|
||||||
|
if (hostname.match(target)) {
|
||||||
|
return hostMap[target]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = {
|
||||||
|
isMatched,
|
||||||
|
domainRegexply,
|
||||||
|
domainMapRegexply,
|
||||||
|
matchHostname
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
const matchUtil = require('../src/utils/util.match')
|
||||||
|
|
||||||
|
const hostMap = matchUtil.domainMapRegexply({
|
||||||
|
'aaa.com': true,
|
||||||
|
'*bbb.com': true,
|
||||||
|
'*.ccc.com': true,
|
||||||
|
'^.{1,3}ddd.com$': true,
|
||||||
|
'*.cn': true
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(hostMap)
|
||||||
|
|
||||||
|
console.log('test1: aaa.com')
|
||||||
|
const value11 = matchUtil.matchHostname(hostMap, 'aaa.com', 'test1.1')
|
||||||
|
const value12 = matchUtil.matchHostname(hostMap, 'aaaa.com', 'test1.2')
|
||||||
|
const value13 = matchUtil.matchHostname(hostMap, 'aaaa.comx', 'test1.3')
|
||||||
|
console.log(value11) // true
|
||||||
|
console.log(value12) // undefined
|
||||||
|
console.log(value13) // undefined
|
||||||
|
|
||||||
|
console.log('test2: *bbb.com')
|
||||||
|
const value21 = matchUtil.matchHostname(hostMap, 'bbb.com', 'test2.1')
|
||||||
|
const value22 = matchUtil.matchHostname(hostMap, 'xbbb.com', 'test2.2')
|
||||||
|
const value23 = matchUtil.matchHostname(hostMap, 'bbb.comx', 'test2.3')
|
||||||
|
const value24 = matchUtil.matchHostname(hostMap, 'x.bbb.com', 'test2.4')
|
||||||
|
console.log(value21) // true
|
||||||
|
console.log(value22) // true
|
||||||
|
console.log(value23) // undefined
|
||||||
|
console.log(value24) // true
|
||||||
|
|
||||||
|
console.log('test3: *.ccc.com')
|
||||||
|
const value31 = matchUtil.matchHostname(hostMap, 'ccc.com', 'test3.1')
|
||||||
|
const value32 = matchUtil.matchHostname(hostMap, 'x.ccc.com', 'test3.2')
|
||||||
|
const value33 = matchUtil.matchHostname(hostMap, 'xccc.com', 'test3.3')
|
||||||
|
console.log(value31) // true
|
||||||
|
console.log(value32) // true
|
||||||
|
console.log(value33) // undefined
|
||||||
|
|
||||||
|
console.log('test4: ^.{1,3}ddd.com$')
|
||||||
|
const value41 = matchUtil.matchHostname(hostMap, 'ddd.com', 'test4.1')
|
||||||
|
const value42 = matchUtil.matchHostname(hostMap, 'x.ddd.com', 'test4.2')
|
||||||
|
const value43 = matchUtil.matchHostname(hostMap, 'xddd.com', 'test4.3')
|
||||||
|
console.log(value41) // undefined
|
||||||
|
console.log(value42) // true
|
||||||
|
console.log(value43) // true
|
||||||
|
|
||||||
|
console.log('test5: *.cn')
|
||||||
|
const value51 = matchUtil.matchHostname(hostMap, 'eee.cn', 'test5.1')
|
||||||
|
const value52 = matchUtil.matchHostname(hostMap, 'x.eee.cn', 'test5.2')
|
||||||
|
const value53 = matchUtil.matchHostname(hostMap, 'aaaa.cnet.com', 'test5.3')
|
||||||
|
console.log(value51) // true
|
||||||
|
console.log(value52) // true
|
||||||
|
console.log(value53) // undefined
|
Loading…
Reference in New Issue