mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2024-04-21 12:21:34 +00:00
add server-side router, randomized sleeping
This commit is contained in:
+4
-5
@@ -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
|
||||
|
||||
@@ -6,9 +6,9 @@ weight: 3
|
||||
|
||||
### 注意,Trojan-GFW版本不支持这个特性
|
||||
|
||||
Trojan-Go内建的路由模块可以帮助你实现国内直连,即国内网站不经过代理,直接连接。
|
||||
Trojan-Go内建的路由模块可以帮助你实现国内直连,即客户端对于国内网站不经过代理,直接连接。
|
||||
|
||||
路由模块只在客户端client生效。
|
||||
路由模块在客户端可以配置三种策略(```bypass```, ```proxy```, ```block```),在服务端只可使用```block```策略。
|
||||
|
||||
下面是一个例子
|
||||
|
||||
|
||||
@@ -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基于时间的检测。
|
||||
|
||||
### 客户端配置
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Info("Trojan-Go", common.Version)
|
||||
flag.Parse()
|
||||
for {
|
||||
h, err := common.PopOptionHandler()
|
||||
|
||||
@@ -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[:]))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -47,6 +47,7 @@ func (r *GeoRouter) matchDomain(fulldomain string) bool {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
log.Debug("Unknown type" + d.GetType().String())
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user