From 99863aa2aca6ca18139f1487a94c50cea0b9d717 Mon Sep 17 00:00:00 2001 From: RPRX <63339210+rprx@users.noreply.github.com> Date: Mon, 18 Jan 2021 07:41:00 +0000 Subject: [PATCH] Add SNI shunt support for Trojan fallbacks --- infra/conf/trojan.go | 2 + proxy/trojan/config.pb.go | 73 ++++++++++++++------------ proxy/trojan/config.proto | 11 ++-- proxy/trojan/server.go | 104 +++++++++++++++++++++++++++++--------- 4 files changed, 129 insertions(+), 61 deletions(-) diff --git a/infra/conf/trojan.go b/infra/conf/trojan.go index 2e0dd378..d243e33a 100644 --- a/infra/conf/trojan.go +++ b/infra/conf/trojan.go @@ -85,6 +85,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) { // TrojanInboundFallback is fallback configuration type TrojanInboundFallback struct { + Name string `json:"name"` Alpn string `json:"alpn"` Path string `json:"path"` Type string `json:"type"` @@ -144,6 +145,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) { _ = json.Unmarshal(fb.Dest, &s) } config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{ + Name: fb.Name, Alpn: fb.Alpn, Path: fb.Path, Type: fb.Type, diff --git a/proxy/trojan/config.pb.go b/proxy/trojan/config.pb.go index 391a7569..7f0600b8 100644 --- a/proxy/trojan/config.pb.go +++ b/proxy/trojan/config.pb.go @@ -86,11 +86,12 @@ type Fallback struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"` - Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"` - Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Alpn string `protobuf:"bytes,2,opt,name=alpn,proto3" json:"alpn,omitempty"` + Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"` + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` + Dest string `protobuf:"bytes,5,opt,name=dest,proto3" json:"dest,omitempty"` + Xver uint64 `protobuf:"varint,6,opt,name=xver,proto3" json:"xver,omitempty"` } func (x *Fallback) Reset() { @@ -125,6 +126,13 @@ func (*Fallback) Descriptor() ([]byte, []int) { return file_proxy_trojan_config_proto_rawDescGZIP(), []int{1} } +func (x *Fallback) GetName() string { + if x != nil { + return x.Name + } + return "" +} + func (x *Fallback) GetAlpn() string { if x != nil { return x.Alpn @@ -275,33 +283,34 @@ var file_proxy_trojan_config_proto_rawDesc = []byte{ 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, - 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, - 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, - 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, - 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, - 0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, - 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, - 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, - 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, + 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, + 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, + 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, + 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, + 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, + 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, + 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proxy/trojan/config.proto b/proxy/trojan/config.proto index b4376a82..6ebed36b 100644 --- a/proxy/trojan/config.proto +++ b/proxy/trojan/config.proto @@ -15,11 +15,12 @@ message Account { } message Fallback { - string alpn = 1; - string path = 2; - string type = 3; - string dest = 4; - uint64 xver = 5; + string name = 1; + string alpn = 2; + string path = 3; + string type = 4; + string dest = 5; + uint64 xver = 6; } message ClientConfig { diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index 12bd8758..6b22e49e 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "io" "strconv" + "strings" "syscall" "time" @@ -46,7 +47,7 @@ func init() { type Server struct { policyManager policy.Manager validator *Validator - fallbacks map[string]map[string]*Fallback // or nil + fallbacks map[string]map[string]map[string]*Fallback // or nil cone bool } @@ -72,19 +73,48 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { } if config.Fallbacks != nil { - server.fallbacks = make(map[string]map[string]*Fallback) + server.fallbacks = make(map[string]map[string]map[string]*Fallback) for _, fb := range config.Fallbacks { - if server.fallbacks[fb.Alpn] == nil { - server.fallbacks[fb.Alpn] = make(map[string]*Fallback) + if server.fallbacks[fb.Name] == nil { + server.fallbacks[fb.Name] = make(map[string]map[string]*Fallback) } - server.fallbacks[fb.Alpn][fb.Path] = fb + if server.fallbacks[fb.Name][fb.Alpn] == nil { + server.fallbacks[fb.Name][fb.Alpn] = make(map[string]*Fallback) + } + server.fallbacks[fb.Name][fb.Alpn][fb.Path] = fb } if server.fallbacks[""] != nil { - for alpn, pfb := range server.fallbacks { - if alpn != "" { // && alpn != "h2" { - for path, fb := range server.fallbacks[""] { - if pfb[path] == nil { - pfb[path] = fb + for name, apfb := range server.fallbacks { + if name != "" { + for alpn := range server.fallbacks[""] { + if apfb[alpn] == nil { + apfb[alpn] = make(map[string]*Fallback) + } + } + } + } + } + for _, apfb := range server.fallbacks { + if apfb[""] != nil { + for alpn, pfb := range apfb { + if alpn != "" { // && alpn != "h2" { + for path, fb := range apfb[""] { + if pfb[path] == nil { + pfb[path] = fb + } + } + } + } + } + } + if server.fallbacks[""] != nil { + for name, apfb := range server.fallbacks { + if name != "" { + for alpn, pfb := range server.fallbacks[""] { + for path, fb := range pfb { + if apfb[alpn][path] == nil { + apfb[alpn][path] = fb + } } } } @@ -141,8 +171,8 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet var user *protocol.MemoryUser - apfb := s.fallbacks - isfb := apfb != nil + napfb := s.fallbacks + isfb := napfb != nil shouldFallback := false if firstLen < 58 || first.Byte(56) != '\r' { @@ -173,7 +203,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet } if isfb && shouldFallback { - return s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, apfb, first, firstLen, bufferedReader) + return s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, napfb, first, firstLen, bufferedReader) } else if shouldFallback { return newError("invalid protocol or invalid user") } @@ -361,25 +391,51 @@ func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Sess return nil } -func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, apfb map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error { +func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, napfb map[string]map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error { if err := connection.SetReadDeadline(time.Time{}); err != nil { newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid) } newError("fallback starts").Base(err).AtInfo().WriteToLog(sid) + name := "" alpn := "" - if len(apfb) > 1 || apfb[""] == nil { - if tlsConn, ok := iConn.(*tls.Conn); ok { - alpn = tlsConn.ConnectionState().NegotiatedProtocol - newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) - } else if xtlsConn, ok := iConn.(*xtls.Conn); ok { - alpn = xtlsConn.ConnectionState().NegotiatedProtocol - newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) - } - if apfb[alpn] == nil { - alpn = "" + if tlsConn, ok := iConn.(*tls.Conn); ok { + cs := tlsConn.ConnectionState() + name = cs.ServerName + alpn = cs.NegotiatedProtocol + newError("realName = " + name).AtInfo().WriteToLog(sid) + newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) + } else if xtlsConn, ok := iConn.(*xtls.Conn); ok { + cs := xtlsConn.ConnectionState() + name = cs.ServerName + alpn = cs.NegotiatedProtocol + newError("realName = " + name).AtInfo().WriteToLog(sid) + newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) + } + + if len(napfb) > 1 || napfb[""] == nil { + if name != "" && napfb[name] == nil { + match := "" + for n := range napfb { + if n != "" && strings.Contains(name, n) && len(n) > len(match) { + match = n + } + } + name = match } } + + if napfb[name] == nil { + name = "" + } + apfb := napfb[name] + if apfb == nil { + return newError(`failed to find the default "name" config`).AtWarning() + } + + if apfb[alpn] == nil { + alpn = "" + } pfb := apfb[alpn] if pfb == nil { return newError(`failed to find the default "alpn" config`).AtWarning()