mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 18:11:28 +00:00
293 lines
6.8 KiB
Go
293 lines
6.8 KiB
Go
package vless
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"io"
|
|
|
|
"github.com/sagernet/sing-vmess"
|
|
"github.com/sagernet/sing/common"
|
|
"github.com/sagernet/sing/common/buf"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
"github.com/sagernet/sing/common/rw"
|
|
)
|
|
|
|
const (
|
|
Version = 0
|
|
FlowVision = "xtls-rprx-vision"
|
|
)
|
|
|
|
type Request struct {
|
|
UUID [16]byte
|
|
Command byte
|
|
Destination M.Socksaddr
|
|
Flow string
|
|
}
|
|
|
|
func ReadRequest(reader io.Reader) (*Request, error) {
|
|
var request Request
|
|
|
|
var version uint8
|
|
err := binary.Read(reader, binary.BigEndian, &version)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if version != Version {
|
|
return nil, E.New("unknown version: ", version)
|
|
}
|
|
|
|
_, err = io.ReadFull(reader, request.UUID[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var addonsLen uint8
|
|
err = binary.Read(reader, binary.BigEndian, &addonsLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if addonsLen > 0 {
|
|
addonsBytes, err := rw.ReadBytes(reader, int(addonsLen))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
addons, err := readAddons(bytes.NewReader(addonsBytes))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
request.Flow = addons.Flow
|
|
}
|
|
|
|
err = binary.Read(reader, binary.BigEndian, &request.Command)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if request.Command != vmess.CommandMux {
|
|
request.Destination, err = vmess.AddressSerializer.ReadAddrPort(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &request, nil
|
|
}
|
|
|
|
type Addons struct {
|
|
Flow string
|
|
Seed string
|
|
}
|
|
|
|
func readAddons(reader io.Reader) (*Addons, error) {
|
|
protoHeader, err := rw.ReadByte(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if protoHeader != 10 {
|
|
return nil, E.New("unknown protobuf message header: ", protoHeader)
|
|
}
|
|
|
|
var addons Addons
|
|
|
|
flowLen, err := rw.ReadUVariant(reader)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return &addons, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
flowBytes, err := rw.ReadBytes(reader, int(flowLen))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addons.Flow = string(flowBytes)
|
|
|
|
seedLen, err := rw.ReadUVariant(reader)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return &addons, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
seedBytes, err := rw.ReadBytes(reader, int(seedLen))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addons.Seed = string(seedBytes)
|
|
|
|
return &addons, nil
|
|
}
|
|
|
|
func WriteRequest(writer io.Writer, request Request, payload []byte) error {
|
|
var requestLen int
|
|
requestLen += 1 // version
|
|
requestLen += 16 // uuid
|
|
requestLen += 1 // protobuf length
|
|
|
|
var addonsLen int
|
|
if request.Flow != "" {
|
|
addonsLen += 1 // protobuf header
|
|
addonsLen += rw.UVariantLen(uint64(len(request.Flow)))
|
|
addonsLen += len(request.Flow)
|
|
requestLen += addonsLen
|
|
}
|
|
requestLen += 1 // command
|
|
if request.Command != vmess.CommandMux {
|
|
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
|
|
}
|
|
requestLen += len(payload)
|
|
_buffer := buf.StackNewSize(requestLen)
|
|
defer common.KeepAlive(_buffer)
|
|
buffer := common.Dup(_buffer)
|
|
defer buffer.Release()
|
|
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(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
|
|
common.Must(common.Error(buffer.WriteString(request.Flow)))
|
|
}
|
|
common.Must(
|
|
buffer.WriteByte(request.Command),
|
|
)
|
|
|
|
if request.Command != vmess.CommandMux {
|
|
common.Must(vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination))
|
|
}
|
|
|
|
common.Must1(buffer.Write(payload))
|
|
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 += rw.UVariantLen(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(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
|
|
common.Must(common.Error(buffer.WriteString(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 += rw.UVariantLen(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
|
|
requestLen += 16 // uuid
|
|
requestLen += 1 // protobuf length
|
|
var addonsLen int
|
|
/*if request.Flow != "" {
|
|
addonsLen += 1 // protobuf header
|
|
addonsLen += rw.UVariantLen(uint64(len(request.Flow)))
|
|
addonsLen += len(request.Flow)
|
|
requestLen += addonsLen
|
|
}*/
|
|
requestLen += 1 // command
|
|
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
|
|
if len(payload) > 0 {
|
|
requestLen += 2
|
|
requestLen += len(payload)
|
|
}
|
|
_buffer := buf.StackNewSize(requestLen)
|
|
defer common.KeepAlive(_buffer)
|
|
buffer := common.Dup(_buffer)
|
|
defer buffer.Release()
|
|
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(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
|
|
common.Must(common.Error(buffer.WriteString(request.Flow)))
|
|
}
|
|
|
|
common.Must(
|
|
buffer.WriteByte(vmess.CommandUDP),
|
|
vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination),
|
|
)
|
|
|
|
if len(payload) > 0 {
|
|
common.Must(
|
|
binary.Write(buffer, binary.BigEndian, uint16(len(payload))),
|
|
common.Error(buffer.Write(payload)),
|
|
)
|
|
}
|
|
|
|
return common.Error(writer.Write(buffer.Bytes()))
|
|
}
|
|
|
|
func ReadResponse(reader io.Reader) error {
|
|
version, err := rw.ReadByte(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if version != Version {
|
|
return E.New("unknown version: ", version)
|
|
}
|
|
protobufLength, err := rw.ReadByte(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if protobufLength > 0 {
|
|
err = rw.SkipN(reader, int(protobufLength))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|