Browse Source

feature: 监听 `HTTP` 和 `HTTPS` 的端口分离,为了在 connect 阶段更好的判断协议

pull/375/head
王良 1 month ago
parent
commit
5901a2e5d1
  1. 20
      packages/core/src/shell/scripts/set-system-proxy/index.js
  2. 67
      packages/mitmproxy/src/index.js
  3. 116
      packages/mitmproxy/src/lib/proxy/mitmproxy/index.js

20
packages/core/src/shell/scripts/set-system-proxy/index.js

@ -224,7 +224,7 @@ async function _winSetProxy (exec, ip, port, setEnv) {
let proxyAddr = `https=http://${ip}:${port}`
// http
if (config.get().proxy.proxyHttp) {
proxyAddr = `http=http://${ip}:${port};` + proxyAddr
proxyAddr = `http=http://${ip}:${port - 1};` + proxyAddr
}
// 读取排除域名
@ -234,16 +234,18 @@ async function _winSetProxy (exec, ip, port, setEnv) {
await execFile(proxyPath, [execFun, proxyAddr, excludeIpStr])
if (setEnv) {
log.info(`开启系统代理的同时设置环境变量:HTTPS_PROXY = "http://${ip}:${port}/"`)
if (config.get().proxy.proxyHttp) {
log.info(`开启系统代理的同时设置环境变量:HTTP_PROXY = "http://${ip}:${port}/"`)
}
// 设置全局代理所需的环境变量
try {
await exec('echo \'设置环境变量 HTTPS_PROXY、HTTP_PROXY\'')
await exec(`echo '设置环境变量 HTTPS_PROXY${config.get().proxy.proxyHttp ? '、HTTP_PROXY' : ''}'`)
log.info(`开启系统代理的同时设置环境变量:HTTPS_PROXY = "http://${ip}:${port}/"`)
await exec(`setx HTTPS_PROXY "http://${ip}:${port}/"`)
if (config.get().proxy.proxyHttp) {
await exec(`setx HTTP_PROXY "http://${ip}:${port}/"`)
log.info(`开启系统代理的同时设置环境变量:HTTP_PROXY = "http://${ip}:${port - 1}/"`)
await exec(`setx HTTP_PROXY "http://${ip}:${port - 1}/"`)
}
// await addClearScriptIni()
} catch (e) {
log.error('设置环境变量 HTTPS_PROXY、HTTP_PROXY 失败:', e)
@ -279,7 +281,7 @@ const executor = {
// http
if (config.get().proxy.proxyHttp) {
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http host ${ip}`)
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port}`)
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port - 1}`)
} else {
setProxyCmd.push("gsettings set org.gnome.system.proxy.http host ''")
setProxyCmd.push('gsettings set org.gnome.system.proxy.http port 0')
@ -311,7 +313,7 @@ const executor = {
await exec(`networksetup -setsecurewebproxy "${wifiAdaptor}" ${ip} ${port}`)
// http
if (config.get().proxy.proxyHttp) {
await exec(`networksetup -setwebproxy "${wifiAdaptor}" ${ip} ${port}`)
await exec(`networksetup -setwebproxy "${wifiAdaptor}" ${ip} ${port - 1}`)
} else {
await exec(`networksetup -setwebproxystate "${wifiAdaptor}" off`)
}

67
packages/mitmproxy/src/index.js

@ -4,7 +4,7 @@ const proxyConfig = require('./lib/proxy/common/config')
const log = require('./utils/util.log')
const { fireError, fireStatus } = require('./utils/util.process')
const speedTest = require('./lib/speed/index.js')
let server
let servers = []
function registerProcessListener () {
process.on('message', function (msg) {
@ -64,44 +64,51 @@ const api = {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'
}
// log.info('启动代理服务时的配置:', JSON.stringify(proxyOptions, null, '\t'))
const newServer = mitmproxy.createProxy(proxyOptions, () => {
const newServers = mitmproxy.createProxy(proxyOptions, (server, port, host, ssl) => {
fireStatus(true)
log.info(`代理服务已启动:${proxyOptions.host}:${proxyOptions.port}`)
log.info(`代理服务已启动:${host}:${port}, ssl: ${ssl}`)
})
newServer.on('close', () => {
log.info('server will closed ')
if (server === newServer) {
server = null
fireStatus(false)
}
})
newServer.on('error', (e) => {
log.info('server error', e)
// newServer = null
fireError(e)
})
server = newServer
for (const newServer of newServers) {
newServer.on('close', () => {
log.info('server will closed ')
if (servers.includes(newServer)) {
servers = servers.filter(item => item !== newServer)
if (servers.length === 0) {
fireStatus(false)
}
}
})
newServer.on('error', (e) => {
log.info('server error', e)
// newServer = null
fireError(e)
})
}
servers = newServers
registerProcessListener()
},
async close () {
return new Promise((resolve, reject) => {
if (server) {
server.close((err) => {
if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') {
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
log.info('代理服务未运行,无需关闭')
resolve()
} else {
log.error('代理服务关闭失败:', err)
reject(err)
if (servers && servers.length > 0) {
for (const server of servers) {
server.close((err) => {
if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') {
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
log.info('代理服务未运行,无需关闭')
resolve()
} else {
log.error('代理服务关闭失败:', err)
reject(err)
}
return
}
return
}
log.info('代理服务关闭成功')
resolve()
})
log.info('代理服务关闭成功')
resolve()
})
}
servers = []
} else {
log.info('server is null, no need to close.')
fireStatus(false)

116
packages/mitmproxy/src/lib/proxy/mitmproxy/index.js

@ -20,7 +20,8 @@ module.exports = {
middlewares = [],
externalProxy,
dnsConfig,
setting
setting,
compatibleConfig
}, callback) {
// Don't reject unauthorized
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
@ -57,7 +58,8 @@ module.exports = {
middlewares,
externalProxy,
dnsConfig,
setting
setting,
compatibleConfig
)
const upgradeHandler = createUpgradeHandler(setting)
@ -75,65 +77,75 @@ module.exports = {
sslConnectInterceptor,
middlewares,
fakeServersCenter,
dnsConfig
dnsConfig,
compatibleConfig
)
const server = new http.Server()
server.listen(port, host, () => {
log.info(`dev-sidecar启动端口: ${host}:${port}`)
server.on('request', (req, res) => {
const ssl = false
log.debug('【server request】\r\n----- req -----\r\n', req, '\r\n----- res -----\r\n', res)
requestHandler(req, res, ssl)
})
// tunneling for https
server.on('connect', (req, cltSocket, head) => {
log.debug('【server connect】\r\n----- req -----\r\n', req, '\r\n----- cltSocket -----\r\n', cltSocket, '\r\n----- head -----\r\n', head)
connectHandler(req, cltSocket, head)
})
// TODO: handler WebSocket
server.on('upgrade', function (req, cltSocket, head) {
const ssl = false
log.debug('【server upgrade】\r\n----- req -----\r\n', req)
upgradeHandler(req, cltSocket, head, ssl)
})
server.on('error', (err) => {
log.error('【server error】\r\n----- error -----\r\n', err)
})
server.on('clientError', (err, cltSocket) => {
// log.error('【server clientError】\r\n----- error -----\r\n', err, '\r\n----- cltSocket -----\r\n', cltSocket)
log.error('【server clientError】\r\n', err)
cltSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
})
// 其他事件:仅记录debug日志
if (process.env.NODE_ENV === 'development') {
server.on('close', () => {
log.debug('【server close】no arguments...')
// 创建监听方法,用于监听 http 和 https 两个端口
const serverListen = (server, ssl, port, host) => {
server.listen(port, host, () => {
log.info(`dev-sidecar启动 ${ssl ? 'https' : 'http'} 端口: ${host}:${port}`)
server.on('request', (req, res) => {
log.debug(`【server request, ssl: ${ssl}\r\n----- req -----\r\n`, req, '\r\n----- res -----\r\n', res)
requestHandler(req, res, ssl)
})
server.on('connection', (cltSocket) => {
log.debug('【server connection】\r\n----- cltSocket -----\r\n', cltSocket)
// tunneling for https
server.on('connect', (req, cltSocket, head) => {
log.debug(`【server connect, ssl: ${ssl}\r\n----- req -----\r\n`, req, '\r\n----- cltSocket -----\r\n', cltSocket, '\r\n----- head -----\r\n', head)
connectHandler(req, cltSocket, head, ssl)
})
server.on('listening', () => {
log.debug('【server listening】no arguments...')
// TODO: handler WebSocket
server.on('upgrade', function (req, cltSocket, head) {
log.debug(`【server upgrade, ssl: ${ssl}\r\n----- req -----\r\n`, req)
upgradeHandler(req, cltSocket, head, ssl)
})
server.on('checkContinue', (req, res) => {
log.debug('【server checkContinue】\r\n----- req -----\r\n', req, '\r\n----- res -----\r\n', res)
server.on('error', (err) => {
log.error(`【server error, ssl: ${ssl}\r\n----- error -----\r\n`, err)
})
server.on('checkExpectation', (req, res) => {
log.debug('【server checkExpectation】\r\n----- req -----\r\n', req, '\r\n----- res -----\r\n', res)
server.on('clientError', (err, cltSocket) => {
// log.error(`【server clientError, ssl: ${ssl}】\r\n----- error -----\r\n`, err, '\r\n----- cltSocket -----\r\n', cltSocket)
log.error(`【server clientError, ssl: ${ssl}】socket.localPort = ${cltSocket.localPort}\r\n`, err)
cltSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
})
server.on('dropRequest', (req, cltSocket) => {
log.debug('【server checkExpectation】\r\n----- req -----\r\n', req, '\r\n----- cltSocket -----\r\n', cltSocket)
})
}
if (callback) {
callback(server)
}
})
// 其他事件:仅记录debug日志
if (process.env.NODE_ENV === 'development') {
server.on('close', () => {
log.debug(`【server close, ssl: ${ssl}】no arguments...`)
})
server.on('connection', (cltSocket) => {
log.debug(`【server connection, ssl: ${ssl}\r\n----- cltSocket -----\r\n`, cltSocket)
})
server.on('listening', () => {
log.debug(`【server listening, ssl: ${ssl}】no arguments...`)
})
server.on('checkContinue', (req, res) => {
log.debug(`【server checkContinue, ssl: ${ssl}\r\n----- req -----\r\n`, req, '\r\n----- res -----\r\n', res)
})
server.on('checkExpectation', (req, res) => {
log.debug(`【server checkExpectation, ssl: ${ssl}\r\n----- req -----\r\n`, req, '\r\n----- res -----\r\n', res)
})
server.on('dropRequest', (req, cltSocket) => {
log.debug(`【server checkExpectation, ssl: ${ssl}\r\n----- req -----\r\n`, req, '\r\n----- cltSocket -----\r\n', cltSocket)
})
}
if (callback) {
callback(server, port, host, ssl)
}
})
}
const httpsServer = new http.Server()
const httpServer = new http.Server()
// `http端口` 比 `https端口` 要小1
const httpsPort = port
const httpPort = port - 1
serverListen(httpsServer, true, httpsPort, host)
serverListen(httpServer, false, httpPort, host)
return server
return [httpsServer, httpServer]
},
createCA (caPaths) {
return tlsUtils.initCA(caPaths)

Loading…
Cancel
Save