github.com/xraypb/xray-core@v1.6.6/common/mux/frame.go (about)

     1  package mux
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  
     7  	"github.com/xraypb/xray-core/common"
     8  	"github.com/xraypb/xray-core/common/bitmask"
     9  	"github.com/xraypb/xray-core/common/buf"
    10  	"github.com/xraypb/xray-core/common/net"
    11  	"github.com/xraypb/xray-core/common/protocol"
    12  	"github.com/xraypb/xray-core/common/serial"
    13  )
    14  
    15  type SessionStatus byte
    16  
    17  const (
    18  	SessionStatusNew       SessionStatus = 0x01
    19  	SessionStatusKeep      SessionStatus = 0x02
    20  	SessionStatusEnd       SessionStatus = 0x03
    21  	SessionStatusKeepAlive SessionStatus = 0x04
    22  )
    23  
    24  const (
    25  	OptionData  bitmask.Byte = 0x01
    26  	OptionError bitmask.Byte = 0x02
    27  )
    28  
    29  type TargetNetwork byte
    30  
    31  const (
    32  	TargetNetworkTCP TargetNetwork = 0x01
    33  	TargetNetworkUDP TargetNetwork = 0x02
    34  )
    35  
    36  var addrParser = protocol.NewAddressParser(
    37  	protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
    38  	protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
    39  	protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
    40  	protocol.PortThenAddress(),
    41  )
    42  
    43  /*
    44  Frame format
    45  2 bytes - length
    46  2 bytes - session id
    47  1 bytes - status
    48  1 bytes - option
    49  
    50  1 byte - network
    51  2 bytes - port
    52  n bytes - address
    53  
    54  */
    55  
    56  type FrameMetadata struct {
    57  	Target        net.Destination
    58  	SessionID     uint16
    59  	Option        bitmask.Byte
    60  	SessionStatus SessionStatus
    61  }
    62  
    63  func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
    64  	lenBytes := b.Extend(2)
    65  
    66  	len0 := b.Len()
    67  	sessionBytes := b.Extend(2)
    68  	binary.BigEndian.PutUint16(sessionBytes, f.SessionID)
    69  
    70  	common.Must(b.WriteByte(byte(f.SessionStatus)))
    71  	common.Must(b.WriteByte(byte(f.Option)))
    72  
    73  	if f.SessionStatus == SessionStatusNew {
    74  		switch f.Target.Network {
    75  		case net.Network_TCP:
    76  			common.Must(b.WriteByte(byte(TargetNetworkTCP)))
    77  		case net.Network_UDP:
    78  			common.Must(b.WriteByte(byte(TargetNetworkUDP)))
    79  		}
    80  
    81  		if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
    82  			return err
    83  		}
    84  	} else if b.UDP != nil {
    85  		b.WriteByte(byte(TargetNetworkUDP))
    86  		addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port)
    87  	}
    88  
    89  	len1 := b.Len()
    90  	binary.BigEndian.PutUint16(lenBytes, uint16(len1-len0))
    91  	return nil
    92  }
    93  
    94  // Unmarshal reads FrameMetadata from the given reader.
    95  func (f *FrameMetadata) Unmarshal(reader io.Reader) error {
    96  	metaLen, err := serial.ReadUint16(reader)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	if metaLen > 512 {
   101  		return newError("invalid metalen ", metaLen).AtError()
   102  	}
   103  
   104  	b := buf.New()
   105  	defer b.Release()
   106  
   107  	if _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {
   108  		return err
   109  	}
   110  	return f.UnmarshalFromBuffer(b)
   111  }
   112  
   113  // UnmarshalFromBuffer reads a FrameMetadata from the given buffer.
   114  // Visible for testing only.
   115  func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
   116  	if b.Len() < 4 {
   117  		return newError("insufficient buffer: ", b.Len())
   118  	}
   119  
   120  	f.SessionID = binary.BigEndian.Uint16(b.BytesTo(2))
   121  	f.SessionStatus = SessionStatus(b.Byte(2))
   122  	f.Option = bitmask.Byte(b.Byte(3))
   123  	f.Target.Network = net.Network_Unknown
   124  
   125  	if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() != 4) {
   126  		if b.Len() < 8 {
   127  			return newError("insufficient buffer: ", b.Len())
   128  		}
   129  		network := TargetNetwork(b.Byte(4))
   130  		b.Advance(5)
   131  
   132  		addr, port, err := addrParser.ReadAddressPort(nil, b)
   133  		if err != nil {
   134  			return newError("failed to parse address and port").Base(err)
   135  		}
   136  
   137  		switch network {
   138  		case TargetNetworkTCP:
   139  			f.Target = net.TCPDestination(addr, port)
   140  		case TargetNetworkUDP:
   141  			f.Target = net.UDPDestination(addr, port)
   142  		default:
   143  			return newError("unknown network type: ", network)
   144  		}
   145  	}
   146  
   147  	return nil
   148  }