Skip to content

Commit

Permalink
add forward proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed Jun 12, 2020
1 parent 23e6b30 commit de6b1e3
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 28 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ Trojan-Go服务端可以兼容所有Trojan-GFW的客户端,如Igniter,Shadow

## 特性

一般情况下,Trojan-Go和Trojan-GFW版本是互相兼容的。但是一旦使用下面介绍的扩展特性(如多路复用,Websocket等),则无法与之兼容。

### 移植性

运行Trojan-Go的可执行文件不依赖其他组件。
Expand Down Expand Up @@ -220,7 +222,7 @@ Trojan-Go支持多路复用(基于[smux](https://github.com/xtaci/smux))。通

启用多路复用并不会增加你测速得到的链路速度,但会降低延迟,提升大量并发请求时的网络体验,例如浏览含有大量图片的网页等。

注意,这个特性和Trojan-GFW**不兼容**,出于兼容性考虑,这个特性是默认关闭的。你可以通过设置客户端的mux选项"enabled"字段启用它。如下
你可以通过设置客户端的mux选项"enabled"字段启用它。如下

```json
...
Expand Down
21 changes: 13 additions & 8 deletions docs/content/basic/full-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ weight: 30

- ```remote_port```

对于服务器server```key``````cert```为必填。
对于服务器```server``````key``````cert```为必填。

对于客户端client,反向代理隧道forward,以及透明代理nat```password```必填
对于客户端```client```,反向代理隧道```forward```,以及透明代理```nat``````password```必填

其余未填的选项,用下面给出的值进行填充。

*Trojan-Go支持对人类更友好的YAML语法,配置文件的基本结构与JSON相同,效果等价。不过为了遵守YAML的命名习惯,你需要把下划线("_")转换为横杠("-"),如```remote_addr```在YAML文件中为```remote-addr```*

```json
{
"run_type": *required*,
Expand Down Expand Up @@ -52,6 +54,7 @@ weight: 30
"session_ticket": true,
"reuse_session": true,
"plain_http_response": "",
"fallback_addr": "",
"fallback_port": 0,
"fingerprint": "firefox",
},
Expand All @@ -72,8 +75,8 @@ weight: 30
"block": [],
"default_policy": "proxy",
"domain_strategy": "as_is",
"geoip": "geoip.dat",
"geosite": "geosite.dat"
"geoip": "$PROGRAM_DIR$/geoip.dat",
"geosite": "$PROGRAM_DIR$/geosite.dat"
},
"websocket": {
"enabled": false,
Expand Down Expand Up @@ -172,7 +175,7 @@ weight: 30

```sni```指的是TLS客户端请求中的服务器名字段,一般和证书的Common Name相同。如果你使用let'sencrypt等机构签发的证书,这里填入你的域名。如果这一项未填,将使用```remote_addr```填充。你应当指定一个有效的SNI(和远端证书CN一致),否则客户端可能无法验证远端证书有效性从而无法连接。

```alpn```为TLS的应用层协议协商指定协议。在TLS Client/Server Hello中传输,协商应用层使用的协议,仅用作指纹伪造,并无实际作用。**如果使用了CDN,错误的alpn字段可能导致与CDN协商错误的应用层协议**
```alpn```为TLS的应用层协议协商指定协议。在TLS Client/Server Hello中传输,协商应用层使用的协议,仅用作指纹伪造,并无实际作用。**如果使用了CDN,错误的alpn字段可能导致与CDN协商得到错误的应用层协议**

```prefer_server_cipher```客户端是否偏好选择服务端在协商中提供的密码学套件。

Expand All @@ -194,7 +197,7 @@ weight: 30

```plain_http_response```指服务端TLS握手失败时,明文发送的原始数据(原始TCP数据)。这个字段填入该文件路径。推荐使用```fallback_port```而不是该字段。

```fallback_port```指服务端TLS握手失败时,trojan-go将该连接代理的端口。这是trojan-go的特性,以便更好地隐蔽Trojan服务器,抵抗GFW的主动检测,使得服务器的443端口在遭遇非TLS协议的探测时,行为与正常服务器完全一致。当服务器接受了一个连接但无法进行TLS握手时,如果```fallback_port```不为空,则流量将会被代理至remote_addr:fallback_port。例如,你可以在本地使用nginx开启一个https服务,当你的服务器443端口被非TLS协议请求时(比如http请求),trojan-go将代理至本地https服务器,nginx将使用http协议明文返回一个400 Bad Request页面。你可以通过使用浏览器访问```http://your-domain-name.com:443```进行验证。
```fallback_addr``````fallback_port```指服务端TLS握手失败时,trojan-go将该连接重定向到该地址。这是trojan-go的特性,以便更好地隐蔽服务器,抵抗GFW的主动检测,使得服务器的443端口在遭遇非TLS协议的探测时,行为与正常服务器完全一致。当服务器接受了一个连接但无法进行TLS握手时,如果```fallback_port```不为空,则流量将会被代理至fallback_addr:fallback_port。如果```fallback_addr```为空,则用```remote_addr```填充。例如,你可以在本地使用nginx开启一个https服务,当你的服务器443端口被非TLS协议请求时(比如http请求),trojan-go将代理至本地https服务器,nginx将使用http协议明文返回一个400 Bad Request页面。你可以通过使用浏览器访问```http://your-domain-name.com:443```进行验证。

```key_log```TLS密钥日志的文件路径。如果填写则开启密钥日志。**记录密钥将破坏TLS的安全性,此项不应该用于除调试以外的其他任何用途。**

Expand Down Expand Up @@ -266,9 +269,11 @@ Websocket传输是trojan-go的特性。在**正常的直接连接代理节点**

- 你的证书失效,无法验证证书有效性

- 你使用了无法保证密码学安全的可插拔传输层

等等。

由于使用的是AEAD,trojan-go启用了AEAD加密后依然可以正确判断是否遭到主动探测,并作出相应的响应。
由于使用的是AEAD,trojan-go可以正确判断请求是否有效,是否遭到主动探测,并作出相应的响应。

```enabled```是否启用Shadowsocks AEAD加密Trojan协议层。

Expand All @@ -280,7 +285,7 @@ Websocket传输是trojan-go的特性。在**正常的直接连接代理节点**

- "AES-256-GCM"

```password```用于生成主密钥的密码。必须确保客户端和服务端一致。
```password```用于生成主密钥的密码。如果启用AEAD加密,必须确保客户端和服务端一致。

### ```transport_plugin```传输层插件选项

Expand Down
4 changes: 2 additions & 2 deletions docs/content/developer/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ Trojan-Go将所有协议(包括路由功能等)抽象为隧道(tunnel.Tunnel

## proxy.Proxy代理核心

代理核心的作用,监听上述隧道进行组合堆叠并形成的协议栈,将所有的入站协议栈(多个的隧道Server)中抽取的流和包,以及对应元信息,转送给出站协议栈(一个隧道Client)。
代理核心的作用,是监听上述隧道进行组合堆叠并形成的协议栈,将所有的入站协议栈(多个隧道Server)中抽取的流和包,以及对应元信息,转送给出站协议栈(一个隧道Client)。

注意,这里的入站协议栈可以有多个,如客户端可以同时从Socks5和HTTP协议栈中抽取流和包,服务端可以同时从Websocket承载的Trojan协议,和TLS承载的Trojan协议中抽取流和包等。但是出站协议栈只能有一个。
注意,这里的入站协议栈可以有多个,如客户端可以同时从Socks5和HTTP协议栈中抽取流和包,服务端可以同时从Websocket承载的Trojan协议,和TLS承载的Trojan协议中抽取流和包等。但是出站协议栈只能有一个,如只使用TLS承载的Trojan协议出站

为了描述入站协议栈(隧道服务端)的组合和堆叠方式,使用一棵多叉树对所有协议栈进行描述。你可以在client/forward/nat/server中看到构建树的过程。

Expand Down
51 changes: 41 additions & 10 deletions tunnel/raw/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/config"
"github.com/p4gefau1t/trojan-go/log"
"golang.org/x/net/proxy"
"net"
"net/url"
"strconv"
Expand All @@ -15,11 +16,15 @@ import (
)

type Client struct {
preferIPv4 bool
noDelay bool
keepAlive bool
dns []string
ctx context.Context
preferIPv4 bool
noDelay bool
keepAlive bool
dns []string
ctx context.Context
forwardProxy bool
proxyAddr *tunnel.Address
username string
password string
}

func (c *Client) resolveIP(addr *tunnel.Address) ([]net.IPAddr, error) {
Expand Down Expand Up @@ -90,6 +95,29 @@ func (c *Client) DialConn(addr *tunnel.Address, t tunnel.Tunnel) (tunnel.Conn, e
if c.preferIPv4 {
network = "tcp4"
}

// forward proxy
if c.forwardProxy {
var auth *proxy.Auth
if c.username != "" {
auth = &proxy.Auth{
User: c.username,
Password: c.password,
}
}
dialer, err := proxy.SOCKS5(network, c.proxyAddr.String(), auth, proxy.Direct)
if err != nil {
return nil, err
}
socksConn, err := dialer.Dial(network, addr.String())
if err != nil {
return nil, err
}
return &Conn{
Conn: socksConn,
}, nil
}

tcpConn, err := net.Dial(network, addr.String())
if err != nil {
return nil, err
Expand All @@ -98,7 +126,7 @@ func (c *Client) DialConn(addr *tunnel.Address, t tunnel.Tunnel) (tunnel.Conn, e
tcpConn.(*net.TCPConn).SetKeepAlive(c.keepAlive)
tcpConn.(*net.TCPConn).SetNoDelay(c.noDelay)
return &Conn{
TCPConn: tcpConn.(*net.TCPConn),
Conn: tcpConn,
}, nil
}

Expand All @@ -123,11 +151,14 @@ func (c *Client) Close() error {
func NewClient(ctx context.Context, client tunnel.Client) (*Client, error) {
// TODO implement dns
cfg := config.FromContext(ctx, Name).(*Config)
addr := tunnel.NewAddressFromHostPort("tcp", cfg.ForwardProxy.ProxyHost, cfg.ForwardProxy.ProxyPort)
return &Client{
dns: cfg.DNS,
noDelay: cfg.TCP.NoDelay,
keepAlive: cfg.TCP.KeepAlive,
preferIPv4: cfg.TCP.PreferIPV4,
dns: cfg.DNS,
noDelay: cfg.TCP.NoDelay,
keepAlive: cfg.TCP.KeepAlive,
preferIPv4: cfg.TCP.PreferIPV4,
forwardProxy: cfg.ForwardProxy.Enabled,
proxyAddr: addr,
}, nil
}

Expand Down
17 changes: 13 additions & 4 deletions tunnel/raw/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package raw
import "github.com/p4gefau1t/trojan-go/config"

type Config struct {
LocalHost string `json:"local_addr" yaml:"local-addr"`
LocalPort int `json:"local_port" yaml:"local-port"`
DNS []string `json:"dns" yaml:"dns"`
TCP TCPConfig `json:"tcp" yaml:"tcp"`
LocalHost string `json:"local_addr" yaml:"local-addr"`
LocalPort int `json:"local_port" yaml:"local-port"`
DNS []string `json:"dns" yaml:"dns"`
TCP TCPConfig `json:"tcp" yaml:"tcp"`
ForwardProxy ForwardProxyConfig `json:"forward_proxy" yaml:"forward-proxy"`
}

type TCPConfig struct {
Expand All @@ -15,6 +16,14 @@ type TCPConfig struct {
NoDelay bool `json:"no_delay" yaml:"no-delay"`
}

type ForwardProxyConfig struct {
Enabled bool `json,yaml:"enabled"`
ProxyHost string `json:"proxy_addr" yaml:"proxy-addr"`
ProxyPort int `json:"proxy_port" yaml:"proxy-port"`
Username string `json,yaml:"username"`
Password string `json,yaml:"password"`
}

func init() {
config.RegisterConfigCreator(Name, func() interface{} {
return &Config{
Expand Down
2 changes: 1 addition & 1 deletion tunnel/raw/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

type Conn struct {
*net.TCPConn
net.Conn
}

func (c *Conn) Metadata() *tunnel.Metadata {
Expand Down
2 changes: 1 addition & 1 deletion tunnel/raw/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
return nil, err
}
return &Conn{
TCPConn: conn.(*net.TCPConn),
Conn: conn,
}, nil
}

Expand Down
3 changes: 2 additions & 1 deletion tunnel/tproxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (s *Server) packetDispatchLoop() {
s.Close()
return
}
log.Debug("udp packet from", src, "to", dst, "size", n)
log.Debug("udp packet from", src, "metadata", dst, "size", n)
s.mappingLock.Lock()
if conn, found := s.mapping[src.String()]; found {
conn.Input <- buf[:n]
Expand Down Expand Up @@ -131,6 +131,7 @@ func (s *Server) packetDispatchLoop() {
func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
select {
case conn := <-s.packetChan:
log.Info("tproxy packet conn accpeted")
return conn, nil
case <-s.ctx.Done():
return nil, io.EOF
Expand Down

0 comments on commit de6b1e3

Please sign in to comment.