refactor: 优化dns选择
parent
6125895ae6
commit
02ab38c299
|
@ -1,8 +1,9 @@
|
||||||
# dev-sidecar
|
# dev-sidecar
|
||||||
开发者边车,命名取自service-mesh的service-sidecar,意为为开发者打辅助的边车工具
|
开发者边车,命名取自service-mesh的service-sidecar,意为为开发者打辅助的边车工具
|
||||||
通过本地代理的方式将请求代理到一些国内的加速通道上
|
通过本地代理的方式将http请求代理到一些国内的加速通道上
|
||||||
解决一些网站和库无法访问或访问速度慢的问题
|
解决一些网站和库无法访问或访问速度慢的问题
|
||||||
|
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
### 1、 github的release、source、zip下载加速
|
### 1、 github的release、source、zip下载加速
|
||||||
|
@ -144,6 +145,10 @@ const intercepts = {
|
||||||
注意:暂时只支持IPv4的解析
|
注意:暂时只支持IPv4的解析
|
||||||
|
|
||||||
## 感谢
|
## 感谢
|
||||||
|
本项目使用lerna包管理工具
|
||||||
|
|
||||||
|
[](https://lerna.js.org/)
|
||||||
|
|
||||||
本项目参考如下开源项目
|
本项目参考如下开源项目
|
||||||
* [node-mitmproxy](https://github.com/wuchangming/node-mitmproxy)
|
* [node-mitmproxy](https://github.com/wuchangming/node-mitmproxy)
|
||||||
* [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN)
|
* [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const start = require('./start/index.js')
|
|
@ -4,7 +4,7 @@ const fs = require('fs')
|
||||||
// 启动服务
|
// 启动服务
|
||||||
const mitmproxyPath = './start/mitmproxy'
|
const mitmproxyPath = './start/mitmproxy'
|
||||||
async function startup () {
|
async function startup () {
|
||||||
const banner = fs.readFileSync('./banner.txt')
|
const banner = fs.readFileSync('./start/banner.txt')
|
||||||
console.log(banner.toString())
|
console.log(banner.toString())
|
||||||
|
|
||||||
const configPath = './start/user_config.json5'
|
const configPath = './start/user_config.json5'
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
{
|
{
|
||||||
|
server: {
|
||||||
|
intercepts: {
|
||||||
|
'notify3.note.youdao.com': {
|
||||||
|
'/pushserver3/.*': {
|
||||||
|
abort: true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
plugin: {
|
plugin: {
|
||||||
node: {
|
node: {
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
||||||
console.log('abort:', rOptions.hostname, req.url)
|
console.log('abort:', rOptions.hostname, req.url)
|
||||||
req.destroy()
|
res.writeHead(403)
|
||||||
|
res.write('Dev-Sidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消')
|
||||||
|
res.end()
|
||||||
},
|
},
|
||||||
is (interceptOpt) {
|
is (interceptOpt) {
|
||||||
return !!interceptOpt.abort
|
return !!interceptOpt.abort
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
module.exports = {
|
module.exports = {
|
||||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
requestInterceptor (interceptOpt, rOptions, req, res, ssl, next) {
|
||||||
const proxy = interceptOpt.proxy.indexOf('http') === 0 ? interceptOpt.proxy : rOptions.protocol + '//' + interceptOpt.proxy
|
const proxyTarget = interceptOpt.proxy
|
||||||
|
// const backup = interceptOpt.backup
|
||||||
|
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.protocol = URL.protocol
|
rOptions.protocol = URL.protocol
|
||||||
|
@ -12,7 +14,7 @@ module.exports = {
|
||||||
rOptions.port = rOptions.protocol === 'https:' ? 443 : 80
|
rOptions.port = rOptions.protocol === 'https:' ? 443 : 80
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('proxy:', rOptions.hostname, req.url, interceptOpt.proxy)
|
console.log('proxy:', rOptions.hostname, req.url, proxyTarget)
|
||||||
},
|
},
|
||||||
is (interceptOpt) {
|
is (interceptOpt) {
|
||||||
return !!interceptOpt.proxy
|
return !!interceptOpt.proxy
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const proxy = require('./impl/proxy')
|
const proxy = require('./impl/proxy')
|
||||||
const redirect = require('./impl/redirect')
|
const redirect = require('./impl/redirect')
|
||||||
|
const abort = require('./impl/abort')
|
||||||
|
|
||||||
const modules = [proxy, redirect]
|
const modules = [proxy, redirect, abort]
|
||||||
|
|
||||||
module.exports = modules
|
module.exports = modules
|
||||||
|
|
|
@ -3,6 +3,7 @@ const url = require('url')
|
||||||
// const colors = require('colors')
|
// 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')
|
||||||
// create connectHandler function
|
// create connectHandler function
|
||||||
module.exports = function createConnectHandler (sslConnectInterceptor, fakeServerCenter, dnsConfig) {
|
module.exports = function createConnectHandler (sslConnectInterceptor, fakeServerCenter, dnsConfig) {
|
||||||
// return
|
// return
|
||||||
|
@ -17,25 +18,38 @@ module.exports = function createConnectHandler (sslConnectInterceptor, fakeServe
|
||||||
console.error('getServerPromise', e)
|
console.error('getServerPromise', e)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (dnsConfig) {
|
connect(req, cltSocket, head, hostname, srvUrl.port, dnsConfig)
|
||||||
const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname)
|
|
||||||
if (dns) {
|
|
||||||
dns.lookup(hostname).then(ip => {
|
|
||||||
connect(req, cltSocket, head, ip, srvUrl.port, { dns, hostname, ip })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
connect(req, cltSocket, head, hostname, srvUrl.port)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function connect (req, cltSocket, head, hostname, port, isDnsIntercept) {
|
function connect (req, cltSocket, head, hostname, port, dnsConfig) {
|
||||||
// tunneling https
|
// tunneling https
|
||||||
// console.log('connect:', hostname, port)
|
// console.log('connect:', hostname, port)
|
||||||
const start = new Date().getTime()
|
const start = new Date().getTime()
|
||||||
|
let isDnsIntercept = null
|
||||||
try {
|
try {
|
||||||
const proxySocket = net.connect({ port, host: hostname, connectTimeout: 5000 }, () => {
|
const options = {
|
||||||
|
port,
|
||||||
|
host: hostname,
|
||||||
|
connectTimeout: 10000
|
||||||
|
}
|
||||||
|
if (dnsConfig) {
|
||||||
|
const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname)
|
||||||
|
if (dns) {
|
||||||
|
options.lookup = (hostname, options, callback) => {
|
||||||
|
dns.lookup(hostname).then(ip => {
|
||||||
|
isDnsIntercept = { dns, hostname, ip }
|
||||||
|
if (ip !== hostname) {
|
||||||
|
callback(null, ip, 4)
|
||||||
|
} else {
|
||||||
|
defaultDns.lookup(hostname, options, callback)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const proxySocket = net.connect(options, () => {
|
||||||
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
|
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
|
||||||
'Proxy-agent: dev-sidecar\r\n' +
|
'Proxy-agent: dev-sidecar\r\n' +
|
||||||
'\r\n')
|
'\r\n')
|
||||||
|
|
|
@ -18,6 +18,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
} else {
|
} else {
|
||||||
req.socket.setKeepAlive(true, 30000)
|
req.socket.setKeepAlive(true, 30000)
|
||||||
}
|
}
|
||||||
|
const context = {}
|
||||||
|
|
||||||
const requestInterceptorPromise = () => {
|
const requestInterceptorPromise = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -26,7 +27,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (typeof requestInterceptor === 'function') {
|
if (typeof requestInterceptor === 'function') {
|
||||||
requestInterceptor(rOptions, req, res, ssl, next)
|
requestInterceptor(rOptions, req, res, ssl, next, context)
|
||||||
} else {
|
} else {
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
@ -82,15 +83,11 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
const end = new Date().getTime()
|
const end = new Date().getTime()
|
||||||
console.error('代理请求错误', e.errno, rOptions.hostname, rOptions.path, (end - start) + 'ms')
|
console.error('代理请求错误', e.errno, rOptions.hostname, rOptions.path, (end - start) + 'ms')
|
||||||
reject(e)
|
reject(e)
|
||||||
if (res) {
|
|
||||||
res.end()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
proxyReq.on('aborted', () => {
|
proxyReq.on('aborted', () => {
|
||||||
console.error('代理请求被取消', rOptions.hostname, rOptions.path)
|
console.error('代理请求被取消', rOptions.hostname, rOptions.path)
|
||||||
reject(new Error('代理请求被取消'))
|
reject(new Error('代理请求被取消'))
|
||||||
req.destroy()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
req.on('aborted', function () {
|
req.on('aborted', function () {
|
||||||
|
@ -101,9 +98,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
req.on('error', function (e, req, res) {
|
req.on('error', function (e, req, res) {
|
||||||
console.error('请求错误:', e.errno, rOptions.hostname, rOptions.path)
|
console.error('请求错误:', e.errno, rOptions.hostname, rOptions.path)
|
||||||
reject(e)
|
reject(e)
|
||||||
if (res) {
|
|
||||||
res.end()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
req.on('timeout', () => {
|
req.on('timeout', () => {
|
||||||
console.error('请求超时', rOptions.hostname, rOptions.path)
|
console.error('请求超时', rOptions.hostname, rOptions.path)
|
||||||
|
@ -130,7 +124,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (typeof responseInterceptor === 'function') {
|
if (typeof responseInterceptor === 'function') {
|
||||||
responseInterceptor(req, res, proxyReq, proxyRes, ssl, next)
|
responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, context)
|
||||||
} else {
|
} else {
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ module.exports = (config) => {
|
||||||
}
|
}
|
||||||
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
||||||
},
|
},
|
||||||
requestInterceptor: (rOptions, req, res, ssl, next) => {
|
requestInterceptor: (rOptions, req, res, ssl, next, context) => {
|
||||||
const hostname = rOptions.hostname
|
const hostname = rOptions.hostname
|
||||||
const interceptOpts = matchHostname(intercepts, hostname)
|
const interceptOpts = matchHostname(intercepts, hostname)
|
||||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
||||||
|
@ -83,7 +83,7 @@ module.exports = (config) => {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const result = interceptImpl.requestInterceptor(interceptOpt, rOptions, req, res, ssl)
|
const result = interceptImpl.requestInterceptor(interceptOpt, rOptions, req, res, ssl, context)
|
||||||
if (result) { // 拦截成功,其他拦截器就不处理了
|
if (result) { // 拦截成功,其他拦截器就不处理了
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ module.exports = (config) => {
|
||||||
}
|
}
|
||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
responseInterceptor: (req, res, proxyReq, proxyRes, ssl, next) => {
|
responseInterceptor: (req, res, proxyReq, proxyRes, ssl, next, context) => {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
const https = require('https')
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = https.get('https://api.github.com/', options, function (response) {
|
||||||
|
response.on('data', function (data) {
|
||||||
|
process.stdout.write(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
request.on('error', function (error) {
|
||||||
|
console.log(error)
|
||||||
|
})
|
Loading…
Reference in New Issue