Skip to content

Commit

Permalink
add server-side router, randomized sleeping
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed May 20, 2020
1 parent ff3c500 commit e21d110
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 16 deletions.
9 changes: 4 additions & 5 deletions conf/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,6 @@ func loadCommonConfig(config *GlobalConfig) error {
config.Websocket.ObfuscationKey = pbkdf2.Key(password, salt, 32, aes.BlockSize, sha256.New)
}
}
return nil
}

func loadClientConfig(config *GlobalConfig) error {
var err error

//router settings
config.Router.BlockList = []byte{}
Expand Down Expand Up @@ -264,6 +259,7 @@ func loadClientConfig(config *GlobalConfig) error {
config.Router.ProxyList = append(config.Router.ProxyList, byte('\n'))
}

var err error
config.Router.GeoIP, err = ioutil.ReadFile(config.Router.GeoIPFilename)
if err != nil {
config.Router.GeoIP = []byte{}
Expand All @@ -274,7 +270,10 @@ func loadClientConfig(config *GlobalConfig) error {
config.Router.GeoSite = []byte{}
log.Warn(err)
}
return nil
}

func loadClientConfig(config *GlobalConfig) error {
if config.TLS.SNI == "" {
log.Warn("SNI is unspecified, using remote_addr as SNI")
config.TLS.SNI = config.RemoteHost
Expand Down
4 changes: 2 additions & 2 deletions docs/content/advance/router.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ weight: 3

### 注意,Trojan-GFW版本不支持这个特性

Trojan-Go内建的路由模块可以帮助你实现国内直连,即国内网站不经过代理,直接连接。
Trojan-Go内建的路由模块可以帮助你实现国内直连,即客户端对于国内网站不经过代理,直接连接。

路由模块只在客户端client生效
路由模块在客户端可以配置三种策略(```bypass```, ```proxy```, ```block```),在服务端只可使用```block```策略

下面是一个例子

Expand Down
2 changes: 1 addition & 1 deletion docs/content/basic/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ sudo ./trojan-go -autocert renew

你可以通过使用浏览器访问你的域名```https://your_domain_name```来验证。如果工作正常,你的浏览器会显示一个正常的HTTPS保护的Web页面,页面内容与服务器本机80端口上的页面一致。你还可以使用```http://your_domain_name:443```验证```fallback_port```工作是否正常。

事实上,你甚至可以将Trojan-Go当作你的HTTPS服务器,用来给你的网站提供HTTPS服务。访客可以正常地通过Trojan-Go浏览你的网站,而和代理流量互不影响。
事实上,你甚至可以将Trojan-Go当作你的HTTPS服务器,用来给你的网站提供HTTPS服务。访客可以正常地通过Trojan-Go浏览你的网站,而和代理流量互不影响。但是注意,不要在```remote_port``````fallback_port```搭建有高实时性需求的服务,Trojan-Go识别到非Trojan协议流量时会有意增加少许延迟以抵抗GFW基于时间的检测。

### 客户端配置

Expand Down
4 changes: 2 additions & 2 deletions docs/content/basic/full-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,11 @@ weight: 30

- Block 封锁。不代理请求,直接关闭连接。

```proxy```, ```bypass```, ```block```字段中填入对应列表文件名或者geoip/geosite标签名,trojan-go即根据列表中的IP(CIDR)或域名执行相应路由策略。列表文件中每行是一个IP或者域名,trojan-go会自动识别。
```proxy```, ```bypass```, ```block```字段中填入对应列表文件名或者geoip/geosite标签名,trojan-go即根据列表中的IP(CIDR)或域名执行相应路由策略。列表文件中每行是一个IP或者域名,trojan-go会自动识别。客户端(client)可以配置三种策略,服务端(server)只可配置block策略。

```enabled```是否开启路由模块。

```default_policy```指的是三个列表匹配均失败后,使用的默认策略,默认为"bypass",即进行代理。合法的值有
```default_policy```指的是三个列表匹配均失败后,使用的默认策略,默认为"proxy",即进行代理。合法的值有

- "proxy"

Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

func main() {
log.Info("Trojan-Go", common.Version)
flag.Parse()
for {
h, err := common.PopOptionHandler()
Expand Down
2 changes: 2 additions & 0 deletions protocol/trojan/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ func (i *TrojanInboundConnSession) Close() error {

func (i *TrojanInboundConnSession) parseRequest(r *common.RewindReader) error {
userHash := [56]byte{}

n, err := r.Read(userHash[:])
if err != nil || n != 56 {
return common.NewError("Failed to read hash").Base(err)
}

valid, meter := i.auth.AuthUser(string(userHash[:]))
if !valid {
return common.NewError("Invalid hash:" + string(userHash[:]))
Expand Down
2 changes: 1 addition & 1 deletion protocol/trojan/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func NewInboundWebsocket(ctx context.Context, conn net.Conn, config *conf.Global

if err != nil {
rewindConn.R.Rewind()
//proxy this to our own ws server
//redirect this to our own ws server
err = common.NewError("Remote websocket " + conn.RemoteAddr().String() + "didn't send any valid iv").Base(err)
goat, err := getWebsocketScapegoat(
config,
Expand Down
1 change: 0 additions & 1 deletion proxy/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ func (*proxyOption) Priority() int {
}

func (c *proxyOption) Handle() error {
log.Info("Trojan-Go", common.Version, "initializing")
log.Info("Loading config file from", *c.args)

//exit code 23 stands for initializing error, and systemd will not trying to restart it
Expand Down
24 changes: 20 additions & 4 deletions proxy/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/p4gefau1t/trojan-go/protocol/simplesocks"
"github.com/p4gefau1t/trojan-go/protocol/trojan"
"github.com/p4gefau1t/trojan-go/proxy"
"github.com/p4gefau1t/trojan-go/router"
"github.com/p4gefau1t/trojan-go/shadow"
"github.com/p4gefau1t/trojan-go/sockopt"
"github.com/p4gefau1t/trojan-go/stat"
Expand All @@ -28,6 +29,7 @@ type Server struct {
auth stat.Authenticator
config *conf.GlobalConfig
shadow *shadow.ShadowManager
router router.Router
ctx context.Context
cancel context.CancelFunc
}
Expand All @@ -41,6 +43,11 @@ func (s *Server) handleMuxConn(stream *smux.Stream) {
}
defer stream.Close()

if policy, err := s.router.RouteRequest(req); err != nil || policy == router.Block {
log.Info("[Block] conn to", req.String())
return
}

switch req.Command {
case protocol.Connect:
outboundConn, err := direct.NewOutboundConnSession(s.ctx, req, s.config)
Expand All @@ -67,7 +74,7 @@ func (s *Server) handleConn(conn net.Conn) {
protocol.SetRandomizedTimeout(conn)
inboundConn, req, err := trojan.NewInboundConnSession(s.ctx, conn, s.config, s.auth, s.shadow)
if err != nil {
//once the auth is failed, the conn will be took over by shadow manager. don't close it
//once the auth is failed, the conn will be took over by shadow manager. DO NOT close it.
log.Error(common.NewError("Failed to start inbound session, remote:" + conn.RemoteAddr().String()).Base(err))
return
}
Expand All @@ -88,6 +95,11 @@ func (s *Server) handleConn(conn net.Conn) {
}
}

if policy, err := s.router.RouteRequest(req); err != nil || policy == router.Block {
log.Info("[Block] conn to", req.String())
return
}

if req.Command == protocol.Associate {
inboundPacket, err := trojan.NewPacketSession(inboundConn)
common.Must(err)
Expand Down Expand Up @@ -131,7 +143,7 @@ func (s *Server) ListenTCP(errChan chan error) {

err = sockopt.ApplyTCPListenerOption(listener.(*net.TCPListener), &s.config.TCP)
if err != nil {
errChan <- common.NewError(fmt.Sprintf("failed to apply tcp option: %v", &s.config.TCP)).Base(err)
errChan <- common.NewError(fmt.Sprintf("Failed to apply tcp option: %v", &s.config.TCP)).Base(err)
return
}

Expand Down Expand Up @@ -177,7 +189,7 @@ func (s *Server) ListenTCP(errChan chan error) {

if err != nil {
rewindConn.R.Rewind()
err = common.NewError("Failed to perform tls handshake with " + conn.RemoteAddr().String()).Base(err)
err = common.NewError("Failed to perform TLS handshake with " + conn.RemoteAddr().String()).Base(err)
log.Warn(err)
if s.config.TLS.FallbackAddress != nil {
s.shadow.SubmitScapegoat(&shadow.Scapegoat{
Expand Down Expand Up @@ -233,14 +245,18 @@ func (*Server) Build(config *conf.GlobalConfig) (common.Runnable, error) {
}
auth, err := stat.NewAuth(ctx, authDriver, config)
if err != nil {
cancel()
return nil, err
}
router, err := router.NewRouter(&config.Router)
if err != nil {
return nil, err
}
s := &Server{
config: config,
ctx: ctx,
cancel: cancel,
shadow: shadow.NewShadowManager(ctx, config),
router: router,
auth: auth,
}
return s, nil
Expand Down
1 change: 1 addition & 0 deletions router/mixed/geo.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (r *GeoRouter) matchDomain(fulldomain string) bool {
return true
}
default:
log.Debug("Unknown type" + d.GetType().String())
}
}
return false
Expand Down
5 changes: 5 additions & 0 deletions shadow/shadow.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"math/rand"
"net"
"time"

Expand Down Expand Up @@ -46,6 +47,10 @@ func (m *ShadowManager) handleScapegoat() {
if conn, ok := goat.Conn.(net.Conn); ok {
conn.SetDeadline(time.Time{})
}

//sleep for a while to resist time-based detection
time.Sleep(time.Millisecond * time.Duration(rand.Intn(50)))

if goat.ShadowConn == nil {
if goat.ShadowAddress == nil {
panic("incorrect shadow server")
Expand Down

0 comments on commit e21d110

Please sign in to comment.