github.com/sagernet/sing-box@v1.2.7/transport/vless/protocol.go (about)

     1  package vless
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  
     8  	"github.com/sagernet/sing-vmess"
     9  	"github.com/sagernet/sing/common"
    10  	"github.com/sagernet/sing/common/buf"
    11  	E "github.com/sagernet/sing/common/exceptions"
    12  	M "github.com/sagernet/sing/common/metadata"
    13  	"github.com/sagernet/sing/common/rw"
    14  )
    15  
    16  const (
    17  	Version    = 0
    18  	FlowVision = "xtls-rprx-vision"
    19  )
    20  
    21  type Request struct {
    22  	UUID        [16]byte
    23  	Command     byte
    24  	Destination M.Socksaddr
    25  	Flow        string
    26  }
    27  
    28  func ReadRequest(reader io.Reader) (*Request, error) {
    29  	var request Request
    30  
    31  	var version uint8
    32  	err := binary.Read(reader, binary.BigEndian, &version)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	if version != Version {
    37  		return nil, E.New("unknown version: ", version)
    38  	}
    39  
    40  	_, err = io.ReadFull(reader, request.UUID[:])
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	var addonsLen uint8
    46  	err = binary.Read(reader, binary.BigEndian, &addonsLen)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	if addonsLen > 0 {
    52  		addonsBytes, err := rw.ReadBytes(reader, int(addonsLen))
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  
    57  		addons, err := readAddons(bytes.NewReader(addonsBytes))
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		request.Flow = addons.Flow
    62  	}
    63  
    64  	err = binary.Read(reader, binary.BigEndian, &request.Command)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	if request.Command != vmess.CommandMux {
    70  		request.Destination, err = vmess.AddressSerializer.ReadAddrPort(reader)
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  	}
    75  
    76  	return &request, nil
    77  }
    78  
    79  type Addons struct {
    80  	Flow string
    81  	Seed string
    82  }
    83  
    84  func readAddons(reader io.Reader) (*Addons, error) {
    85  	protoHeader, err := rw.ReadByte(reader)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	if protoHeader != 10 {
    90  		return nil, E.New("unknown protobuf message header: ", protoHeader)
    91  	}
    92  
    93  	var addons Addons
    94  
    95  	flowLen, err := rw.ReadUVariant(reader)
    96  	if err != nil {
    97  		if err == io.EOF {
    98  			return &addons, nil
    99  		}
   100  		return nil, err
   101  	}
   102  	flowBytes, err := rw.ReadBytes(reader, int(flowLen))
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	addons.Flow = string(flowBytes)
   107  
   108  	seedLen, err := rw.ReadUVariant(reader)
   109  	if err != nil {
   110  		if err == io.EOF {
   111  			return &addons, nil
   112  		}
   113  		return nil, err
   114  	}
   115  	seedBytes, err := rw.ReadBytes(reader, int(seedLen))
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	addons.Seed = string(seedBytes)
   120  
   121  	return &addons, nil
   122  }
   123  
   124  func WriteRequest(writer io.Writer, request Request, payload []byte) error {
   125  	var requestLen int
   126  	requestLen += 1  // version
   127  	requestLen += 16 // uuid
   128  	requestLen += 1  // protobuf length
   129  
   130  	var addonsLen int
   131  	if request.Command == vmess.CommandTCP && request.Flow != "" {
   132  		addonsLen += 1 // protobuf header
   133  		addonsLen += UvarintLen(uint64(len(request.Flow)))
   134  		addonsLen += len(request.Flow)
   135  		requestLen += addonsLen
   136  	}
   137  	requestLen += 1 // command
   138  	if request.Command != vmess.CommandMux {
   139  		requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
   140  	}
   141  	requestLen += len(payload)
   142  	_buffer := buf.StackNewSize(requestLen)
   143  	defer common.KeepAlive(_buffer)
   144  	buffer := common.Dup(_buffer)
   145  	defer buffer.Release()
   146  	common.Must(
   147  		buffer.WriteByte(Version),
   148  		common.Error(buffer.Write(request.UUID[:])),
   149  		buffer.WriteByte(byte(addonsLen)),
   150  	)
   151  	if addonsLen > 0 {
   152  		common.Must(buffer.WriteByte(10))
   153  		binary.PutUvarint(buffer.Extend(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
   154  		common.Must(common.Error(buffer.Write([]byte(request.Flow))))
   155  	}
   156  	common.Must(
   157  		buffer.WriteByte(request.Command),
   158  	)
   159  
   160  	if request.Command != vmess.CommandMux {
   161  		common.Must(vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination))
   162  	}
   163  
   164  	common.Must1(buffer.Write(payload))
   165  	return common.Error(writer.Write(buffer.Bytes()))
   166  }
   167  
   168  func WritePacketRequest(writer io.Writer, request Request, payload []byte) error {
   169  	var requestLen int
   170  	requestLen += 1  // version
   171  	requestLen += 16 // uuid
   172  	requestLen += 1  // protobuf length
   173  	var addonsLen int
   174  	/*if request.Flow != "" {
   175  		addonsLen += 1 // protobuf header
   176  		addonsLen += UvarintLen(uint64(len(request.Flow)))
   177  		addonsLen += len(request.Flow)
   178  		requestLen += addonsLen
   179  	}*/
   180  	requestLen += 1 // command
   181  	requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
   182  	if len(payload) > 0 {
   183  		requestLen += 2
   184  		requestLen += len(payload)
   185  	}
   186  	_buffer := buf.StackNewSize(requestLen)
   187  	defer common.KeepAlive(_buffer)
   188  	buffer := common.Dup(_buffer)
   189  	defer buffer.Release()
   190  	common.Must(
   191  		buffer.WriteByte(Version),
   192  		common.Error(buffer.Write(request.UUID[:])),
   193  		buffer.WriteByte(byte(addonsLen)),
   194  	)
   195  
   196  	if addonsLen > 0 {
   197  		common.Must(buffer.WriteByte(10))
   198  		binary.PutUvarint(buffer.Extend(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
   199  		common.Must(common.Error(buffer.Write([]byte(request.Flow))))
   200  	}
   201  
   202  	common.Must(
   203  		buffer.WriteByte(vmess.CommandUDP),
   204  		vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination),
   205  	)
   206  
   207  	if len(payload) > 0 {
   208  		common.Must(
   209  			binary.Write(buffer, binary.BigEndian, uint16(len(payload))),
   210  			common.Error(buffer.Write(payload)),
   211  		)
   212  	}
   213  
   214  	return common.Error(writer.Write(buffer.Bytes()))
   215  }
   216  
   217  func ReadResponse(reader io.Reader) error {
   218  	version, err := rw.ReadByte(reader)
   219  	if err != nil {
   220  		return err
   221  	}
   222  	if version != Version {
   223  		return E.New("unknown version: ", version)
   224  	}
   225  	protobufLength, err := rw.ReadByte(reader)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	if protobufLength > 0 {
   230  		err = rw.SkipN(reader, int(protobufLength))
   231  		if err != nil {
   232  			return err
   233  		}
   234  	}
   235  	return nil
   236  }
   237  
   238  func UvarintLen(value uint64) int {
   239  	var buffer [binary.MaxVarintLen64]byte
   240  	return binary.PutUvarint(buffer[:], value)
   241  }