#69 KCP client now supports proxy chain
This commit is contained in:
parent
c1d7927257
commit
2dd7ace3ce
21
README.md
21
README.md
@ -38,25 +38,25 @@ scheme分为两部分: protocol+transport
|
|||||||
|
|
||||||
protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp), 二者可以任意组合,或单独使用:
|
protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp), 二者可以任意组合,或单独使用:
|
||||||
|
|
||||||
> http - 作为HTTP代理: http://:8080
|
> http - HTTP代理: http://:8080
|
||||||
|
|
||||||
> http+tls - 作为HTTPS代理(可能需要提供受信任的证书): http+tls://:443
|
> http+tls - HTTPS代理(可能需要提供受信任的证书): http+tls://:443或https://:443
|
||||||
|
|
||||||
> http2 - 作为HTTP2代理并向下兼容HTTPS代理: http2://:443
|
> http2 - HTTP2代理并向下兼容HTTPS代理: http2://:443
|
||||||
|
|
||||||
> socks - 作为标准SOCKS5代理(支持tls协商加密): socks://:1080
|
> socks - 标准SOCKS5代理(支持tls协商加密): socks://:1080
|
||||||
|
|
||||||
> socks+wss - 作为SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
> socks+wss - SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
||||||
|
|
||||||
> tls - 作为HTTPS/SOCKS5代理,使用tls传输数据: tls://:443
|
> tls - HTTPS/SOCKS5代理,使用tls传输数据: tls://:443
|
||||||
|
|
||||||
> ss - 作为Shadowsocks服务,ss://aes-256-cfb:123456@:8338
|
> ss - Shadowsocks代理,ss://aes-256-cfb:123456@:8338
|
||||||
|
|
||||||
> quic - 作为QUIC代理,quic://:6121
|
> quic - QUIC代理,quic://:6121
|
||||||
|
|
||||||
> kcp - 作为KCP代理,kcp://:8388或kcp://aes:123456@:8388
|
> kcp - KCP代理,kcp://:8388或kcp://aes:123456@:8388
|
||||||
|
|
||||||
> redirect - 作为透明代理,redirect://:12345
|
> redirect - 透明代理,redirect://:12345
|
||||||
|
|
||||||
#### 端口转发
|
#### 端口转发
|
||||||
|
|
||||||
@ -251,7 +251,6 @@ gost -L=kcp://:8388?c=/path/to/conf/file
|
|||||||
```
|
```
|
||||||
|
|
||||||
**注:** 客户端若要开启KCP转发,当且仅当代理链不为空且首个代理节点(第一个-F参数)为kcp类型。
|
**注:** 客户端若要开启KCP转发,当且仅当代理链不为空且首个代理节点(第一个-F参数)为kcp类型。
|
||||||
当KCP转发开启,代理链中的其他代理节点将被忽略。
|
|
||||||
|
|
||||||
#### 透明代理
|
#### 透明代理
|
||||||
基于iptables的透明代理。
|
基于iptables的透明代理。
|
||||||
|
@ -40,7 +40,7 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
|
|||||||
|
|
||||||
> http - standard HTTP proxy: http://:8080
|
> http - standard HTTP proxy: http://:8080
|
||||||
|
|
||||||
> http+tls - standard HTTPS proxy (may need to provide a trusted certificate): http+tls://:443
|
> http+tls - standard HTTPS proxy (may need to provide a trusted certificate): http+tls://:443 or https://:443
|
||||||
|
|
||||||
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
||||||
|
|
||||||
@ -253,7 +253,6 @@ gost -L=kcp://:8388?c=/path/to/conf/file
|
|||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** KCP will be enabled if and only if the proxy chain is not empty and the first proxy node (the first -F parameter) is of type KCP.
|
**NOTE:** KCP will be enabled if and only if the proxy chain is not empty and the first proxy node (the first -F parameter) is of type KCP.
|
||||||
When KCP is enabled, other proxy nodes are ignored.
|
|
||||||
|
|
||||||
#### Transparent proxy
|
#### Transparent proxy
|
||||||
Iptables-based transparent proxy
|
Iptables-based transparent proxy
|
||||||
|
73
chain.go
73
chain.go
@ -69,7 +69,7 @@ func (c *ProxyChain) SetNode(index int, node ProxyNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize the proxy chain.
|
// Init initialize the proxy chain.
|
||||||
// KCP will be enabled if the first proxy node is KCP proxy (transport == kcp), the remaining nodes are ignored.
|
// KCP will be enabled if the first proxy node is KCP proxy (transport == kcp).
|
||||||
// HTTP2 will be enabled when at least one HTTP2 proxy node (scheme == http2) is present.
|
// HTTP2 will be enabled when at least one HTTP2 proxy node (scheme == http2) is present.
|
||||||
//
|
//
|
||||||
// NOTE: Should be called immediately when proxy nodes are ready.
|
// NOTE: Should be called immediately when proxy nodes are ready.
|
||||||
@ -81,6 +81,26 @@ func (c *ProxyChain) Init() {
|
|||||||
|
|
||||||
c.lastNode = &c.nodes[length-1]
|
c.lastNode = &c.nodes[length-1]
|
||||||
|
|
||||||
|
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
|
||||||
|
for i, node := range c.nodes {
|
||||||
|
if node.Transport == "http2" {
|
||||||
|
glog.V(LINFO).Infoln("HTTP2 is enabled")
|
||||||
|
cfg := &tls.Config{
|
||||||
|
InsecureSkipVerify: node.insecureSkipVerify(),
|
||||||
|
ServerName: node.serverName,
|
||||||
|
}
|
||||||
|
c.http2NodeIndex = i
|
||||||
|
c.initHttp2Client(cfg, c.nodes[:i]...)
|
||||||
|
break // shortest chain for HTTP2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, node := range c.nodes {
|
||||||
|
if node.Transport == "kcp" && i > 0 {
|
||||||
|
glog.Fatal("KCP must be the first node in the proxy chain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.nodes[0].Transport == "kcp" {
|
if c.nodes[0].Transport == "kcp" {
|
||||||
glog.V(LINFO).Infoln("KCP is enabled")
|
glog.V(LINFO).Infoln("KCP is enabled")
|
||||||
c.kcpEnabled = true
|
c.kcpEnabled = true
|
||||||
@ -98,20 +118,6 @@ func (c *ProxyChain) Init() {
|
|||||||
c.kcpConfig = config
|
c.kcpConfig = config
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
|
|
||||||
for i, node := range c.nodes {
|
|
||||||
if node.Transport == "http2" {
|
|
||||||
glog.V(LINFO).Infoln("HTTP2 is enabled")
|
|
||||||
cfg := &tls.Config{
|
|
||||||
InsecureSkipVerify: node.insecureSkipVerify(),
|
|
||||||
ServerName: node.serverName,
|
|
||||||
}
|
|
||||||
c.http2NodeIndex = i
|
|
||||||
c.initHttp2Client(cfg, c.nodes[:i]...)
|
|
||||||
break // shortest chain for HTTP2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyChain) KCPEnabled() bool {
|
func (c *ProxyChain) KCPEnabled() bool {
|
||||||
@ -198,19 +204,6 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
|
|||||||
return nil, ErrEmptyChain
|
return nil, ErrEmptyChain
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.KCPEnabled() {
|
|
||||||
kcpConn, err := c.getKCPConn()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pc := NewProxyConn(kcpConn, c.nodes[0])
|
|
||||||
if err := pc.Handshake(); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return pc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Http2Enabled() {
|
if c.Http2Enabled() {
|
||||||
nodes = nodes[c.http2NodeIndex+1:]
|
nodes = nodes[c.http2NodeIndex+1:]
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
@ -243,23 +236,6 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
|
|||||||
return net.DialTimeout("tcp", addr, DialTimeout)
|
return net.DialTimeout("tcp", addr, DialTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.KCPEnabled() {
|
|
||||||
kcpConn, err := c.getKCPConn()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pc := NewProxyConn(kcpConn, nodes[0])
|
|
||||||
if err := pc.Handshake(); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := pc.Connect(addr); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return pc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if withHttp2 && c.Http2Enabled() {
|
if withHttp2 && c.Http2Enabled() {
|
||||||
nodes = nodes[c.http2NodeIndex+1:]
|
nodes = nodes[c.http2NodeIndex+1:]
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
@ -291,6 +267,8 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
|
|
||||||
if withHttp2 && c.Http2Enabled() {
|
if withHttp2 && c.Http2Enabled() {
|
||||||
cc, err = c.http2Connect(node.Addr)
|
cc, err = c.http2Connect(node.Addr)
|
||||||
|
} else if node.Transport == "kcp" {
|
||||||
|
cc, err = c.getKCPConn()
|
||||||
} else {
|
} else {
|
||||||
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
||||||
}
|
}
|
||||||
@ -300,19 +278,20 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
setKeepAlive(cc, KeepAliveTime)
|
setKeepAlive(cc, KeepAliveTime)
|
||||||
|
|
||||||
pc := NewProxyConn(cc, node)
|
pc := NewProxyConn(cc, node)
|
||||||
|
conn = pc
|
||||||
if err = pc.Handshake(); err != nil {
|
if err = pc.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = pc
|
|
||||||
for _, node := range nodes[1:] {
|
for _, node := range nodes[1:] {
|
||||||
if err = conn.Connect(node.Addr); err != nil {
|
if err = conn.Connect(node.Addr); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pc := NewProxyConn(conn, node)
|
pc := NewProxyConn(conn, node)
|
||||||
|
conn = pc
|
||||||
if err = pc.Handshake(); err != nil {
|
if err = pc.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = pc
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
71
cmd/gost/vendor/github.com/ginuerzh/gost/chain.go
generated
vendored
71
cmd/gost/vendor/github.com/ginuerzh/gost/chain.go
generated
vendored
@ -81,6 +81,26 @@ func (c *ProxyChain) Init() {
|
|||||||
|
|
||||||
c.lastNode = &c.nodes[length-1]
|
c.lastNode = &c.nodes[length-1]
|
||||||
|
|
||||||
|
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
|
||||||
|
for i, node := range c.nodes {
|
||||||
|
if node.Transport == "http2" {
|
||||||
|
glog.V(LINFO).Infoln("HTTP2 is enabled")
|
||||||
|
cfg := &tls.Config{
|
||||||
|
InsecureSkipVerify: node.insecureSkipVerify(),
|
||||||
|
ServerName: node.serverName,
|
||||||
|
}
|
||||||
|
c.http2NodeIndex = i
|
||||||
|
c.initHttp2Client(cfg, c.nodes[:i]...)
|
||||||
|
break // shortest chain for HTTP2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, node := range c.nodes {
|
||||||
|
if node.Transport == "kcp" && i > 0 {
|
||||||
|
glog.Fatal("KCP must be the first node in the proxy chain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.nodes[0].Transport == "kcp" {
|
if c.nodes[0].Transport == "kcp" {
|
||||||
glog.V(LINFO).Infoln("KCP is enabled")
|
glog.V(LINFO).Infoln("KCP is enabled")
|
||||||
c.kcpEnabled = true
|
c.kcpEnabled = true
|
||||||
@ -98,20 +118,6 @@ func (c *ProxyChain) Init() {
|
|||||||
c.kcpConfig = config
|
c.kcpConfig = config
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
|
|
||||||
for i, node := range c.nodes {
|
|
||||||
if node.Transport == "http2" {
|
|
||||||
glog.V(LINFO).Infoln("HTTP2 is enabled")
|
|
||||||
cfg := &tls.Config{
|
|
||||||
InsecureSkipVerify: node.insecureSkipVerify(),
|
|
||||||
ServerName: node.serverName,
|
|
||||||
}
|
|
||||||
c.http2NodeIndex = i
|
|
||||||
c.initHttp2Client(cfg, c.nodes[:i]...)
|
|
||||||
break // shortest chain for HTTP2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyChain) KCPEnabled() bool {
|
func (c *ProxyChain) KCPEnabled() bool {
|
||||||
@ -198,19 +204,6 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
|
|||||||
return nil, ErrEmptyChain
|
return nil, ErrEmptyChain
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.KCPEnabled() {
|
|
||||||
kcpConn, err := c.getKCPConn()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pc := NewProxyConn(kcpConn, c.nodes[0])
|
|
||||||
if err := pc.Handshake(); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return pc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Http2Enabled() {
|
if c.Http2Enabled() {
|
||||||
nodes = nodes[c.http2NodeIndex+1:]
|
nodes = nodes[c.http2NodeIndex+1:]
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
@ -243,23 +236,6 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
|
|||||||
return net.DialTimeout("tcp", addr, DialTimeout)
|
return net.DialTimeout("tcp", addr, DialTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.KCPEnabled() {
|
|
||||||
kcpConn, err := c.getKCPConn()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pc := NewProxyConn(kcpConn, nodes[0])
|
|
||||||
if err := pc.Handshake(); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := pc.Connect(addr); err != nil {
|
|
||||||
pc.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return pc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if withHttp2 && c.Http2Enabled() {
|
if withHttp2 && c.Http2Enabled() {
|
||||||
nodes = nodes[c.http2NodeIndex+1:]
|
nodes = nodes[c.http2NodeIndex+1:]
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
@ -291,6 +267,8 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
|
|
||||||
if withHttp2 && c.Http2Enabled() {
|
if withHttp2 && c.Http2Enabled() {
|
||||||
cc, err = c.http2Connect(node.Addr)
|
cc, err = c.http2Connect(node.Addr)
|
||||||
|
} else if node.Transport == "kcp" {
|
||||||
|
cc, err = c.getKCPConn()
|
||||||
} else {
|
} else {
|
||||||
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
||||||
}
|
}
|
||||||
@ -300,19 +278,20 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
setKeepAlive(cc, KeepAliveTime)
|
setKeepAlive(cc, KeepAliveTime)
|
||||||
|
|
||||||
pc := NewProxyConn(cc, node)
|
pc := NewProxyConn(cc, node)
|
||||||
|
conn = pc
|
||||||
if err = pc.Handshake(); err != nil {
|
if err = pc.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = pc
|
|
||||||
for _, node := range nodes[1:] {
|
for _, node := range nodes[1:] {
|
||||||
if err = conn.Connect(node.Addr); err != nil {
|
if err = conn.Connect(node.Addr); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pc := NewProxyConn(conn, node)
|
pc := NewProxyConn(conn, node)
|
||||||
|
conn = pc
|
||||||
if err = pc.Handshake(); err != nil {
|
if err = pc.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = pc
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
6
cmd/gost/vendor/vendor.json
vendored
6
cmd/gost/vendor/vendor.json
vendored
@ -15,10 +15,10 @@
|
|||||||
"revisionTime": "2017-01-19T05:34:58Z"
|
"revisionTime": "2017-01-19T05:34:58Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "g55EnuSESwa92RY7U+shNoPi900=",
|
"checksumSHA1": "oZV/w2ONwoM0nMDddIJQYDAZOPg=",
|
||||||
"path": "github.com/ginuerzh/gost",
|
"path": "github.com/ginuerzh/gost",
|
||||||
"revision": "0585749a819f33404f369650e74716cddf4ed3b7",
|
"revision": "c1d79272573ada276e5a4234774ea4c2e2b4e9ef",
|
||||||
"revisionTime": "2017-01-19T05:40:53Z"
|
"revisionTime": "2017-01-19T05:42:02Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
|
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
|
||||||
|
Loading…
Reference in New Issue
Block a user