github.com/sagernet/sing-box@v1.9.0-rc.20/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.Flow != "" {
   132  		addonsLen += 1 // protobuf header
   133  		addonsLen += rw.UVariantLen(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.NewSize(requestLen)
   143  	defer buffer.Release()
   144  	common.Must(
   145  		buffer.WriteByte(Version),
   146  		common.Error(buffer.Write(request.UUID[:])),
   147  		buffer.WriteByte(byte(addonsLen)),
   148  	)
   149  	if addonsLen > 0 {
   150  		common.Must(buffer.WriteByte(10))
   151  		binary.PutUvarint(buffer.Extend(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
   152  		common.Must(common.Error(buffer.WriteString(request.Flow)))
   153  	}
   154  	common.Must(
   155  		buffer.WriteByte(request.Command),
   156  	)
   157  
   158  	if request.Command != vmess.CommandMux {
   159  		err := vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination)
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	common.Must1(buffer.Write(payload))
   166  	return common.Error(writer.Write(buffer.Bytes()))
   167  }
   168  
   169  func EncodeRequest(request Request, buffer *buf.Buffer) error {
   170  	var requestLen int
   171  	requestLen += 1  // version
   172  	requestLen += 16 // uuid
   173  	requestLen += 1  // protobuf length
   174  
   175  	var addonsLen int
   176  	if request.Flow != "" {
   177  		addonsLen += 1 // protobuf header
   178  		addonsLen += rw.UVariantLen(uint64(len(request.Flow)))
   179  		addonsLen += len(request.Flow)
   180  		requestLen += addonsLen
   181  	}
   182  	requestLen += 1 // command
   183  	if request.Command != vmess.CommandMux {
   184  		requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
   185  	}
   186  	common.Must(
   187  		buffer.WriteByte(Version),
   188  		common.Error(buffer.Write(request.UUID[:])),
   189  		buffer.WriteByte(byte(addonsLen)),
   190  	)
   191  	if addonsLen > 0 {
   192  		common.Must(buffer.WriteByte(10))
   193  		binary.PutUvarint(buffer.Extend(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
   194  		common.Must(common.Error(buffer.WriteString(request.Flow)))
   195  	}
   196  	common.Must(
   197  		buffer.WriteByte(request.Command),
   198  	)
   199  
   200  	if request.Command != vmess.CommandMux {
   201  		err := vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination)
   202  		if err != nil {
   203  			return err
   204  		}
   205  	}
   206  	return nil
   207  }
   208  
   209  func RequestLen(request Request) int {
   210  	var requestLen int
   211  	requestLen += 1  // version
   212  	requestLen += 16 // uuid
   213  	requestLen += 1  // protobuf length
   214  
   215  	var addonsLen int
   216  	if request.Flow != "" {
   217  		addonsLen += 1 // protobuf header
   218  		addonsLen += rw.UVariantLen(uint64(len(request.Flow)))
   219  		addonsLen += len(request.Flow)
   220  		requestLen += addonsLen
   221  	}
   222  	requestLen += 1 // command
   223  	if request.Command != vmess.CommandMux {
   224  		requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
   225  	}
   226  	return requestLen
   227  }
   228  
   229  func WritePacketRequest(writer io.Writer, request Request, payload []byte) error {
   230  	var requestLen int
   231  	requestLen += 1  // version
   232  	requestLen += 16 // uuid
   233  	requestLen += 1  // protobuf length
   234  	var addonsLen int
   235  	/*if request.Flow != "" {
   236  		addonsLen += 1 // protobuf header
   237  		addonsLen += rw.UVariantLen(uint64(len(request.Flow)))
   238  		addonsLen += len(request.Flow)
   239  		requestLen += addonsLen
   240  	}*/
   241  	requestLen += 1 // command
   242  	requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
   243  	if len(payload) > 0 {
   244  		requestLen += 2
   245  		requestLen += len(payload)
   246  	}
   247  	buffer := buf.NewSize(requestLen)
   248  	defer buffer.Release()
   249  	common.Must(
   250  		buffer.WriteByte(Version),
   251  		common.Error(buffer.Write(request.UUID[:])),
   252  		buffer.WriteByte(byte(addonsLen)),
   253  	)
   254  
   255  	if addonsLen > 0 {
   256  		common.Must(buffer.WriteByte(10))
   257  		binary.PutUvarint(buffer.Extend(rw.UVariantLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
   258  		common.Must(common.Error(buffer.WriteString(request.Flow)))
   259  	}
   260  
   261  	common.Must(buffer.WriteByte(vmess.CommandUDP))
   262  
   263  	err := vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination)
   264  	if err != nil {
   265  		return err
   266  	}
   267  
   268  	if len(payload) > 0 {
   269  		common.Must(
   270  			binary.Write(buffer, binary.BigEndian, uint16(len(payload))),
   271  			common.Error(buffer.Write(payload)),
   272  		)
   273  	}
   274  
   275  	return common.Error(writer.Write(buffer.Bytes()))
   276  }
   277  
   278  func ReadResponse(reader io.Reader) error {
   279  	version, err := rw.ReadByte(reader)
   280  	if err != nil {
   281  		return err
   282  	}
   283  	if version != Version {
   284  		return E.New("unknown version: ", version)
   285  	}
   286  	protobufLength, err := rw.ReadByte(reader)
   287  	if err != nil {
   288  		return err
   289  	}
   290  	if protobufLength > 0 {
   291  		err = rw.SkipN(reader, int(protobufLength))
   292  		if err != nil {
   293  			return err
   294  		}
   295  	}
   296  	return nil
   297  }