Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed Jun 4, 2020
2 parents 3bbd92d + 23fe740 commit b93b95f
Show file tree
Hide file tree
Showing 18 changed files with 515 additions and 152 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Trojan-Go支持并且兼容Trojan-GFW的绝大多数功能,包括但不限于

- 基于gRPC的API支持,支持动态用户管理和流量速度限制

- 服务端支持处理Trojan协议明文(TCP明文传输),以适应前置nginx等服务器的场景
- 可插拔传输层,可将TLS替换为其他协议或明文传输。同时有完整的Shadowsocks混淆插件支持。

## 图形界面客户端

Expand Down Expand Up @@ -337,6 +337,38 @@ Trojan-Go的客户端内建一个简单实用的路由模块用以方便实现

所需要的geoip.dat和geosite.dat已经包含在release的压缩包中。它们来自v2ray的[domain-list-community](https://github.com/v2ray/domain-list-community)和[geoip](https://github.com/v2ray/geoip)。

完整的选项说明参见[Trojan-Go 文档](https://p4gefau1t.github.io/trojan-go)。

## 混淆插件

Trojan-Go支持可插拔的传输层插件,并支持Shadowsocks SIP003标准的混淆插件。下面是使用v2ray-plugin的一个例子:

**此配置并不安全,仅用作演示**

服务端配置:

```json
"transport_plugin": {
"enabled": true,
"type": "shadowsocks",
"command": "./v2ray-plugin",
"arg": ["-server", "-host", "www.baidu.com"]
}
```

客户端配置:

```json
"transport_plugin": {
"enabled": true,
"type": "shadowsocks",
"command": "./v2ray-plugin",
"arg": ["-host", "www.baidu.com"]
}
```

完整的选项说明参见[Trojan-Go 文档](https://p4gefau1t.github.io/trojan-go)。

## 构建

确保你的Go版本 >= 1.14,推荐使用snap安装Go保持与上游同步。
Expand Down
2 changes: 1 addition & 1 deletion common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

const (
Version = "v0.5.1"
Version = "v0.6.0"
)

type Runnable interface {
Expand Down
11 changes: 11 additions & 0 deletions common/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,14 @@ func HumanFriendlyTraffic(bytes uint64) string {
}
return fmt.Sprintf("%.2f GiB", float32(bytes)/GiB)
}

func PickPort(network string, host string) int {
l, err := net.Listen(network, host+":0")
Must(err)
defer l.Close()
_, port, err := net.SplitHostPort(l.Addr().String())
Must(err)
p, err := strconv.ParseInt(port, 10, 32)
Must(err)
return int(p)
}
60 changes: 36 additions & 24 deletions conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/tls"
"crypto/x509"
"io"
"os/exec"

"github.com/p4gefau1t/trojan-go/common"
utls "github.com/refraction-networking/utls"
Expand Down Expand Up @@ -46,7 +47,6 @@ type TLSConfig struct {
ALPN []string `json:"alpn"`
Curves string `json:"curves"`
Fingerprint string `json:"fingerprint"`
ServePlainText bool `json:"serve_plain_text"`
KeyLogPath string `json:"key_log"`

ClientHelloID *utls.ClientHelloID
Expand Down Expand Up @@ -153,30 +153,42 @@ type APIConfig struct {
APIAddress *common.Address
}

type TransportPluginConfig struct {
Enabled bool `json:"enabled"`
Type string `json:"type"`
Command string `json:"command"`
PluginOption string `json:"plugin_option"`
Arg []string `json:"arg"`
Env []string `json:"env"`

Cmd *exec.Cmd
}

type GlobalConfig struct {
RunType RunType `json:"run_type"`
LogLevel int `json:"log_level"`
LogFile string `json:"log_file"`
LocalHost string `json:"local_addr"`
LocalPort int `json:"local_port"`
TargetHost string `json:"target_addr"`
TargetPort int `json:"target_port"`
RemoteHost string `json:"remote_addr"`
RemotePort int `json:"remote_port"`
BufferSize int `json:"buffer_size"`
DisableHTTPCheck bool `json:"disable_http_check"`
Passwords []string `json:"password"`
DNS []string `json:"dns"`
TLS TLSConfig `json:"ssl"`
TCP TCPConfig `json:"tcp"`
MySQL MySQLConfig `json:"mysql"`
Redis RedisConfig `json:"redis"`
Mux MuxConfig `json:"mux"`
Router RouterConfig `json:"router"`
Websocket WebsocketConfig `json:"websocket"`
API APIConfig `json:"api"`
ForwardProxy ForwardProxyConfig `json:"forward_proxy"`
Compression CompressionConfig `json:"compression"`
RunType RunType `json:"run_type"`
LogLevel int `json:"log_level"`
LogFile string `json:"log_file"`
LocalHost string `json:"local_addr"`
LocalPort int `json:"local_port"`
TargetHost string `json:"target_addr"`
TargetPort int `json:"target_port"`
RemoteHost string `json:"remote_addr"`
RemotePort int `json:"remote_port"`
BufferSize int `json:"buffer_size"`
DisableHTTPCheck bool `json:"disable_http_check"`
Passwords []string `json:"password"`
DNS []string `json:"dns"`
TLS TLSConfig `json:"ssl"`
TCP TCPConfig `json:"tcp"`
MySQL MySQLConfig `json:"mysql"`
Redis RedisConfig `json:"redis"`
Mux MuxConfig `json:"mux"`
Router RouterConfig `json:"router"`
Websocket WebsocketConfig `json:"websocket"`
API APIConfig `json:"api"`
ForwardProxy ForwardProxyConfig `json:"forward_proxy"`
Compression CompressionConfig `json:"compression"`
TransportPlugin TransportPluginConfig `json:"transport_plugin"`

LocalAddress *common.Address
RemoteAddress *common.Address
Expand Down
153 changes: 114 additions & 39 deletions conf/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"net"
"net/http"
"os"
"os/exec"
"strconv"
"strings"

"github.com/p4gefau1t/trojan-go/common"
Expand Down Expand Up @@ -313,27 +315,65 @@ func loadCommonConfig(config *GlobalConfig) error {
}

func loadClientConfig(config *GlobalConfig) error {
if config.TLS.SNI == "" {
log.Warn("SNI is unspecified, using remote_addr as SNI")
config.TLS.SNI = config.RemoteHost
}
if err := loadCert(&config.TLS); err != nil {
return err
}
//forward proxy settings
if config.ForwardProxy.Enabled {
log.Info("Forward proxy enabled")
config.ForwardProxy.ProxyAddress = common.NewAddress(config.ForwardProxy.ProxyHost, config.ForwardProxy.ProxyPort, "tcp")
log.Debug("Forward proxy", config.ForwardProxy.ProxyAddress.String())
}

if config.Websocket.Enabled && config.Websocket.DoubleTLS {
if config.Websocket.TLS.CertPath == "" {
log.Warn("Empty double TLS settings, using default ssl settings")
config.Websocket.TLS = config.TLS
} else {
if err := loadCert(&config.Websocket.TLS); err != nil {
return err
if config.TransportPlugin.Enabled {
log.Warn("Trojan-Go will use transport plugin and work in plain text mode")
switch config.TransportPlugin.Type {
case "plaintext":
// do nothing
case "shadowsocks":
pluginHost := "127.0.0.1"
pluginPort := common.PickPort("tcp", pluginHost)
config.TransportPlugin.Env = append(
config.TransportPlugin.Env,
"SS_LOCAL_HOST="+pluginHost,
"SS_LOCAL_PORT="+strconv.FormatInt(int64(pluginPort), 10),
"SS_REMOTE_HOST="+config.RemoteHost,
"SS_REMOTE_PORT="+strconv.FormatInt(int64(config.RemotePort), 10),
"SS_PLUGIN_OPTIONS="+config.TransportPlugin.PluginOption,
)
config.RemoteHost = pluginHost
config.RemotePort = pluginPort
config.RemoteAddress = common.NewAddress(config.RemoteHost, config.RemotePort, "tcp")
log.Debug("New remote address", config.RemoteAddress.String())
log.Debug("Plugin env", config.TransportPlugin.Env)

cmd := exec.Command(config.TransportPlugin.Command, config.TransportPlugin.Arg...)
cmd.Env = append(cmd.Env, config.TransportPlugin.Env...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
config.TransportPlugin.Cmd = cmd
case "other":
cmd := exec.Command(config.TransportPlugin.Command, config.TransportPlugin.Arg...)
cmd.Env = append(cmd.Env, config.TransportPlugin.Env...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
config.TransportPlugin.Cmd = cmd
default:
return common.NewError("Invalid plugin type: " + config.TransportPlugin.Type)
}
} else {
if config.TLS.SNI == "" {
log.Warn("SNI is unspecified, using remote_addr as SNI")
config.TLS.SNI = config.RemoteHost
}
if err := loadCert(&config.TLS); err != nil {
return err
}
if config.Websocket.Enabled && config.Websocket.DoubleTLS {
if config.Websocket.TLS.CertPath == "" {
log.Warn("Empty double TLS settings, using default ssl settings")
config.Websocket.TLS = config.TLS
} else {
if err := loadCert(&config.Websocket.TLS); err != nil {
return err
}
}
}
}
Expand All @@ -354,35 +394,70 @@ func loadServerConfig(config *GlobalConfig) error {
resp.Body.Close()
}

//tls settings
if config.TLS.ServePlainText {
log.Warn("Server will now use plain text. TLS config is ignored")
// transport plugin settings
if config.TransportPlugin.Enabled {
log.Warn("Trojan-Go will use transport plugin and work in plain text mode")
switch config.TransportPlugin.Type {
case "shadowsocks":
trojanHost := "127.0.0.1"
trojanPort := common.PickPort("tcp", trojanHost)
config.TransportPlugin.Env = append(
config.TransportPlugin.Env,
"SS_REMOTE_HOST="+config.LocalHost,
"SS_REMOTE_PORT="+strconv.FormatInt(int64(config.LocalPort), 10),
"SS_LOCAL_HOST="+trojanHost,
"SS_LOCAL_PORT="+strconv.FormatInt(int64(trojanPort), 10),
"SS_PLUGIN_OPTIONS="+config.TransportPlugin.PluginOption,
)

config.LocalHost = trojanHost
config.LocalPort = trojanPort
config.LocalAddress = common.NewAddress(config.LocalHost, config.LocalPort, "tcp")
log.Debug("New local address", config.RemoteAddress.String())
log.Debug("Plugin env", config.TransportPlugin.Env)

cmd := exec.Command(config.TransportPlugin.Command, config.TransportPlugin.Arg...)
cmd.Env = append(cmd.Env, config.TransportPlugin.Env...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
config.TransportPlugin.Cmd = cmd
case "other":
cmd := exec.Command(config.TransportPlugin.Command, config.TransportPlugin.Arg...)
cmd.Env = append(cmd.Env, config.TransportPlugin.Env...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
config.TransportPlugin.Cmd = cmd
case "plaintext":
// do nothing
default:
return common.NewError("Invalid plugin type: " + config.TransportPlugin.Type)
}
} else {
if err := loadCertAndKey(&config.TLS); err != nil {
return err
}
if config.TLS.SNI == "" {
log.Warn("Empty SNI field. Server will not verify the SNI in client hello request")
config.TLS.VerifyHostName = false
}
if config.TLS.HTTPResponseFileName != "" {
payload, err := ioutil.ReadFile(config.TLS.HTTPResponseFileName)
if err != nil {
return common.NewError("Failed to load http response file").Base(err)
}
config.TLS.HTTPResponse = payload
}
}


if config.Websocket.Enabled && config.Websocket.DoubleTLS {
if config.Websocket.TLS.CertPath == "" {
log.Warn("Empty double TLS settings, using global TLS settings")
config.Websocket.TLS = config.TLS
}
if err := loadCertAndKey(&config.Websocket.TLS); err != nil {
return err
// tls settings
if config.TLS.SNI == "" {
log.Warn("Empty SNI field. Server will not verify the SNI in client hello request")
config.TLS.VerifyHostName = false
}

if config.TLS.HTTPResponseFileName != "" {
payload, err := ioutil.ReadFile(config.TLS.HTTPResponseFileName)
if err != nil {
return common.NewError("Failed to load http response file").Base(err)
}
config.TLS.HTTPResponse = payload
}

if config.Websocket.Enabled && config.Websocket.DoubleTLS {
if config.Websocket.TLS.CertPath == "" {
log.Warn("Empty double TLS settings, using global TLS settings")
config.Websocket.TLS = config.TLS
}
if err := loadCertAndKey(&config.Websocket.TLS); err != nil {
return err
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enableMissingTranslationPlaceholders = false
# Source Code repository section
description = "An unidentifiable mechanism that helps you bypass GFW. "
github_repository = "https://github.com/p4gefau1t/trojan-go"
version = "0.5.1"
version = "0.6.0"

# Documentation repository section
# documentation repository (set edit link to documentation repository)
Expand Down
Loading

0 comments on commit b93b95f

Please sign in to comment.