#69 KCP client now supports proxy chain

This commit is contained in:
rui.zheng 2017-01-19 15:34:22 +08:00
parent c1d7927257
commit 2dd7ace3ce
6 changed files with 66 additions and 110 deletions

View File

@ -38,25 +38,25 @@ scheme分为两部分: protocol+transport
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转发开启代理链中的其他代理节点将被忽略。
#### 透明代理
基于iptables的透明代理。

View File

@ -40,7 +40,7 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
> 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
@ -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.
When KCP is enabled, other proxy nodes are ignored.
#### Transparent proxy
Iptables-based transparent proxy

View File

@ -69,7 +69,7 @@ func (c *ProxyChain) SetNode(index int, node ProxyNode) {
}
// 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.
//
// NOTE: Should be called immediately when proxy nodes are ready.
@ -81,6 +81,26 @@ func (c *ProxyChain) Init() {
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" {
glog.V(LINFO).Infoln("KCP is enabled")
c.kcpEnabled = true
@ -98,20 +118,6 @@ func (c *ProxyChain) Init() {
c.kcpConfig = config
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 {
@ -198,19 +204,6 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
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() {
nodes = nodes[c.http2NodeIndex+1:]
if len(nodes) == 0 {
@ -243,23 +236,6 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
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() {
nodes = nodes[c.http2NodeIndex+1:]
if len(nodes) == 0 {
@ -291,6 +267,8 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
if withHttp2 && c.Http2Enabled() {
cc, err = c.http2Connect(node.Addr)
} else if node.Transport == "kcp" {
cc, err = c.getKCPConn()
} else {
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)
pc := NewProxyConn(cc, node)
conn = pc
if err = pc.Handshake(); err != nil {
return
}
conn = pc
for _, node := range nodes[1:] {
if err = conn.Connect(node.Addr); err != nil {
return
}
pc := NewProxyConn(conn, node)
conn = pc
if err = pc.Handshake(); err != nil {
return
}
conn = pc
}
return
}

View File

@ -81,6 +81,26 @@ func (c *ProxyChain) Init() {
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" {
glog.V(LINFO).Infoln("KCP is enabled")
c.kcpEnabled = true
@ -98,20 +118,6 @@ func (c *ProxyChain) Init() {
c.kcpConfig = config
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 {
@ -198,19 +204,6 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
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() {
nodes = nodes[c.http2NodeIndex+1:]
if len(nodes) == 0 {
@ -243,23 +236,6 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
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() {
nodes = nodes[c.http2NodeIndex+1:]
if len(nodes) == 0 {
@ -291,6 +267,8 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
if withHttp2 && c.Http2Enabled() {
cc, err = c.http2Connect(node.Addr)
} else if node.Transport == "kcp" {
cc, err = c.getKCPConn()
} else {
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)
pc := NewProxyConn(cc, node)
conn = pc
if err = pc.Handshake(); err != nil {
return
}
conn = pc
for _, node := range nodes[1:] {
if err = conn.Connect(node.Addr); err != nil {
return
}
pc := NewProxyConn(conn, node)
conn = pc
if err = pc.Handshake(); err != nil {
return
}
conn = pc
}
return
}

View File

@ -15,10 +15,10 @@
"revisionTime": "2017-01-19T05:34:58Z"
},
{
"checksumSHA1": "g55EnuSESwa92RY7U+shNoPi900=",
"checksumSHA1": "oZV/w2ONwoM0nMDddIJQYDAZOPg=",
"path": "github.com/ginuerzh/gost",
"revision": "0585749a819f33404f369650e74716cddf4ed3b7",
"revisionTime": "2017-01-19T05:40:53Z"
"revision": "c1d79272573ada276e5a4234774ea4c2e2b4e9ef",
"revisionTime": "2017-01-19T05:42:02Z"
},
{
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",

View File

@ -11,7 +11,7 @@ import (
)
const (
Version = "2.3-rc2"
Version = "2.3-rc3"
)
// Log level for glog