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

pull/375/head
王良 2024-10-16 17:15:27 +08:00
parent 938ca58421
commit 5901a2e5d1
3 changed files with 116 additions and 95 deletions

View File

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

View File

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

View File

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