| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- 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 += 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)
- }
- 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(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))
- }
- common.Must1(buffer.Write(payload))
- return common.Error(writer.Write(buffer.Bytes()))
- }
- 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 += UvarintLen(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(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
- common.Must(common.Error(buffer.Write([]byte(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
- }
- func UvarintLen(value uint64) int {
- var buffer [binary.MaxVarintLen64]byte
- return binary.PutUvarint(buffer[:], value)
- }
|