mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-09 18:43:14 +00:00
Improve VLESS request
This commit is contained in:
parent
a62ad44883
commit
8eb7dd0059
|
@ -135,7 +135,7 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn
|
|||
|
||||
hello.SessionId[0] = 1
|
||||
hello.SessionId[1] = 8
|
||||
hello.SessionId[2] = 0
|
||||
hello.SessionId[2] = 1
|
||||
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
|
||||
copy(hello.SessionId[8:], e.shortID[:])
|
||||
|
||||
|
|
|
@ -141,6 +141,95 @@ func TestVLESSVisionReality(t *testing.T) {
|
|||
testSuit(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func TestVLESSVisionRealityPlain(t *testing.T) {
|
||||
userUUID := newUUID()
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
MixedOptions: option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeVLESS,
|
||||
VLESSOptions: option.VLESSInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Users: []option.VLESSUser{
|
||||
{
|
||||
Name: "sekai",
|
||||
UUID: userUUID.String(),
|
||||
Flow: vless.FlowVision,
|
||||
},
|
||||
},
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "google.com",
|
||||
Reality: &option.InboundRealityOptions{
|
||||
Enabled: true,
|
||||
Handshake: option.InboundRealityHandshakeOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "google.com",
|
||||
ServerPort: 443,
|
||||
},
|
||||
},
|
||||
ShortID: []string{"0123456789abcdef"},
|
||||
PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeVLESS,
|
||||
Tag: "vless-out",
|
||||
VLESSOptions: option.VLESSOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
UUID: userUUID.String(),
|
||||
Flow: vless.FlowVision,
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "google.com",
|
||||
Reality: &option.OutboundRealityOptions{
|
||||
Enabled: true,
|
||||
ShortID: "0123456789abcdef",
|
||||
PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0",
|
||||
},
|
||||
UTLS: &option.OutboundUTLSOptions{
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
DefaultOptions: option.DefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
Outbound: "vless-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
testSuit(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func TestVLESSRealityTransport(t *testing.T) {
|
||||
t.Run("grpc", func(t *testing.T) {
|
||||
testVLESSRealityTransport(t, &option.V2RayTransportOptions{
|
||||
|
@ -160,8 +249,6 @@ func TestVLESSRealityTransport(t *testing.T) {
|
|||
}
|
||||
|
||||
func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) {
|
||||
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
|
||||
userUUID := newUUID()
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
|
@ -206,52 +293,11 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
|
|||
Transport: transport,
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeTrojan,
|
||||
Tag: "trojan",
|
||||
TrojanOptions: option.TrojanInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: otherPort,
|
||||
},
|
||||
Users: []option.TrojanUser{
|
||||
{
|
||||
Name: "sekai",
|
||||
Password: userUUID.String(),
|
||||
},
|
||||
},
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
KeyPath: keyPem,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeTrojan,
|
||||
Tag: "trojan-out",
|
||||
TrojanOptions: option.TrojanOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: otherPort,
|
||||
},
|
||||
Password: userUUID.String(),
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
},
|
||||
DialerOptions: option.DialerOptions{
|
||||
Detour: "vless-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeVLESS,
|
||||
Tag: "vless-out",
|
||||
|
@ -282,7 +328,7 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
|
|||
{
|
||||
DefaultOptions: option.DefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
Outbound: "trojan-out",
|
||||
Outbound: "vless-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/sagernet/sing-vmess"
|
||||
"github.com/sagernet/sing/common"
|
||||
"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"
|
||||
|
@ -35,32 +36,28 @@ func NewClient(userId string, flow string, logger logger.Logger) (*Client, error
|
|||
return &Client{user, flow, logger}, nil
|
||||
}
|
||||
|
||||
func (c *Client) prepareConn(conn net.Conn) (net.Conn, error) {
|
||||
func (c *Client) prepareConn(conn net.Conn, tlsConn net.Conn) (net.Conn, error) {
|
||||
if c.flow == FlowVision {
|
||||
vConn, err := NewVisionConn(conn, c.key, c.logger)
|
||||
protocolConn, err := NewVisionConn(conn, tlsConn, c.key, c.logger)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initialize vision")
|
||||
}
|
||||
conn = vConn
|
||||
conn = protocolConn
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) {
|
||||
vConn, err := c.prepareConn(conn)
|
||||
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
|
||||
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
|
||||
protocolConn, err := c.prepareConn(remoteConn, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serverConn := &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}
|
||||
return serverConn, common.Error(serverConn.Write(nil))
|
||||
return protocolConn, common.Error(remoteConn.Write(nil))
|
||||
}
|
||||
|
||||
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) {
|
||||
vConn, err := c.prepareConn(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}, nil
|
||||
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
|
||||
return c.prepareConn(NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow), conn)
|
||||
}
|
||||
|
||||
func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) (*PacketConn, error) {
|
||||
|
@ -73,71 +70,122 @@ func (c *Client) DialEarlyPacketConn(conn net.Conn, destination M.Socksaddr) (*P
|
|||
}
|
||||
|
||||
func (c *Client) DialXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
|
||||
serverConn := &Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}
|
||||
err := common.Error(serverConn.Write(nil))
|
||||
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
|
||||
protocolConn, err := c.prepareConn(remoteConn, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vmess.NewXUDPConn(serverConn, destination), nil
|
||||
return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
|
||||
}
|
||||
|
||||
func (c *Client) DialEarlyXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
|
||||
return vmess.NewXUDPConn(&Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}, destination), nil
|
||||
remoteConn := NewConn(conn, c.key, vmess.CommandMux, destination, c.flow)
|
||||
protocolConn, err := c.prepareConn(remoteConn, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
|
||||
}
|
||||
|
||||
var _ N.EarlyConn = (*Conn)(nil)
|
||||
var (
|
||||
_ N.EarlyConn = (*Conn)(nil)
|
||||
_ N.VectorisedWriter = (*Conn)(nil)
|
||||
)
|
||||
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
protocolConn net.Conn
|
||||
key [16]byte
|
||||
command byte
|
||||
destination M.Socksaddr
|
||||
flow string
|
||||
N.ExtendedConn
|
||||
writer N.VectorisedWriter
|
||||
request Request
|
||||
requestWritten bool
|
||||
responseRead bool
|
||||
}
|
||||
|
||||
func NewConn(conn net.Conn, uuid [16]byte, command byte, destination M.Socksaddr, flow string) *Conn {
|
||||
return &Conn{
|
||||
ExtendedConn: bufio.NewExtendedConn(conn),
|
||||
writer: bufio.NewVectorisedWriter(conn),
|
||||
request: Request{
|
||||
UUID: uuid,
|
||||
Command: command,
|
||||
Destination: destination,
|
||||
Flow: flow,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) Read(b []byte) (n int, err error) {
|
||||
if !c.responseRead {
|
||||
err = ReadResponse(c.ExtendedConn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.responseRead = true
|
||||
}
|
||||
return c.ExtendedConn.Read(b)
|
||||
}
|
||||
|
||||
func (c *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
||||
if !c.responseRead {
|
||||
err := ReadResponse(c.ExtendedConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.responseRead = true
|
||||
}
|
||||
return c.ExtendedConn.ReadBuffer(buffer)
|
||||
}
|
||||
|
||||
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||
if !c.requestWritten {
|
||||
err = WriteRequest(c.ExtendedConn, c.request, b)
|
||||
if err == nil {
|
||||
n = len(b)
|
||||
}
|
||||
c.requestWritten = true
|
||||
return
|
||||
}
|
||||
return c.ExtendedConn.Write(b)
|
||||
}
|
||||
|
||||
func (c *Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
if !c.requestWritten {
|
||||
EncodeRequest(c.request, buf.With(buffer.ExtendHeader(RequestLen(c.request))))
|
||||
c.requestWritten = true
|
||||
}
|
||||
return c.ExtendedConn.WriteBuffer(buffer)
|
||||
}
|
||||
|
||||
func (c *Conn) WriteVectorised(buffers []*buf.Buffer) error {
|
||||
if !c.requestWritten {
|
||||
buffer := buf.NewSize(RequestLen(c.request))
|
||||
EncodeRequest(c.request, buffer)
|
||||
c.requestWritten = true
|
||||
return c.writer.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...))
|
||||
}
|
||||
return c.writer.WriteVectorised(buffers)
|
||||
}
|
||||
|
||||
func (c *Conn) ReaderReplaceable() bool {
|
||||
return c.responseRead
|
||||
}
|
||||
|
||||
func (c *Conn) WriterReplaceable() bool {
|
||||
return c.requestWritten
|
||||
}
|
||||
|
||||
func (c *Conn) NeedHandshake() bool {
|
||||
return !c.requestWritten
|
||||
}
|
||||
|
||||
func (c *Conn) Read(b []byte) (n int, err error) {
|
||||
if !c.responseRead {
|
||||
err = ReadResponse(c.Conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.responseRead = true
|
||||
func (c *Conn) FrontHeadroom() int {
|
||||
if c.requestWritten {
|
||||
return 0
|
||||
}
|
||||
return c.protocolConn.Read(b)
|
||||
}
|
||||
|
||||
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||
if !c.requestWritten {
|
||||
request := Request{c.key, c.command, c.destination, c.flow}
|
||||
if c.protocolConn != nil {
|
||||
err = WriteRequest(c.Conn, request, nil)
|
||||
} else {
|
||||
err = WriteRequest(c.Conn, request, b)
|
||||
}
|
||||
if err == nil {
|
||||
n = len(b)
|
||||
}
|
||||
c.requestWritten = true
|
||||
if c.protocolConn == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return c.protocolConn.Write(b)
|
||||
}
|
||||
|
||||
func (c *Conn) NeedAdditionalReadDeadline() bool {
|
||||
return true
|
||||
return RequestLen(c.request)
|
||||
}
|
||||
|
||||
func (c *Conn) Upstream() any {
|
||||
return c.Conn
|
||||
return c.ExtendedConn
|
||||
}
|
||||
|
||||
type PacketConn struct {
|
||||
|
|
|
@ -11,10 +11,12 @@ var (
|
|||
tlsClientHandShakeStart = []byte{0x16, 0x03}
|
||||
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
|
||||
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
|
||||
)
|
||||
|
||||
commandPaddingContinue byte = 0
|
||||
commandPaddingEnd byte = 1
|
||||
commandPaddingDirect byte = 2
|
||||
const (
|
||||
commandPaddingContinue byte = iota
|
||||
commandPaddingEnd
|
||||
commandPaddingDirect
|
||||
)
|
||||
|
||||
var tls13CipherSuiteDic = map[uint16]string{
|
||||
|
|
|
@ -128,7 +128,7 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
|
|||
requestLen += 1 // protobuf length
|
||||
|
||||
var addonsLen int
|
||||
if request.Command == vmess.CommandTCP && request.Flow != "" {
|
||||
if request.Flow != "" {
|
||||
addonsLen += 1 // protobuf header
|
||||
addonsLen += UvarintLen(uint64(len(request.Flow)))
|
||||
addonsLen += len(request.Flow)
|
||||
|
@ -165,6 +165,62 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
|
|||
return common.Error(writer.Write(buffer.Bytes()))
|
||||
}
|
||||
|
||||
func EncodeRequest(request Request, buffer *buf.Buffer) {
|
||||
var requestLen int
|
||||
requestLen += 1 // version
|
||||
requestLen += 16 // uuid
|
||||
requestLen += 1 // protobuf length
|
||||
|
||||
var addonsLen int
|
||||
if request.Flow != "" {
|
||||
addonsLen += 1 // protobuf header
|
||||
addonsLen += UvarintLen(uint64(len(request.Flow)))
|
||||
addonsLen += len(request.Flow)
|
||||
requestLen += addonsLen
|
||||
}
|
||||
requestLen += 1 // command
|
||||
if request.Command != vmess.CommandMux {
|
||||
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
|
||||
}
|
||||
common.Must(
|
||||
buffer.WriteByte(Version),
|
||||
common.Error(buffer.Write(request.UUID[:])),
|
||||
buffer.WriteByte(byte(addonsLen)),
|
||||
)
|
||||
if addonsLen > 0 {
|
||||
common.Must(buffer.WriteByte(10))
|
||||
binary.PutUvarint(buffer.Extend(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
|
||||
common.Must(common.Error(buffer.Write([]byte(request.Flow))))
|
||||
}
|
||||
common.Must(
|
||||
buffer.WriteByte(request.Command),
|
||||
)
|
||||
|
||||
if request.Command != vmess.CommandMux {
|
||||
common.Must(vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination))
|
||||
}
|
||||
}
|
||||
|
||||
func RequestLen(request Request) int {
|
||||
var requestLen int
|
||||
requestLen += 1 // version
|
||||
requestLen += 16 // uuid
|
||||
requestLen += 1 // protobuf length
|
||||
|
||||
var addonsLen int
|
||||
if request.Flow != "" {
|
||||
addonsLen += 1 // protobuf header
|
||||
addonsLen += UvarintLen(uint64(len(request.Flow)))
|
||||
addonsLen += len(request.Flow)
|
||||
requestLen += addonsLen
|
||||
}
|
||||
requestLen += 1 // command
|
||||
if request.Command != vmess.CommandMux {
|
||||
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
|
||||
}
|
||||
return requestLen
|
||||
}
|
||||
|
||||
func WritePacketRequest(writer io.Writer, request Request, payload []byte) error {
|
||||
var requestLen int
|
||||
requestLen += 1 // version
|
||||
|
|
|
@ -68,30 +68,32 @@ func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata
|
|||
metadata.Destination = request.Destination
|
||||
|
||||
userFlow := s.userFlow[user]
|
||||
|
||||
var responseWriter io.Writer
|
||||
if request.Command == vmess.CommandTCP {
|
||||
if request.Flow != userFlow {
|
||||
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
|
||||
}
|
||||
switch userFlow {
|
||||
case "":
|
||||
case FlowVision:
|
||||
responseWriter = conn
|
||||
conn, err = NewVisionConn(conn, request.UUID, s.logger)
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize vision")
|
||||
}
|
||||
}
|
||||
if request.Flow == FlowVision && request.Command == vmess.NetworkUDP {
|
||||
return E.New(FlowVision, " flow does not support UDP")
|
||||
} else if request.Flow != userFlow {
|
||||
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
|
||||
}
|
||||
|
||||
if request.Command == vmess.CommandUDP {
|
||||
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
|
||||
}
|
||||
responseConn := &serverConn{ExtendedConn: bufio.NewExtendedConn(conn), writer: bufio.NewVectorisedWriter(conn)}
|
||||
switch userFlow {
|
||||
case FlowVision:
|
||||
conn, err = NewVisionConn(responseConn, conn, request.UUID, s.logger)
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize vision")
|
||||
}
|
||||
case "":
|
||||
conn = responseConn
|
||||
default:
|
||||
return E.New("unknown flow: ", userFlow)
|
||||
}
|
||||
switch request.Command {
|
||||
case vmess.CommandTCP:
|
||||
return s.handler.NewConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, metadata)
|
||||
case vmess.CommandUDP:
|
||||
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
|
||||
return s.handler.NewConnection(ctx, conn, metadata)
|
||||
case vmess.CommandMux:
|
||||
return vmess.HandleMuxConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, s.handler)
|
||||
return vmess.HandleMuxConnection(ctx, conn, s.handler)
|
||||
default:
|
||||
return E.New("unknown command: ", request.Command)
|
||||
}
|
||||
|
@ -104,42 +106,70 @@ func flowName(value string) string {
|
|||
return value
|
||||
}
|
||||
|
||||
var _ N.VectorisedWriter = (*serverConn)(nil)
|
||||
|
||||
type serverConn struct {
|
||||
net.Conn
|
||||
responseWriter io.Writer
|
||||
N.ExtendedConn
|
||||
writer N.VectorisedWriter
|
||||
responseWritten bool
|
||||
}
|
||||
|
||||
func (c *serverConn) Read(b []byte) (n int, err error) {
|
||||
return c.Conn.Read(b)
|
||||
return c.ExtendedConn.Read(b)
|
||||
}
|
||||
|
||||
func (c *serverConn) Write(b []byte) (n int, err error) {
|
||||
if !c.responseWritten {
|
||||
if c.responseWriter == nil {
|
||||
_, err = bufio.WriteVectorised(bufio.NewVectorisedWriter(c.Conn), [][]byte{{Version, 0}, b})
|
||||
if err == nil {
|
||||
n = len(b)
|
||||
}
|
||||
c.responseWritten = true
|
||||
return
|
||||
} else {
|
||||
_, err = c.responseWriter.Write([]byte{Version, 0})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.responseWritten = true
|
||||
_, err = bufio.WriteVectorised(c.writer, [][]byte{{Version, 0}, b})
|
||||
if err == nil {
|
||||
n = len(b)
|
||||
}
|
||||
c.responseWritten = true
|
||||
return
|
||||
}
|
||||
return c.Conn.Write(b)
|
||||
return c.ExtendedConn.Write(b)
|
||||
}
|
||||
|
||||
func (c *serverConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
if !c.responseWritten {
|
||||
header := buffer.ExtendHeader(2)
|
||||
header[0] = Version
|
||||
header[1] = 0
|
||||
c.responseWritten = true
|
||||
}
|
||||
return c.ExtendedConn.WriteBuffer(buffer)
|
||||
}
|
||||
|
||||
func (c *serverConn) WriteVectorised(buffers []*buf.Buffer) error {
|
||||
if !c.responseWritten {
|
||||
err := c.writer.WriteVectorised(append([]*buf.Buffer{buf.As([]byte{Version, 0})}, buffers...))
|
||||
c.responseWritten = true
|
||||
return err
|
||||
}
|
||||
return c.writer.WriteVectorised(buffers)
|
||||
}
|
||||
|
||||
func (c *serverConn) NeedAdditionalReadDeadline() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *serverConn) FrontHeadroom() int {
|
||||
if c.responseWritten {
|
||||
return 0
|
||||
}
|
||||
return 2
|
||||
}
|
||||
|
||||
func (c *serverConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *serverConn) WriterReplaceable() bool {
|
||||
return c.responseWritten
|
||||
}
|
||||
|
||||
func (c *serverConn) Upstream() any {
|
||||
return c.Conn
|
||||
return c.ExtendedConn
|
||||
}
|
||||
|
||||
type serverPacketConn struct {
|
||||
|
|
|
@ -56,12 +56,12 @@ type VisionConn struct {
|
|||
withinPaddingBuffers bool
|
||||
remainingContent int
|
||||
remainingPadding int
|
||||
currentCommand int
|
||||
currentCommand byte
|
||||
directRead bool
|
||||
remainingReader io.Reader
|
||||
}
|
||||
|
||||
func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
|
||||
func NewVisionConn(conn net.Conn, tlsConn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
|
||||
var (
|
||||
loaded bool
|
||||
reflectType reflect.Type
|
||||
|
@ -69,7 +69,7 @@ func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*Vis
|
|||
netConn net.Conn
|
||||
)
|
||||
for _, tlsCreator := range tlsRegistry {
|
||||
loaded, netConn, reflectType, reflectPointer = tlsCreator(conn)
|
||||
loaded, netConn, reflectType, reflectPointer = tlsCreator(tlsConn)
|
||||
if loaded {
|
||||
break
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
|
|||
if c.remainingReader != nil {
|
||||
n, err = c.remainingReader.Read(p)
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
c.remainingReader = nil
|
||||
}
|
||||
if n > 0 {
|
||||
|
@ -113,6 +114,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
|
|||
return c.netConn.Read(p)
|
||||
}
|
||||
var bufferBytes []byte
|
||||
var chunkBuffer *buf.Buffer
|
||||
if len(p) > xrayChunkSize {
|
||||
n, err = c.Conn.Read(p)
|
||||
if err != nil {
|
||||
|
@ -120,21 +122,26 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
|
|||
}
|
||||
bufferBytes = p[:n]
|
||||
} else {
|
||||
buffer, err := c.reader.ReadChunk()
|
||||
chunkBuffer, err = c.reader.ReadChunk()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer buffer.FullReset()
|
||||
bufferBytes = buffer.Bytes()
|
||||
bufferBytes = chunkBuffer.Bytes()
|
||||
}
|
||||
if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 {
|
||||
buffers := c.unPadding(bufferBytes)
|
||||
if chunkBuffer != nil {
|
||||
buffers = common.Map(buffers, func(it *buf.Buffer) *buf.Buffer {
|
||||
return it.ToOwned()
|
||||
})
|
||||
chunkBuffer.FullReset()
|
||||
}
|
||||
if c.remainingContent == 0 && c.remainingPadding == 0 {
|
||||
if c.currentCommand == 1 {
|
||||
if c.currentCommand == commandPaddingEnd {
|
||||
c.withinPaddingBuffers = false
|
||||
c.remainingContent = -1
|
||||
c.remainingPadding = -1
|
||||
} else if c.currentCommand == 2 {
|
||||
} else if c.currentCommand == commandPaddingDirect {
|
||||
c.withinPaddingBuffers = false
|
||||
c.directRead = true
|
||||
|
||||
|
@ -142,17 +149,17 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buffers = append(buffers, inputBuffer)
|
||||
buffers = append(buffers, buf.As(inputBuffer))
|
||||
|
||||
rawInputBuffer, err := io.ReadAll(c.rawInput)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
buffers = append(buffers, rawInputBuffer)
|
||||
buffers = append(buffers, buf.As(rawInputBuffer))
|
||||
|
||||
c.logger.Trace("XtlsRead readV")
|
||||
} else if c.currentCommand == 0 {
|
||||
} else if c.currentCommand == commandPaddingContinue {
|
||||
c.withinPaddingBuffers = true
|
||||
} else {
|
||||
return 0, E.New("unknown command ", c.currentCommand)
|
||||
|
@ -163,14 +170,18 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
|
|||
c.withinPaddingBuffers = false
|
||||
}
|
||||
if c.numberOfPacketToFilter > 0 {
|
||||
c.filterTLS(buffers)
|
||||
c.filterTLS(buf.ToSliceMulti(buffers))
|
||||
}
|
||||
c.remainingReader = io.MultiReader(common.Map(buffers, func(it []byte) io.Reader { return bytes.NewReader(it) })...)
|
||||
c.remainingReader = io.MultiReader(common.Map(buffers, func(it *buf.Buffer) io.Reader { return it })...)
|
||||
return c.Read(p)
|
||||
} else {
|
||||
if c.numberOfPacketToFilter > 0 {
|
||||
c.filterTLS([][]byte{bufferBytes})
|
||||
}
|
||||
if chunkBuffer != nil {
|
||||
n = copy(p, bufferBytes)
|
||||
chunkBuffer.Advance(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -310,7 +321,7 @@ func (c *VisionConn) padding(buffer *buf.Buffer, command byte) *buf.Buffer {
|
|||
return newBuffer
|
||||
}
|
||||
|
||||
func (c *VisionConn) unPadding(buffer []byte) [][]byte {
|
||||
func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
|
||||
var bufferIndex int
|
||||
if c.remainingContent == -1 && c.remainingPadding == -1 {
|
||||
if len(buffer) >= 21 && bytes.Equal(c.userUUID[:], buffer[:16]) {
|
||||
|
@ -321,17 +332,17 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
|
|||
}
|
||||
}
|
||||
if c.remainingContent == -1 && c.remainingPadding == -1 {
|
||||
return [][]byte{buffer}
|
||||
return []*buf.Buffer{buf.As(buffer)}
|
||||
}
|
||||
var buffers [][]byte
|
||||
var buffers []*buf.Buffer
|
||||
for bufferIndex < len(buffer) {
|
||||
if c.remainingContent <= 0 && c.remainingPadding <= 0 {
|
||||
if c.currentCommand == 1 {
|
||||
buffers = append(buffers, buffer[bufferIndex:])
|
||||
buffers = append(buffers, buf.As(buffer[bufferIndex:]))
|
||||
break
|
||||
} else {
|
||||
paddingInfo := buffer[bufferIndex : bufferIndex+5]
|
||||
c.currentCommand = int(paddingInfo[0])
|
||||
c.currentCommand = paddingInfo[0]
|
||||
c.remainingContent = int(paddingInfo[1])<<8 | int(paddingInfo[2])
|
||||
c.remainingPadding = int(paddingInfo[3])<<8 | int(paddingInfo[4])
|
||||
bufferIndex += 5
|
||||
|
@ -342,7 +353,7 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
|
|||
if end > len(buffer)-bufferIndex {
|
||||
end = len(buffer) - bufferIndex
|
||||
}
|
||||
buffers = append(buffers, buffer[bufferIndex:bufferIndex+end])
|
||||
buffers = append(buffers, buf.As(buffer[bufferIndex:bufferIndex+end]))
|
||||
c.remainingContent -= end
|
||||
bufferIndex += end
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue