DRAFT 3
This commit is contained in:
parent
abced62f4d
commit
fc58f80cc8
@ -479,7 +479,7 @@ func NewVless(option VlessOption) (*Vless, error) {
|
|||||||
if option.Network != "ws" && len(option.Flow) >= 16 {
|
if option.Network != "ws" && len(option.Flow) >= 16 {
|
||||||
option.Flow = option.Flow[:16]
|
option.Flow = option.Flow[:16]
|
||||||
switch option.Flow {
|
switch option.Flow {
|
||||||
case vless.XRO, vless.XRD, vless.XRS:
|
case vless.XRO, vless.XRD, vless.XRS, vless.XRV:
|
||||||
addons = &vless.Addons{
|
addons = &vless.Addons{
|
||||||
Flow: option.Flow,
|
Flow: option.Flow,
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,6 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
utls "github.com/refraction-networking/utls"
|
|
||||||
buf2 "github.com/sagernet/sing/common/buf"
|
|
||||||
"github.com/sagernet/sing/common/network"
|
|
||||||
"github.com/sagernet/sing/common/rw"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -23,7 +17,13 @@ import (
|
|||||||
"github.com/Dreamacro/clash/common/buf"
|
"github.com/Dreamacro/clash/common/buf"
|
||||||
N "github.com/Dreamacro/clash/common/net"
|
N "github.com/Dreamacro/clash/common/net"
|
||||||
|
|
||||||
|
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
|
utls "github.com/refraction-networking/utls"
|
||||||
|
buf2 "github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/sing/common/network"
|
||||||
|
"github.com/sagernet/sing/common/rw"
|
||||||
xtls "github.com/xtls/go"
|
xtls "github.com/xtls/go"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
@ -54,7 +54,6 @@ type Conn struct {
|
|||||||
readRemainingContent int
|
readRemainingContent int
|
||||||
readRemainingPadding int
|
readRemainingPadding int
|
||||||
readFilter bool
|
readFilter bool
|
||||||
readDirect bool
|
|
||||||
readLastCommand byte
|
readLastCommand byte
|
||||||
writeFilterApplicationData bool
|
writeFilterApplicationData bool
|
||||||
writeDirect bool
|
writeDirect bool
|
||||||
@ -84,35 +83,44 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||||||
if vc.readRemainingContent < buffer.FreeLen() {
|
if vc.readRemainingContent < buffer.FreeLen() {
|
||||||
toRead = toRead[:vc.readRemainingContent]
|
toRead = toRead[:vc.readRemainingContent]
|
||||||
}
|
}
|
||||||
n, err := vc.ExtendedReader.Read(buffer.FreeBytes())
|
n, err := vc.ExtendedReader.Read(toRead)
|
||||||
buffer.Truncate(n)
|
buffer.Truncate(n)
|
||||||
vc.readRemainingPadding -= n
|
vc.readRemainingContent -= n
|
||||||
|
vc.FilterTLS(buffer.Bytes())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if vc.readRemainingPadding > 0 {
|
if vc.readRemainingPadding > 0 {
|
||||||
rw.SkipN(vc.ExtendedReader, vc.readRemainingPadding)
|
err := rw.SkipN(vc.ExtendedReader, vc.readRemainingPadding)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vc.readRemainingPadding = 0
|
||||||
}
|
}
|
||||||
if vc.readFilter {
|
if vc.readFilter {
|
||||||
switch vc.readLastCommand {
|
switch vc.readLastCommand {
|
||||||
case commandPaddingContinue:
|
case commandPaddingContinue:
|
||||||
if vc.isTLS || vc.packetsToFilter > 0 {
|
//if vc.isTLS || vc.packetsToFilter > 0 {
|
||||||
header := buffer.FreeBytes()[:paddingHeaderLen]
|
header := buffer.FreeBytes()[:paddingHeaderLen]
|
||||||
_, err := io.ReadFull(vc.ExtendedReader, header)
|
_, err := io.ReadFull(vc.ExtendedReader, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 {
|
|
||||||
return fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
|
|
||||||
uuid.FromBytesOrNil(header[:uuid.Size]).String())
|
|
||||||
}
|
|
||||||
vc.readLastCommand = header[uuid.Size]
|
|
||||||
vc.readRemainingContent = int(binary.BigEndian.Uint16(header[uuid.Size+1:]))
|
|
||||||
vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[uuid.Size+3:]))
|
|
||||||
return vc.ReadBuffer(buffer)
|
|
||||||
}
|
}
|
||||||
|
if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 {
|
||||||
|
return fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
|
||||||
|
uuid.FromBytesOrNil(header[:uuid.Size]).String())
|
||||||
|
}
|
||||||
|
vc.readLastCommand = header[uuid.Size]
|
||||||
|
vc.readRemainingContent = int(binary.BigEndian.Uint16(header[uuid.Size+1:]))
|
||||||
|
vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[uuid.Size+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:
|
case commandPaddingEnd:
|
||||||
vc.readFilter = false
|
vc.readFilter = false
|
||||||
|
return vc.ReadBuffer(buffer)
|
||||||
case commandPaddingDirect:
|
case commandPaddingDirect:
|
||||||
|
log.Debugln("command read direct")
|
||||||
if vc.input != nil {
|
if vc.input != nil {
|
||||||
_, err := buffer.ReadFrom(vc.input)
|
_, err := buffer.ReadFrom(vc.input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -121,6 +129,9 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||||||
if vc.input.Len() == 0 {
|
if vc.input.Len() == 0 {
|
||||||
vc.input = nil
|
vc.input = nil
|
||||||
}
|
}
|
||||||
|
if buffer.IsFull() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if vc.rawInput != nil {
|
if vc.rawInput != nil {
|
||||||
_, err := buffer.ReadFrom(vc.rawInput)
|
_, err := buffer.ReadFrom(vc.rawInput)
|
||||||
@ -134,7 +145,10 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||||||
if vc.input == nil && vc.rawInput == nil {
|
if vc.input == nil && vc.rawInput == nil {
|
||||||
vc.readFilter = false
|
vc.readFilter = false
|
||||||
vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
|
vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
|
||||||
|
log.Debugln("XTLS Vision Direct read start")
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
log.Debugln("XTLS Vision read unknown command: %d", vc.readLastCommand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vc.ExtendedReader.ReadBuffer(buffer)
|
return vc.ExtendedReader.ReadBuffer(buffer)
|
||||||
@ -190,44 +204,51 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error {
|
|||||||
if vc.writeFilterApplicationData && vc.isTLS {
|
if vc.writeFilterApplicationData && vc.isTLS {
|
||||||
buffer2 := ReshapeBuffer(buffer)
|
buffer2 := ReshapeBuffer(buffer)
|
||||||
defer buffer2.Release()
|
defer buffer2.Release()
|
||||||
if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) {
|
vc.FilterTLS(buffer.Bytes())
|
||||||
command := commandPaddingEnd
|
command := commandPaddingContinue
|
||||||
|
if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||||
|
command = commandPaddingEnd
|
||||||
if vc.enableXTLS {
|
if vc.enableXTLS {
|
||||||
command = commandPaddingDirect
|
command = commandPaddingDirect
|
||||||
vc.writeDirect = true
|
vc.writeDirect = true
|
||||||
}
|
}
|
||||||
vc.writeFilterApplicationData = false
|
vc.writeFilterApplicationData = false
|
||||||
ApplyPadding(buffer, command, vc.id)
|
|
||||||
}
|
}
|
||||||
|
ApplyPadding(buffer, command, vc.id)
|
||||||
err := vc.ExtendedWriter.WriteBuffer(buffer)
|
err := vc.ExtendedWriter.WriteBuffer(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if vc.writeDirect {
|
if vc.writeDirect {
|
||||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(20 * time.Millisecond)
|
||||||
}
|
}
|
||||||
if buffer2 != nil {
|
if buffer2 != nil {
|
||||||
if vc.writeDirect {
|
if vc.writeDirect {
|
||||||
return vc.ExtendedWriter.WriteBuffer(buffer2)
|
return vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||||
}
|
}
|
||||||
if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) {
|
vc.FilterTLS(buffer2.Bytes())
|
||||||
command := commandPaddingEnd
|
command = commandPaddingContinue
|
||||||
|
if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||||
|
command = commandPaddingEnd
|
||||||
if vc.enableXTLS {
|
if vc.enableXTLS {
|
||||||
command = commandPaddingDirect
|
command = commandPaddingDirect
|
||||||
vc.writeDirect = true
|
vc.writeDirect = true
|
||||||
}
|
}
|
||||||
vc.writeFilterApplicationData = false
|
vc.writeFilterApplicationData = false
|
||||||
ApplyPadding(buffer2, command, vc.id)
|
|
||||||
}
|
}
|
||||||
|
ApplyPadding(buffer2, command, vc.id)
|
||||||
err = vc.ExtendedWriter.WriteBuffer(buffer2)
|
err = vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||||
}
|
if vc.writeDirect {
|
||||||
if vc.writeDirect {
|
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
time.Sleep(20 * time.Millisecond)
|
||||||
time.Sleep(5 * time.Millisecond)
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if vc.writeDirect {
|
||||||
|
log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len())
|
||||||
|
}
|
||||||
return vc.ExtendedWriter.WriteBuffer(buffer)
|
return vc.ExtendedWriter.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +397,10 @@ func (vc *Conn) FrontHeadroom() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (vc *Conn) Upstream() any {
|
func (vc *Conn) Upstream() any {
|
||||||
return vc.Conn
|
if vc.tlsConn == nil {
|
||||||
|
return vc.Conn
|
||||||
|
}
|
||||||
|
return vc.tlsConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vc *Conn) IsXTLSVisionEnabled() bool {
|
func (vc *Conn) IsXTLSVisionEnabled() bool {
|
||||||
@ -413,9 +437,10 @@ 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)
|
return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow)
|
||||||
}
|
}
|
||||||
case XRV:
|
case XRV:
|
||||||
c.packetsToFilter = 2048
|
c.packetsToFilter = 10
|
||||||
c.readFilter = true
|
c.readFilter = true
|
||||||
c.writeFilterApplicationData = true
|
c.writeFilterApplicationData = true
|
||||||
|
c.addons = client.Addons
|
||||||
var t reflect.Type
|
var t reflect.Type
|
||||||
var p uintptr
|
var p uintptr
|
||||||
switch underlying := conn.(type) {
|
switch underlying := conn.(type) {
|
||||||
|
@ -7,12 +7,13 @@ import (
|
|||||||
|
|
||||||
"github.com/Dreamacro/clash/common/buf"
|
"github.com/Dreamacro/clash/common/buf"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
buf2 "github.com/sagernet/sing/common/buf"
|
buf2 "github.com/sagernet/sing/common/buf"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
paddingHeaderLen = 16 + 1 + 2 + 2 // =21
|
paddingHeaderLen = uuid.Size + 1 + 2 + 2 // =21
|
||||||
|
|
||||||
commandPaddingContinue byte = 0x00
|
commandPaddingContinue byte = 0x00
|
||||||
commandPaddingEnd byte = 0x01
|
commandPaddingEnd byte = 0x01
|
||||||
@ -34,6 +35,7 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid
|
|||||||
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen))
|
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen))
|
||||||
buffer.Write(p)
|
buffer.Write(p)
|
||||||
buffer.Extend(int(paddingLen))
|
buffer.Extend(int(paddingLen))
|
||||||
|
log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID) {
|
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID) {
|
||||||
@ -50,6 +52,7 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID) {
|
|||||||
copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes())
|
copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes())
|
||||||
}
|
}
|
||||||
buffer.Extend(int(paddingLen))
|
buffer.Extend(int(paddingLen))
|
||||||
|
log.Debugln("XTLS Vision write padding2: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer {
|
func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer {
|
||||||
|
Reference in New Issue
Block a user