From b4e84603a2fa5199afef7d1d95881b987e024138 Mon Sep 17 00:00:00 2001 From: RPRX <63339210+rprx@users.noreply.github.com> Date: Fri, 11 Dec 2020 03:05:39 +0000 Subject: [PATCH] Add XTLS Splice to Trojan Outbound --- proxy/trojan/client.go | 20 +++++++++++++------- proxy/trojan/protocol.go | 35 ++++++++++++++++++++++++++++++++++- proxy/trojan/server.go | 2 +- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/proxy/trojan/client.go b/proxy/trojan/client.go index a1219343..74410d32 100644 --- a/proxy/trojan/client.go +++ b/proxy/trojan/client.go @@ -94,15 +94,16 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter } var rawConn syscall.RawConn + var sctx context.Context connWriter := &ConnWriter{} allowUDP443 := false switch account.Flow { - case XRO + "-udp443", XRD + "-udp443": + case XRO + "-udp443", XRD + "-udp443", XRS + "-udp443": allowUDP443 = true account.Flow = account.Flow[:16] fallthrough - case XRO, XRD: + case XRO, XRD, XRS: if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress { return newError(account.Flow + " doesn't support Mux").AtWarning() } @@ -114,13 +115,18 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter if xtlsConn, ok := iConn.(*xtls.Conn); ok { xtlsConn.RPRX = true xtlsConn.SHOW = trojanXTLSShow - connWriter.Flow = account.Flow + xtlsConn.MARK = "XTLS" + if account.Flow == XRS { + sctx = ctx + account.Flow = XRD + } if account.Flow == XRD { xtlsConn.DirectMode = true + if sc, ok := xtlsConn.Connection.(syscall.Conn); ok { + rawConn, _ = sc.SyscallConn() + } } - if sc, ok := xtlsConn.Connection.(syscall.Conn); ok { - rawConn, _ = sc.SyscallConn() - } + connWriter.Flow = account.Flow } else { return newError(`failed to use ` + account.Flow + `, maybe "security" is not "xtls"`).AtWarning() } @@ -185,7 +191,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter if statConn != nil { counter = statConn.ReadCounter } - return ReadV(reader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter) + return ReadV(reader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter, sctx) } return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)) } diff --git a/proxy/trojan/protocol.go b/proxy/trojan/protocol.go index 3b161163..739bc137 100644 --- a/proxy/trojan/protocol.go +++ b/proxy/trojan/protocol.go @@ -1,17 +1,21 @@ package trojan import ( + "context" "encoding/binary" fmt "fmt" "io" + "runtime" "syscall" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/protocol" + "github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/features/stats" + "github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet/xtls" ) @@ -29,6 +33,8 @@ var ( const ( maxLength = 8192 + // XRS is constant for XTLS splice mode + XRS = "xtls-rprx-splice" // XRD is constant for XTLS direct mode XRD = "xtls-rprx-direct" // XRO is constant for XTLS origin mode @@ -307,12 +313,39 @@ func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) { return &PacketPayload{Target: dest, Buffer: mb}, nil } -func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter) error { +func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, sctx context.Context) error { err := func() error { var ct stats.Counter for { if conn.DirectIn { conn.DirectIn = false + if sctx != nil { + if inbound := session.InboundFromContext(sctx); inbound != nil && inbound.Conn != nil { + iConn := inbound.Conn + statConn, ok := iConn.(*internet.StatCouterConnection) + if ok { + iConn = statConn.Connection + } + if tc, ok := iConn.(*net.TCPConn); ok { + if conn.SHOW { + fmt.Println(conn.MARK, "Splice") + } + runtime.Gosched() // necessary + w, err := tc.ReadFrom(conn.Connection) + if counter != nil { + counter.Add(w) + } + if statConn != nil && statConn.WriteCounter != nil { + statConn.WriteCounter.Add(w) + } + return err + } else { + panic("XTLS Splice: not TCP inbound") + } + } else { + //panic("XTLS Splice: nil inbound or nil inbound.Conn") + } + } reader = buf.NewReadVReader(conn.Connection, rawConn) ct = counter if conn.SHOW { diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index 9f0d3e58..7324fb49 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -310,7 +310,7 @@ func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Sess if statConn != nil { counter = statConn.ReadCounter } - err = ReadV(clientReader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter) + err = ReadV(clientReader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter, nil) } else { err = buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer)) }