Add SNI shunt support for Trojan fallbacks

This commit is contained in:
RPRX 2021-01-18 07:41:00 +00:00 committed by GitHub
parent 8eed8a0824
commit 99863aa2ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 129 additions and 61 deletions

View file

@ -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()