pull/88/head
parent
a0812d4bbf
commit
cc46292cd9
|
@ -157,9 +157,9 @@ module.exports = {
|
||||||
'pay.weixin.qq.com': true,
|
'pay.weixin.qq.com': true,
|
||||||
'www.baidu.com': true
|
'www.baidu.com': true
|
||||||
},
|
},
|
||||||
sniList: {
|
// sniList: {
|
||||||
'github.com': 'baidu.com'
|
// 'github.com': 'abaidu.com'
|
||||||
},
|
// },
|
||||||
dns: {
|
dns: {
|
||||||
providers: {
|
providers: {
|
||||||
aliyun: {
|
aliyun: {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
const server = require('@docmirror/mitmproxy')
|
const server = require('@docmirror/mitmproxy')
|
||||||
const JSON5 = require('json5')
|
const JSON5 = require('json5')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const home = process.env.HOME
|
const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/xiaoj/'
|
||||||
let configPath = path.join(home, '.dev-sidecar/running.json')
|
let configPath = path.join(home, '.dev-sidecar/running.json')
|
||||||
if (process.argv && process.argv.length > 3) {
|
if (process.argv && process.argv.length > 3) {
|
||||||
configPath = process.argv[2]
|
configPath = process.argv[2]
|
||||||
|
@ -11,9 +11,9 @@ if (process.argv && process.argv.length > 3) {
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const configJson = fs.readFileSync(configPath)
|
const configJson = fs.readFileSync(configPath)
|
||||||
const config = JSON5.parse(configJson)
|
const config = JSON5.parse(configJson)
|
||||||
const scriptDir = '../../gui/extra/scripts/'
|
// const scriptDir = '../../gui/extra/scripts/'
|
||||||
config.setting.script.defaultDir = path.join(__dirname, scriptDir)
|
// config.setting.script.defaultDir = path.join(__dirname, scriptDir)
|
||||||
const pacFilePath = '../../gui/extra/pac/pac.txt'
|
// const pacFilePath = '../../gui/extra/pac/pac.txt'
|
||||||
config.plugin.overwall.pac.customPacFilePath = path.join(__dirname, pacFilePath)
|
// config.plugin.overwall.pac.customPacFilePath = path.join(__dirname, pacFilePath)
|
||||||
|
config.setting.rootDir = path.join(__dirname, '../../gui/')
|
||||||
server.start(config)
|
server.start(config)
|
||||||
|
|
|
@ -1,24 +1,31 @@
|
||||||
{
|
{
|
||||||
server: {
|
app: {
|
||||||
intercepts: {
|
autoStart: {
|
||||||
'github1.githubassets.com': {
|
enabled: true,
|
||||||
'.*': {
|
|
||||||
redirect: 'assets.fastgit.org',
|
|
||||||
test: 'https://github.githubassets.com/favicons/favicon.svg',
|
|
||||||
desc: '静态资源加速'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'github.githubassets.com': null,
|
|
||||||
'notify3.note.youdao.com': {
|
|
||||||
'/pushserver3/.*': {
|
|
||||||
abort: true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
mode: 'safe',
|
||||||
},
|
},
|
||||||
plugin: {
|
plugin: {
|
||||||
node: {
|
node: {
|
||||||
enabled: true
|
setting: {
|
||||||
}
|
yarnRegistry: null,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
git: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
overwall: {
|
||||||
|
targets: {
|
||||||
|
'*yonsz.net': true,
|
||||||
|
'*bootstrapcdn.com': true,
|
||||||
|
'*cloudflare.com': true,
|
||||||
|
'help.yonsz.net': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
intercept: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -110,28 +110,28 @@
|
||||||
</a-row>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="SNI" key="5">
|
<!-- <a-tab-pane tab="SNI" key="5">-->
|
||||||
<a-row style="margin-top:10px">
|
<!-- <a-row style="margin-top:10px">-->
|
||||||
<a-col span="19">
|
<!-- <a-col span="19">-->
|
||||||
<div>这里配置哪些域名要修改sni</div>
|
<!-- <div>这里配置哪些域名要修改sni</div>-->
|
||||||
</a-col>
|
<!-- </a-col>-->
|
||||||
<a-col span="3">
|
<!-- <a-col span="3">-->
|
||||||
<a-button style="margin-left:8px" type="primary" icon="plus" @click="addSniList()"/>
|
<!-- <a-button style="margin-left:8px" type="primary" icon="plus" @click="addSniList()"/>-->
|
||||||
</a-col>
|
<!-- </a-col>-->
|
||||||
</a-row>
|
<!-- </a-row>-->
|
||||||
<a-row :gutter="10" style="margin-top: 10px" v-for="(item,index) of sniList" :key='index'>
|
<!-- <a-row :gutter="10" style="margin-top: 10px" v-for="(item,index) of sniList" :key='index'>-->
|
||||||
<a-col :span="14">
|
<!-- <a-col :span="14">-->
|
||||||
<a-input v-model="item.key"></a-input>
|
<!-- <a-input v-model="item.key"></a-input>-->
|
||||||
</a-col>
|
<!-- </a-col>-->
|
||||||
<a-col :span="5">
|
<!-- <a-col :span="5">-->
|
||||||
<a-input v-model="item.value"></a-input>
|
<!-- <a-input v-model="item.value"></a-input>-->
|
||||||
</a-col>
|
<!-- </a-col>-->
|
||||||
<a-col :span="3">
|
<!-- <a-col :span="3">-->
|
||||||
<a-button type="danger" icon="minus" @click="deleteSniList(item,index)"/>
|
<!-- <a-button type="danger" icon="minus" @click="deleteSniList(item,index)"/>-->
|
||||||
</a-col>
|
<!-- </a-col>-->
|
||||||
</a-row>
|
<!-- </a-row>-->
|
||||||
|
|
||||||
</a-tab-pane>
|
<!-- </a-tab-pane>-->
|
||||||
<a-tab-pane tab="IP测速" key="6">
|
<a-tab-pane tab="IP测速" key="6">
|
||||||
<div>
|
<div>
|
||||||
<a-alert type="info" message="对从dns获取到的ip进行测速,使用速度最快的ip进行访问。(对使用增强功能的域名没啥用)"></a-alert>
|
<a-alert type="info" message="对从dns获取到的ip进行测速,使用速度最快的ip进行访问。(对使用增强功能的域名没啥用)"></a-alert>
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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)
|
||||||
|
@ -55,16 +55,11 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig, sniRegexpMap)
|
||||||
let isDnsIntercept = null
|
let isDnsIntercept = null
|
||||||
const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname)
|
const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname)
|
||||||
console.log('replaceSni', replaceSni, sniRegexpMap)
|
console.log('replaceSni', replaceSni, sniRegexpMap)
|
||||||
let servername = null
|
|
||||||
if (replaceSni) {
|
|
||||||
servername = replaceSni
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
port,
|
port,
|
||||||
host: hostname,
|
host: hostname,
|
||||||
connectTimeout: 10000,
|
connectTimeout: 10000
|
||||||
servername
|
|
||||||
}
|
}
|
||||||
if (dnsConfig) {
|
if (dnsConfig) {
|
||||||
const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname)
|
const dns = DnsUtil.hasDnsLookup(dnsConfig, hostname)
|
||||||
|
@ -100,6 +95,33 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig, sniRegexpMap)
|
||||||
proxySocket.pipe(cltSocket)
|
proxySocket.pipe(cltSocket)
|
||||||
|
|
||||||
cltSocket.pipe(proxySocket)
|
cltSocket.pipe(proxySocket)
|
||||||
|
// let sniReplaced = false
|
||||||
|
// cltSocket.on('data', (chunk) => {
|
||||||
|
// // if (replaceSni && sniReplaced === false) {
|
||||||
|
// // const sniPackage = sniExtract(chunk)
|
||||||
|
// // if (sniPackage != null) {
|
||||||
|
// // sniReplaced = true
|
||||||
|
// // const bytes = Buffer.from(replaceSni)
|
||||||
|
// // const start = sniPackage.start
|
||||||
|
// // const length = sniPackage.length
|
||||||
|
// // for (let i = 0; i < length; i++) {
|
||||||
|
// // let char = 97 // a 的ascii
|
||||||
|
// // if (bytes.length > i) {
|
||||||
|
// // char = bytes[i]
|
||||||
|
// // }
|
||||||
|
// // chunk[start + i] = char
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// if (sniReplaced === false) {
|
||||||
|
// sniReplaced = true
|
||||||
|
// chunk[chunk.length - 1] = 1
|
||||||
|
// }
|
||||||
|
// proxySocket.write(chunk)
|
||||||
|
// })
|
||||||
|
// cltSocket.on('end', () => {
|
||||||
|
// proxySocket.end()
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
|
|
||||||
cltSocket.on('error', (e) => {
|
cltSocket.on('error', (e) => {
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
module.exports = function extractSNI (data) {
|
||||||
|
/*
|
||||||
|
From https://tools.ietf.org/html/rfc5246:
|
||||||
|
enum {
|
||||||
|
hello_request(0), client_hello(1), server_hello(2),
|
||||||
|
certificate(11), server_key_exchange (12),
|
||||||
|
certificate_request(13), server_hello_done(14),
|
||||||
|
certificate_verify(15), client_key_exchange(16),
|
||||||
|
finished(20)
|
||||||
|
(255)
|
||||||
|
} HandshakeType;
|
||||||
|
struct {
|
||||||
|
HandshakeType msg_type;
|
||||||
|
uint24 length;
|
||||||
|
select (HandshakeType) {
|
||||||
|
case hello_request: HelloRequest;
|
||||||
|
case client_hello: ClientHello;
|
||||||
|
case server_hello: ServerHello;
|
||||||
|
case certificate: Certificate;
|
||||||
|
case server_key_exchange: ServerKeyExchange;
|
||||||
|
case certificate_request: CertificateRequest;
|
||||||
|
case server_hello_done: ServerHelloDone;
|
||||||
|
case certificate_verify: CertificateVerify;
|
||||||
|
case client_key_exchange: ClientKeyExchange;
|
||||||
|
case finished: Finished;
|
||||||
|
} body;
|
||||||
|
} Handshake;
|
||||||
|
struct {
|
||||||
|
uint8 major;
|
||||||
|
uint8 minor;
|
||||||
|
} ProtocolVersion;
|
||||||
|
struct {
|
||||||
|
uint32 gmt_unix_time;
|
||||||
|
opaque random_bytes[28];
|
||||||
|
} Random;
|
||||||
|
opaque SessionID<0..32>;
|
||||||
|
uint8 CipherSuite[2];
|
||||||
|
enum { null(0), (255) } CompressionMethod;
|
||||||
|
struct {
|
||||||
|
ProtocolVersion client_version;
|
||||||
|
Random random;
|
||||||
|
SessionID session_id;
|
||||||
|
CipherSuite cipher_suites<2..2^16-2>;
|
||||||
|
CompressionMethod compression_methods<1..2^8-1>;
|
||||||
|
select (extensions_present) {
|
||||||
|
case false:
|
||||||
|
struct {};
|
||||||
|
case true:
|
||||||
|
Extension extensions<0..2^16-1>;
|
||||||
|
};
|
||||||
|
} ClientHello;
|
||||||
|
*/
|
||||||
|
|
||||||
|
var end = data.length
|
||||||
|
|
||||||
|
// skip the record header
|
||||||
|
var pos = 5
|
||||||
|
|
||||||
|
// skip HandshakeType (you should already have verified this)
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
// skip handshake length
|
||||||
|
pos += 3
|
||||||
|
|
||||||
|
// skip protocol version (you should already have verified this)
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
// skip Random
|
||||||
|
pos += 32
|
||||||
|
|
||||||
|
// skip SessionID
|
||||||
|
if (pos > end - 1) return null
|
||||||
|
var sessionIdLength = data[pos]
|
||||||
|
pos += 1 + sessionIdLength
|
||||||
|
|
||||||
|
// skip CipherSuite
|
||||||
|
if (pos > end - 2) return null
|
||||||
|
var cipherSuiteLength = data[pos] << 8 | data[pos + 1]
|
||||||
|
pos += 2 + cipherSuiteLength
|
||||||
|
|
||||||
|
// skip CompressionMethod
|
||||||
|
if (pos > end - 1) return null
|
||||||
|
var compressionMethodLength = data[pos]
|
||||||
|
pos += 1 + compressionMethodLength
|
||||||
|
|
||||||
|
// verify extensions exist
|
||||||
|
if (pos > end - 2) return null
|
||||||
|
var extensionsLength = data[pos] << 8 | data[pos + 1]
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
// verify the extensions fit
|
||||||
|
var extensionsEnd = pos + extensionsLength
|
||||||
|
if (extensionsEnd > end) return null
|
||||||
|
end = extensionsEnd
|
||||||
|
|
||||||
|
/*
|
||||||
|
From https://tools.ietf.org/html/rfc5246
|
||||||
|
and http://tools.ietf.org/html/rfc6066:
|
||||||
|
struct {
|
||||||
|
ExtensionType extension_type;
|
||||||
|
opaque extension_data<0..2^16-1>;
|
||||||
|
} Extension;
|
||||||
|
enum {
|
||||||
|
signature_algorithms(13), (65535)
|
||||||
|
} ExtensionType;
|
||||||
|
enum {
|
||||||
|
server_name(0), max_fragment_length(1),
|
||||||
|
client_certificate_url(2), trusted_ca_keys(3),
|
||||||
|
truncated_hmac(4), status_request(5), (65535)
|
||||||
|
} ExtensionType;
|
||||||
|
struct {
|
||||||
|
NameType name_type;
|
||||||
|
select (name_type) {
|
||||||
|
case host_name: HostName;
|
||||||
|
} name;
|
||||||
|
} ServerName;
|
||||||
|
enum {
|
||||||
|
host_name(0), (255)
|
||||||
|
} NameType;
|
||||||
|
opaque HostName<1..2^16-1>;
|
||||||
|
struct {
|
||||||
|
ServerName server_name_list<1..2^16-1>
|
||||||
|
} ServerNameList;
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (pos <= end - 4) {
|
||||||
|
var extensionType = data[pos] << 8 | data[pos + 1]
|
||||||
|
var extensionSize = data[pos + 2] << 8 | data[pos + 3]
|
||||||
|
pos += 4
|
||||||
|
if (extensionType === 0) { // ExtensionType was server_name(0)
|
||||||
|
// read ServerNameList length
|
||||||
|
if (pos > end - 2) return null
|
||||||
|
var nameListLength = data[pos] << 8 | data[pos + 1]
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
// verify we have enough bytes and loop over SeverNameList
|
||||||
|
var n = pos
|
||||||
|
pos += nameListLength
|
||||||
|
if (pos > end) return null
|
||||||
|
while (n < pos - 3) {
|
||||||
|
var nameType = data[n]
|
||||||
|
var nameLength = data[n + 1] << 8 | data[n + 2]
|
||||||
|
n += 3
|
||||||
|
|
||||||
|
// check if NameType is host_name(0)
|
||||||
|
if (nameType === 0) {
|
||||||
|
// verify we have enough bytes
|
||||||
|
if (n > end - nameLength) return null
|
||||||
|
|
||||||
|
// decode as ascii and return
|
||||||
|
|
||||||
|
const sniName = data.toString('ascii', n, n + nameLength)
|
||||||
|
return {
|
||||||
|
sniName,
|
||||||
|
start: n,
|
||||||
|
end: n + nameLength,
|
||||||
|
length: nameLength
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n += nameLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // ExtensionType was something we are not interested in
|
||||||
|
pos += extensionSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
|
@ -24,6 +24,9 @@ function domainMapRegexply (hostMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchHostname (hostMap, hostname) {
|
function matchHostname (hostMap, hostname) {
|
||||||
|
if (hostMap == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
const value = hostMap[hostname]
|
const value = hostMap[hostname]
|
||||||
if (value) {
|
if (value) {
|
||||||
return value
|
return value
|
||||||
|
|
Loading…
Reference in New Issue