Update vision protocol

This commit is contained in:
世界 2023-02-27 15:07:15 +08:00
parent 5ce3ddee9b
commit e4bff0460d
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
6 changed files with 92 additions and 53 deletions

View file

@ -50,7 +50,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
ctx: ctx,
users: options.Users,
}
service := vless.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
service := vless.NewService[int](logger, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
service.UpdateUsers(common.MapIndexed(inbound.users, func(index int, _ option.VLESSUser) int {
return index
}), common.Map(inbound.users, func(it option.VLESSUser) string {

View file

@ -67,7 +67,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
default:
return nil, E.New("unknown packet encoding: ", options.PacketEncoding)
}
outbound.client, err = vless.NewClient(options.UUID, options.Flow)
outbound.client, err = vless.NewClient(options.UUID, options.Flow, logger)
if err != nil {
return nil, err
}

View file

@ -9,6 +9,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@ -18,9 +19,10 @@ import (
type Client struct {
key [16]byte
flow string
logger logger.Logger
}
func NewClient(userId string, flow string) (*Client, error) {
func NewClient(userId string, flow string, logger logger.Logger) (*Client, error) {
user := uuid.FromStringOrNil(userId)
if user == uuid.Nil {
user = uuid.NewV5(user, userId)
@ -30,12 +32,12 @@ func NewClient(userId string, flow string) (*Client, error) {
default:
return nil, E.New("unsupported flow: " + flow)
}
return &Client{user, flow}, nil
return &Client{user, flow, logger}, nil
}
func (c *Client) prepareConn(conn net.Conn) (net.Conn, error) {
if c.flow == FlowVision {
vConn, err := NewVisionConn(conn, c.key)
vConn, err := NewVisionConn(conn, c.key, c.logger)
if err != nil {
return nil, E.Cause(err, "initialize vision")
}

View file

@ -11,6 +11,10 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
commandPaddingContinue byte = 0
commandPaddingEnd byte = 1
commandPaddingDirect byte = 2
)
var tls13CipherSuiteDic = map[uint16]string{

View file

@ -11,6 +11,7 @@ import (
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@ -19,6 +20,7 @@ import (
type Service[T any] struct {
userMap map[[16]byte]T
logger logger.Logger
handler Handler
}
@ -28,8 +30,9 @@ type Handler interface {
E.Handler
}
func NewService[T any](handler Handler) *Service[T] {
func NewService[T any](logger logger.Logger, handler Handler) *Service[T] {
return &Service[T]{
logger: logger,
handler: handler,
}
}
@ -64,7 +67,7 @@ func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata
switch request.Flow {
case "":
case FlowVision:
protocolConn, err = NewVisionConn(conn, request.UUID)
protocolConn, err = NewVisionConn(conn, request.UUID, s.logger)
if err != nil {
return E.Cause(err, "initialize vision")
}

View file

@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
)
@ -37,6 +38,7 @@ type VisionConn struct {
input *bytes.Reader
rawInput *bytes.Buffer
netConn net.Conn
logger logger.Logger
userUUID [16]byte
isTLS bool
@ -45,10 +47,10 @@ type VisionConn struct {
remainingServerHello int32
cipher uint16
enableXTLS bool
filterTlsApplicationData bool
isPadding bool
directWrite bool
writeUUID bool
filterUUID bool
withinPaddingBuffers bool
remainingContent int
remainingPadding int
currentCommand int
@ -56,7 +58,7 @@ type VisionConn struct {
remainingReader io.Reader
}
func NewVisionConn(conn net.Conn, userUUID [16]byte) (*VisionConn, error) {
func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
var (
loaded bool
reflectType reflect.Type
@ -80,12 +82,14 @@ func NewVisionConn(conn net.Conn, userUUID [16]byte) (*VisionConn, error) {
input: (*bytes.Reader)(unsafe.Pointer(reflectPointer + input.Offset)),
rawInput: (*bytes.Buffer)(unsafe.Pointer(reflectPointer + rawInput.Offset)),
netConn: netConn,
logger: logger,
userUUID: userUUID,
numberOfPacketToFilter: 8,
remainingServerHello: -1,
filterTlsApplicationData: true,
isPadding: true,
writeUUID: true,
filterUUID: true,
withinPaddingBuffers: true,
remainingContent: -1,
remainingPadding: -1,
}, nil
@ -97,6 +101,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
if err == io.EOF {
c.remainingReader = nil
if n > 0 {
err = nil
return
}
}
@ -109,13 +114,15 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
return
}
buffer := p[:n]
if c.filterUUID && (c.isTLS || c.numberOfPacketToFilter > 0) {
if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 {
buffers := c.unPadding(buffer)
if c.remainingContent == 0 && c.remainingPadding == 0 {
if c.currentCommand == 1 {
c.filterUUID = false
c.withinPaddingBuffers = false
c.remainingContent = -1
c.remainingPadding = -1
} else if c.currentCommand == 2 {
c.filterUUID = false
c.withinPaddingBuffers = false
c.directRead = true
inputBuffer, err := io.ReadAll(c.input)
@ -130,9 +137,17 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
}
buffers = append(buffers, rawInputBuffer)
} else if c.currentCommand != 0 {
c.logger.Trace("XtlsRead readV")
} else if c.currentCommand == 0 {
c.withinPaddingBuffers = true
} else {
return 0, E.New("unknown command ", c.currentCommand)
}
} else if c.remainingContent > 0 || c.remainingPadding > 0 {
c.withinPaddingBuffers = true
} else {
c.withinPaddingBuffers = false
}
if c.numberOfPacketToFilter > 0 {
c.filterTLS(buffers)
@ -151,27 +166,27 @@ func (c *VisionConn) Write(p []byte) (n int, err error) {
if c.numberOfPacketToFilter > 0 {
c.filterTLS([][]byte{p})
}
if c.isTLS && c.filterTlsApplicationData {
if c.isPadding {
inputLen := len(p)
buffers := reshapeBuffer(p)
var specIndex int
for i, buffer := range buffers {
if buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) {
var command byte = 1
if c.isTLS && buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) {
var command byte = commandPaddingEnd
if c.enableXTLS {
c.directWrite = true
specIndex = i
command = 2
command = commandPaddingDirect
}
c.filterTlsApplicationData = false
c.isPadding = false
buffers[i] = c.padding(buffer, command)
break
} else if !c.isTLS12orAbove && c.numberOfPacketToFilter == 0 {
c.filterTlsApplicationData = false
buffers[i] = c.padding(buffer, 0x01)
} else if !c.isTLS12orAbove && c.numberOfPacketToFilter <= 1 {
c.isPadding = false
buffers[i] = c.padding(buffer, commandPaddingEnd)
break
}
buffers[i] = c.padding(buffer, 0x00)
buffers[i] = c.padding(buffer, commandPaddingContinue)
}
if c.directWrite {
encryptedBuffer := buffers[:specIndex+1]
@ -181,6 +196,7 @@ func (c *VisionConn) Write(p []byte) (n int, err error) {
}
buffers = buffers[specIndex+1:]
c.writer = bufio.NewVectorisedWriter(c.netConn)
c.logger.Trace("XtlsWrite writeV ", specIndex, " ", buf.LenMulti(encryptedBuffer), " ", len(buffers))
time.Sleep(5 * time.Millisecond) // wtf
}
err = c.writer.WriteVectorised(buffers)
@ -209,10 +225,13 @@ func (c *VisionConn) filterTLS(buffers [][]byte) {
sessionIdLen := int32(buffer[43])
cipherSuite := buffer[43+sessionIdLen+1 : 43+sessionIdLen+3]
c.cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1])
} else {
c.logger.Trace("XtlsFilterTls short server hello, tls 1.2 or older? ", len(buffer), " ", c.remainingServerHello)
}
}
} else if bytes.Equal(tlsClientHandShakeStart, buffer[:2]) && buffer[5] == 1 {
c.isTLS = true
c.logger.Trace("XtlsFilterTls found tls client hello! ", len(buffer))
}
}
if c.remainingServerHello > 0 {
@ -226,13 +245,18 @@ func (c *VisionConn) filterTLS(buffers [][]byte) {
if ok && cipher != "TLS_AES_128_CCM_8_SHA256" {
c.enableXTLS = true
}
c.logger.Trace("XtlsFilterTls found tls 1.3! ", len(buffer), " ", c.cipher, " ", c.enableXTLS)
c.numberOfPacketToFilter = 0
return
} else if c.remainingServerHello == 0 {
c.logger.Trace("XtlsFilterTls found tls 1.2! ", len(buffer))
c.numberOfPacketToFilter = 0
return
}
}
if c.numberOfPacketToFilter == 0 {
c.logger.Trace("XtlsFilterTls stop filtering ", len(buffer))
}
}
}
@ -242,9 +266,12 @@ func (c *VisionConn) padding(buffer *buf.Buffer, command byte) *buf.Buffer {
if buffer != nil {
contentLen = buffer.Len()
}
if contentLen < 900 {
if contentLen < 900 && c.isTLS {
l, _ := rand.Int(rand.Reader, big.NewInt(500))
paddingLen = int(l.Int64()) + 900 - contentLen
} else {
l, _ := rand.Int(rand.Reader, big.NewInt(256))
paddingLen = int(l.Int64())
}
newBuffer := buf.New()
if c.writeUUID {
@ -257,6 +284,7 @@ func (c *VisionConn) padding(buffer *buf.Buffer, command byte) *buf.Buffer {
buffer.Release()
}
newBuffer.Extend(paddingLen)
c.logger.Trace("XtlsPadding ", contentLen, " ", paddingLen, " ", command)
return newBuffer
}
@ -267,6 +295,7 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
bufferIndex = 16
c.remainingContent = 0
c.remainingPadding = 0
c.currentCommand = 0
}
}
if c.remainingContent == -1 && c.remainingPadding == -1 {
@ -284,6 +313,7 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
c.remainingContent = int(paddingInfo[1])<<8 | int(paddingInfo[2])
c.remainingPadding = int(paddingInfo[3])<<8 | int(paddingInfo[4])
bufferIndex += 5
c.logger.Trace("Xtls Unpadding new block ", bufferIndex, " ", c.remainingContent, " padding ", c.remainingPadding, " ", c.currentCommand)
}
} else if c.remainingContent > 0 {
end := c.remainingContent