add server-side router, randomized sleeping

This commit is contained in:
Page Fault
2020-05-20 04:06:34 +00:00
parent ff3c500a64
commit e21d1101df
11 changed files with 39 additions and 16 deletions
+4 -5
View File
@@ -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{}
@@ -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{}
@@ -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
+2 -2
View File
@@ -6,9 +6,9 @@ weight: 3
### 注意,Trojan-GFW版本不支持这个特性
Trojan-Go内建的路由模块可以帮助你实现国内直连,即国内网站不经过代理,直接连接。
Trojan-Go内建的路由模块可以帮助你实现国内直连,即客户端对于国内网站不经过代理,直接连接。
路由模块在客户端client生效
路由模块在客户端可以配置三种策略(```bypass```, ```proxy```, ```block```),在服务端只可使用```block```策略
下面是一个例子
+1 -1
View File
@@ -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基于时间的检测。
### 客户端配置
+2 -2
View File
@@ -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"
+1
View File
@@ -10,6 +10,7 @@ import (
)
func main() {
log.Info("Trojan-Go", common.Version)
flag.Parse()
for {
h, err := common.PopOptionHandler()
+2
View File
@@ -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[:]))
+1 -1
View File
@@ -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,
-1
View File
@@ -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
+20 -4
View File
@@ -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"
@@ -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
}
@@ -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)
@@ -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
}
@@ -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)
@@ -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
}
@@ -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{
@@ -233,7 +245,10 @@ 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{
@@ -241,6 +256,7 @@ func (*Server) Build(config *conf.GlobalConfig) (common.Runnable, error) {
ctx: ctx,
cancel: cancel,
shadow: shadow.NewShadowManager(ctx, config),
router: router,
auth: auth,
}
return s, nil
+1
View File
@@ -47,6 +47,7 @@ func (r *GeoRouter) matchDomain(fulldomain string) bool {
return true
}
default:
log.Debug("Unknown type" + d.GetType().String())
}
}
return false
+5
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"math/rand"
"net"
"time"
@@ -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")