From 7d831273477078dd96a293473fa5fb782d7e92a5 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Fri, 26 May 2023 20:11:06 +0800 Subject: [PATCH] refactor: Move vision implementation to a new package --- transport/vless/conn.go | 305 +----------------- transport/vless/vision/conn.go | 274 ++++++++++++++++ transport/vless/{ => vision}/filter.go | 2 +- .../vless/{vision.go => vision/padding.go} | 6 +- transport/vless/vision/vision.go | 70 ++++ transport/vless/xtls.go | 5 - 6 files changed, 362 insertions(+), 300 deletions(-) create mode 100644 transport/vless/vision/conn.go rename transport/vless/{ => vision}/filter.go (99%) rename transport/vless/{vision.go => vision/padding.go} (94%) create mode 100644 transport/vless/vision/vision.go diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 9289afcf..9e2e5e89 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -1,25 +1,18 @@ package vless import ( - "bytes" - "crypto/subtle" - gotls "crypto/tls" "encoding/binary" "errors" "fmt" "io" "net" - "reflect" "sync" - "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/vless/vision" "github.com/gofrs/uuid/v5" - utls "github.com/sagernet/utls" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) @@ -36,33 +29,10 @@ type Conn struct { handshakeMutex sync.Mutex needHandshake bool err error - - tlsConn net.Conn - input *bytes.Reader - rawInput *bytes.Buffer - - packetsToFilter int - isTLS bool - isTLS12orAbove bool - enableXTLS bool - cipher uint16 - remainingServerHello uint16 - readRemainingContent int - readRemainingPadding int - readProcess bool - readFilterUUID bool - readLastCommand byte - writeFilterApplicationData bool - writeDirect bool } func (vc *Conn) Read(b []byte) (int, error) { if vc.received { - if vc.readProcess { - buffer := buf.With(b) - err := vc.ReadBuffer(buffer) - return buffer.Len(), err - } return vc.ExtendedReader.Read(b) } @@ -70,106 +40,11 @@ func (vc *Conn) Read(b []byte) (int, error) { return 0, err } vc.received = true - return vc.Read(b) + return vc.ExtendedReader.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { if vc.received { - toRead := buffer.FreeBytes() - if vc.readRemainingContent > 0 { - if vc.readRemainingContent < buffer.FreeLen() { - toRead = toRead[:vc.readRemainingContent] - } - n, err := vc.ExtendedReader.Read(toRead) - buffer.Truncate(n) - vc.readRemainingContent -= n - vc.FilterTLS(toRead) - return err - } - if vc.readRemainingPadding > 0 { - _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) - if err != nil { - return err - } - vc.readRemainingPadding = 0 - } - if vc.readProcess { - switch vc.readLastCommand { - case commandPaddingContinue: - //if vc.isTLS || vc.packetsToFilter > 0 { - headerUUIDLen := 0 - if vc.readFilterUUID { - headerUUIDLen = uuid.Size - } - var header []byte - if need := headerUUIDLen + paddingHeaderLen; buffer.FreeLen() < need { - header = make([]byte, need) - } else { - header = buffer.FreeBytes()[:need] - } - _, err := io.ReadFull(vc.ExtendedReader, header) - if err != nil { - return err - } - pos := 0 - if vc.readFilterUUID { - vc.readFilterUUID = false - pos = uuid.Size - if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 { - err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", - uuid.FromBytesOrNil(header[:uuid.Size]).String()) - log.Errorln(err.Error()) - return err - } - } - vc.readLastCommand = header[pos] - vc.readRemainingContent = int(binary.BigEndian.Uint16(header[pos+1:])) - vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[pos+3:])) - log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", - vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) - return vc.ReadBuffer(buffer) - //} - case commandPaddingEnd: - vc.readProcess = false - return vc.ReadBuffer(buffer) - case commandPaddingDirect: - needReturn := false - if vc.input != nil { - _, err := buffer.ReadFrom(vc.input) - if err != nil { - return err - } - if vc.input.Len() == 0 { - needReturn = true - vc.input = nil - } else { // buffer is full - return nil - } - } - if vc.rawInput != nil { - _, err := buffer.ReadFrom(vc.rawInput) - if err != nil { - return err - } - needReturn = true - if vc.rawInput.Len() == 0 { - vc.rawInput = nil - } - } - if vc.input == nil && vc.rawInput == nil { - vc.readProcess = false - vc.ExtendedReader = N.NewExtendedReader(vc.Conn) - log.Debugln("XTLS Vision direct read start") - } - if needReturn { - return nil - } - default: - err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) - log.Debugln(err.Error()) - return err - } - } return vc.ExtendedReader.ReadBuffer(buffer) } @@ -177,7 +52,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { return err } vc.received = true - return vc.ReadBuffer(buffer) + return vc.ExtendedReader.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { @@ -200,18 +75,6 @@ func (vc *Conn) Write(p []byte) (int, error) { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - _buffer := buf.StackNew() - defer buf.KeepAlive(_buffer) - buffer := buf.Dup(_buffer) - defer buffer.Release() - buffer.Write(p) - err := vc.WriteBuffer(buffer) - if err != nil { - return 0, err - } - return len(p), nil - } return vc.ExtendedWriter.Write(p) } @@ -232,63 +95,6 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - buffer2 := ReshapeBuffer(buffer) - defer buffer2.Release() - vc.FilterTLS(buffer.Bytes()) - command := commandPaddingContinue - if !vc.isTLS { - command = commandPaddingEnd - - // disable XTLS - //vc.readProcess = false - vc.writeFilterApplicationData = false - vc.packetsToFilter = 0 - } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer, command, nil, vc.isTLS) - err := vc.ExtendedWriter.WriteBuffer(buffer) - if err != nil { - return err - } - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(5 * time.Millisecond) - } - if buffer2 != nil { - if vc.writeDirect || !vc.isTLS { - return vc.ExtendedWriter.WriteBuffer(buffer2) - } - vc.FilterTLS(buffer2.Bytes()) - command = commandPaddingContinue - if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer2, command, nil, vc.isTLS) - err = vc.ExtendedWriter.WriteBuffer(buffer2) - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(10 * time.Millisecond) - } - } - return err - } - /*if vc.writeDirect { - log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) - }*/ return vc.ExtendedWriter.WriteBuffer(buffer) } @@ -300,10 +106,9 @@ func (vc *Conn) sendRequest(p []byte) bool { return true } } - isVision := vc.IsXTLSVisionEnabled() var buffer *buf.Buffer - if isVision { + if vc.IsXTLSVisionEnabled() { _buffer := buf.StackNew() defer buf.KeepAlive(_buffer) buffer = buf.Dup(_buffer) @@ -350,50 +155,14 @@ func (vc *Conn) sendRequest(p []byte) bool { ) } - if isVision && !vc.dst.UDP && !vc.dst.Mux { - if len(p) == 0 { - WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id, vc.isTLS) - } else { - vc.FilterTLS(p) - //if vc.isTLS { - WriteWithPadding(buffer, p, commandPaddingContinue, vc.id, vc.isTLS) - //} else { - // buf.Must(buf.Error(buffer.Write(p))) - // - // // disable XTLS - // vc.readProcess = false - // vc.writeFilterApplicationData = false - // vc.packetsToFilter = 0 - //} - } - } else { - buf.Must(buf.Error(buffer.Write(p))) - } + buf.Must(buf.Error(buffer.Write(p))) _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) - if vc.err != nil { - return true - } - if isVision { - switch underlying := vc.tlsConn.(type) { - case *gotls.Conn: - if underlying.ConnectionState().Version != gotls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - case *utls.UConn: - if underlying.ConnectionState().Version != utls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - default: - vc.err = fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, vc.addons.Flow) - } - vc.tlsConn = nil - } return true } func (vc *Conn) recvResponse() error { - var buffer [1]byte + var buffer [2]byte _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) if vc.err != nil { return vc.err @@ -403,12 +172,7 @@ func (vc *Conn) recvResponse() error { return errors.New("unexpected response version") } - _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) - if vc.err != nil { - return vc.err - } - - length := int64(buffer[0]) + length := int64(buffer[1]) if length != 0 { // addon data length > 0 io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard } @@ -416,18 +180,8 @@ func (vc *Conn) recvResponse() error { return nil } -func (vc *Conn) FrontHeadroom() int { - if vc.IsXTLSVisionEnabled() { - return paddingHeaderLen - } - return 0 -} - func (vc *Conn) Upstream() any { - if vc.tlsConn == nil { - return vc.Conn - } - return vc.tlsConn + return vc.Conn } func (vc *Conn) NeedHandshake() bool { @@ -439,7 +193,7 @@ func (vc *Conn) IsXTLSVisionEnabled() bool { } // newConn return a Conn instance -func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { +func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { c := &Conn{ ExtendedReader: N.NewExtendedReader(conn), ExtendedWriter: N.NewExtendedWriter(conn), @@ -468,43 +222,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } case XRV: - c.packetsToFilter = 6 - c.readProcess = true - c.readFilterUUID = true - c.writeFilterApplicationData = true - c.addons = client.Addons - var t reflect.Type - var p unsafe.Pointer - switch underlying := conn.(type) { - case *gotls.Conn: - //log.Debugln("type tls") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *utls.UConn: - //log.Debugln("type *utls.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying.Conn).Elem() - p = unsafe.Pointer(underlying.Conn) - case *tlsC.UConn: - //log.Debugln("type *tlsC.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying.UConn - t = reflect.TypeOf(underlying.Conn).Elem() - //log.Debugln("t:%v", t) - p = unsafe.Pointer(underlying.Conn) - default: - return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) + visionConn, err := vision.NewConn(c, c.id) + if err != nil { + return nil, err } - i, _ := t.FieldByName("input") - r, _ := t.FieldByName("rawInput") - c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) - c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) - //if _, ok := c.Conn.(*net.TCPConn); !ok { - // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) - //} + c.addons = client.Addons + return visionConn, nil } } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go new file mode 100644 index 00000000..650d094d --- /dev/null +++ b/transport/vless/vision/conn.go @@ -0,0 +1,274 @@ +package vision + +import ( + "bytes" + "crypto/subtle" + gotls "crypto/tls" + "encoding/binary" + "fmt" + "io" + "net" + + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/log" + + "github.com/gofrs/uuid/v5" + utls "github.com/sagernet/utls" +) + +var ( + _ N.ExtendedConn = (*Conn)(nil) +) + +type Conn struct { + net.Conn + N.ExtendedReader + N.ExtendedWriter + upstream net.Conn + userUUID *uuid.UUID + + tlsConn net.Conn + input *bytes.Reader + rawInput *bytes.Buffer + + needHandshake bool + packetsToFilter int + isTLS bool + isTLS12orAbove bool + enableXTLS bool + cipher uint16 + remainingServerHello uint16 + readRemainingContent int + readRemainingPadding int + readProcess bool + readFilterUUID bool + readLastCommand byte + writeFilterApplicationData bool + writeDirect bool +} + +func (vc *Conn) Read(b []byte) (int, error) { + if vc.readProcess { + buffer := buf.With(b) + err := vc.ReadBuffer(buffer) + return buffer.Len(), err + } + return vc.ExtendedReader.Read(b) +} + +func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { + toRead := buffer.FreeBytes() + if vc.readRemainingContent > 0 { + if vc.readRemainingContent < buffer.FreeLen() { + toRead = toRead[:vc.readRemainingContent] + } + n, err := vc.ExtendedReader.Read(toRead) + buffer.Truncate(n) + vc.readRemainingContent -= n + vc.FilterTLS(toRead) + return err + } + if vc.readRemainingPadding > 0 { + _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) + if err != nil { + return err + } + vc.readRemainingPadding = 0 + } + if vc.readProcess { + switch vc.readLastCommand { + case commandPaddingContinue: + //if vc.isTLS || vc.packetsToFilter > 0 { + headerUUIDLen := 0 + if vc.readFilterUUID { + headerUUIDLen = uuid.Size + } + var header []byte + if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need { + header = make([]byte, need) + } else { + header = buffer.FreeBytes()[:need] + } + _, err := io.ReadFull(vc.ExtendedReader, header) + if err != nil { + return err + } + if vc.readFilterUUID { + vc.readFilterUUID = false + if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", + uuid.FromBytesOrNil(header[:uuid.Size]).String()) + log.Errorln(err.Error()) + return err + } + header = header[uuid.Size:] + } + vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[3:])) + vc.readRemainingContent = int(binary.BigEndian.Uint16(header[1:])) + vc.readLastCommand = header[0] + log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", + vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) + return vc.ReadBuffer(buffer) + //} + case commandPaddingEnd: + vc.readProcess = false + return vc.ReadBuffer(buffer) + case commandPaddingDirect: + needReturn := false + if vc.input != nil { + _, err := buffer.ReadFrom(vc.input) + if err != nil { + return err + } + if vc.input.Len() == 0 { + needReturn = true + vc.input = nil + } else { // buffer is full + return nil + } + } + if vc.rawInput != nil { + _, err := buffer.ReadFrom(vc.rawInput) + if err != nil { + return err + } + needReturn = true + if vc.rawInput.Len() == 0 { + vc.rawInput = nil + } + } + if vc.input == nil && vc.rawInput == nil { + vc.readProcess = false + vc.ExtendedReader = N.NewExtendedReader(vc.Conn) + log.Debugln("XTLS Vision direct read start") + } + if needReturn { + return nil + } + default: + err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) + log.Debugln(err.Error()) + return err + } + } + return vc.ExtendedReader.ReadBuffer(buffer) +} + +func (vc *Conn) Write(p []byte) (int, error) { + if vc.writeFilterApplicationData { + _buffer := buf.StackNew() + defer buf.KeepAlive(_buffer) + buffer := buf.Dup(_buffer) + defer buffer.Release() + buffer.Write(p) + err := vc.WriteBuffer(buffer) + if err != nil { + return 0, err + } + return len(p), nil + } + return vc.ExtendedWriter.Write(p) +} + +func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { + if vc.needHandshake { + vc.needHandshake = false + if buffer.IsEmpty() { + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false) + } else { + vc.FilterTLS(buffer.Bytes()) + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS) + } + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + buffer.Release() + return err + } + switch underlying := vc.tlsConn.(type) { + case *gotls.Conn: + if underlying.ConnectionState().Version != gotls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + case *utls.UConn: + if underlying.ConnectionState().Version != utls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + } + vc.tlsConn = nil + return nil + } + + if vc.writeFilterApplicationData { + buffer2 := ReshapeBuffer(buffer) + defer buffer2.Release() + vc.FilterTLS(buffer.Bytes()) + command := commandPaddingContinue + if !vc.isTLS { + command = commandPaddingEnd + + // disable XTLS + //vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 + } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + return err + } + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(5 * time.Millisecond) + } + if buffer2 != nil { + if vc.writeDirect || !vc.isTLS { + return vc.ExtendedWriter.WriteBuffer(buffer2) + } + vc.FilterTLS(buffer2.Bytes()) + command = commandPaddingContinue + if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer2, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer2) + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(10 * time.Millisecond) + } + } + return err + } + /*if vc.writeDirect { + log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) + }*/ + return vc.ExtendedWriter.WriteBuffer(buffer) +} + +func (vc *Conn) FrontHeadroom() int { + return PaddingHeaderLen +} + +func (vc *Conn) NeedHandshake() bool { + return vc.needHandshake +} + +func (vc *Conn) Upstream() any { + return vc.upstream +} diff --git a/transport/vless/filter.go b/transport/vless/vision/filter.go similarity index 99% rename from transport/vless/filter.go rename to transport/vless/vision/filter.go index f577be7a..e070de35 100644 --- a/transport/vless/filter.go +++ b/transport/vless/vision/filter.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" diff --git a/transport/vless/vision.go b/transport/vless/vision/padding.go similarity index 94% rename from transport/vless/vision.go rename to transport/vless/vision/padding.go index 5649dde4..d5a230d1 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision/padding.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" @@ -12,7 +12,7 @@ import ( ) const ( - paddingHeaderLen = 1 + 2 + 2 // =5 + PaddingHeaderLen = uuid.Size + 1 + 2 + 2 // =21 commandPaddingContinue byte = 0x00 commandPaddingEnd byte = 0x01 @@ -67,7 +67,7 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding } func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer { - if buffer.Len() <= buf.BufferSize-paddingHeaderLen { + if buffer.Len() <= buf.BufferSize-PaddingHeaderLen { return nil } cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart) diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go new file mode 100644 index 00000000..3b52dd4b --- /dev/null +++ b/transport/vless/vision/vision.go @@ -0,0 +1,70 @@ +// Package vision implements VLESS flow `xtls-rprx-vision` introduced by Xray-core. +package vision + +import ( + "bytes" + gotls "crypto/tls" + "errors" + "fmt" + "net" + "reflect" + "unsafe" + + N "github.com/Dreamacro/clash/common/net" + tlsC "github.com/Dreamacro/clash/component/tls" + + "github.com/gofrs/uuid/v5" + "github.com/sagernet/sing/common" + utls "github.com/sagernet/utls" +) + +var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") + +type connWithUpstream interface { + net.Conn + common.WithUpstream +} + +func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) { + c := &Conn{ + ExtendedReader: N.NewExtendedReader(conn), + ExtendedWriter: N.NewExtendedWriter(conn), + upstream: conn, + userUUID: userUUID, + packetsToFilter: 6, + needHandshake: true, + readProcess: true, + readFilterUUID: true, + writeFilterApplicationData: true, + } + var t reflect.Type + var p unsafe.Pointer + switch underlying := conn.Upstream().(type) { + case *gotls.Conn: + //log.Debugln("type tls") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + case *utls.UConn: + //log.Debugln("type *utls.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying.Conn).Elem() + p = unsafe.Pointer(underlying.Conn) + case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying.UConn + t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) + p = unsafe.Pointer(underlying.Conn) + default: + return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`) + } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) + c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) + return c, nil +} diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index 09929fc3..071e6e8f 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -2,17 +2,12 @@ package vless import ( "context" - "errors" "net" tlsC "github.com/Dreamacro/clash/component/tls" xtls "github.com/xtls/go" ) -var ( - ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") -) - type XTLSConfig struct { Host string SkipCertVerify bool