protocol.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. package tuic
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net"
  8. "strconv"
  9. )
  10. const (
  11. // ProtocolVersion is the TUIC protocol version (0x05).
  12. ProtocolVersion byte = 0x05
  13. // Command types
  14. CmdAuthenticate byte = 0x00
  15. CmdConnect byte = 0x01
  16. CmdPacket byte = 0x02
  17. CmdDissociate byte = 0x03
  18. CmdHeartbeat byte = 0x04
  19. // Address types
  20. AddrTypeDomain byte = 0x00
  21. AddrTypeIPv4 byte = 0x01
  22. AddrTypeIPv6 byte = 0x02
  23. AddrTypeNone byte = 0xff
  24. )
  25. var (
  26. ErrInvalidVersion = errors.New("tuic: invalid protocol version")
  27. ErrInvalidCmd = errors.New("tuic: invalid command type")
  28. ErrInvalidAddr = errors.New("tuic: invalid address format")
  29. )
  30. // Address represents a network endpoint (host + port) in TUIC v5.
  31. type Address struct {
  32. Type byte
  33. Host string
  34. IP net.IP
  35. Port uint16
  36. }
  37. // String returns "host:port" suitable for net.Dial.
  38. func (a *Address) String() string {
  39. if a == nil || a.Type == AddrTypeNone {
  40. return ""
  41. }
  42. if len(a.IP) > 0 {
  43. return net.JoinHostPort(a.IP.String(), strconv.Itoa(int(a.Port)))
  44. }
  45. return net.JoinHostPort(a.Host, strconv.Itoa(int(a.Port)))
  46. }
  47. // ReadAddress decodes a TUIC v5 address from the reader.
  48. func ReadAddress(r io.Reader) (*Address, error) {
  49. var typeBuf [1]byte
  50. if _, err := io.ReadFull(r, typeBuf[:]); err != nil {
  51. return nil, err
  52. }
  53. addrType := typeBuf[0]
  54. if addrType == AddrTypeNone {
  55. return &Address{Type: AddrTypeNone}, nil
  56. }
  57. addr := &Address{Type: addrType}
  58. switch addrType {
  59. case AddrTypeIPv4:
  60. var ip [4]byte
  61. if _, err := io.ReadFull(r, ip[:]); err != nil {
  62. return nil, err
  63. }
  64. addr.IP = net.IP(ip[:])
  65. addr.Host = addr.IP.String()
  66. case AddrTypeIPv6:
  67. var ip [16]byte
  68. if _, err := io.ReadFull(r, ip[:]); err != nil {
  69. return nil, err
  70. }
  71. addr.IP = net.IP(ip[:])
  72. addr.Host = addr.IP.String()
  73. case AddrTypeDomain:
  74. var lenBuf [1]byte
  75. if _, err := io.ReadFull(r, lenBuf[:]); err != nil {
  76. return nil, err
  77. }
  78. dLen := int(lenBuf[0])
  79. if dLen == 0 {
  80. return nil, ErrInvalidAddr
  81. }
  82. domainBuf := make([]byte, dLen)
  83. if _, err := io.ReadFull(r, domainBuf); err != nil {
  84. return nil, err
  85. }
  86. addr.Host = string(domainBuf)
  87. default:
  88. return nil, fmt.Errorf("%w: unknown type 0x%02x", ErrInvalidAddr, addrType)
  89. }
  90. var portBuf [2]byte
  91. if _, err := io.ReadFull(r, portBuf[:]); err != nil {
  92. return nil, err
  93. }
  94. addr.Port = binary.BigEndian.Uint16(portBuf[:])
  95. return addr, nil
  96. }
  97. // WriteAddress encodes a TUIC v5 address to the writer.
  98. func WriteAddress(w io.Writer, addr *Address) error {
  99. if addr == nil || addr.Type == AddrTypeNone {
  100. _, err := w.Write([]byte{AddrTypeNone})
  101. return err
  102. }
  103. var buf []byte
  104. switch addr.Type {
  105. case AddrTypeIPv4:
  106. ip4 := addr.IP.To4()
  107. if len(ip4) != 4 {
  108. return ErrInvalidAddr
  109. }
  110. buf = make([]byte, 1+4+2)
  111. buf[0] = AddrTypeIPv4
  112. copy(buf[1:5], ip4)
  113. binary.BigEndian.PutUint16(buf[5:7], addr.Port)
  114. case AddrTypeIPv6:
  115. ip16 := addr.IP.To16()
  116. if len(ip16) != 16 {
  117. return ErrInvalidAddr
  118. }
  119. buf = make([]byte, 1+16+2)
  120. buf[0] = AddrTypeIPv6
  121. copy(buf[1:17], ip16)
  122. binary.BigEndian.PutUint16(buf[17:19], addr.Port)
  123. case AddrTypeDomain:
  124. dLen := len(addr.Host)
  125. if dLen == 0 || dLen > 255 {
  126. return ErrInvalidAddr
  127. }
  128. buf = make([]byte, 1+1+dLen+2)
  129. buf[0] = AddrTypeDomain
  130. buf[1] = byte(dLen)
  131. copy(buf[2:2+dLen], []byte(addr.Host))
  132. binary.BigEndian.PutUint16(buf[2+dLen:4+dLen], addr.Port)
  133. default:
  134. return ErrInvalidAddr
  135. }
  136. _, err := w.Write(buf)
  137. return err
  138. }
  139. // ReadCommand reads the 2-byte TUIC command header: [VER (1)][TYPE (1)].
  140. func ReadCommand(r io.Reader) (byte, byte, error) {
  141. var hdr [2]byte
  142. if _, err := io.ReadFull(r, hdr[:]); err != nil {
  143. return 0, 0, err
  144. }
  145. if hdr[0] != ProtocolVersion {
  146. return hdr[0], hdr[1], fmt.Errorf("%w: got 0x%02x, want 0x%02x", ErrInvalidVersion, hdr[0], ProtocolVersion)
  147. }
  148. return hdr[0], hdr[1], nil
  149. }
  150. // PacketHeader represents the header of a UDP Packet command (0x02).
  151. type PacketHeader struct {
  152. AssocID uint16
  153. PktID uint16
  154. FragTotal uint8
  155. FragID uint8
  156. Size uint16
  157. Addr *Address
  158. }
  159. // ReadPacketHeader reads the packet command fields following [VER][0x02].
  160. func ReadPacketHeader(r io.Reader) (*PacketHeader, error) {
  161. var fixed [8]byte
  162. if _, err := io.ReadFull(r, fixed[:]); err != nil {
  163. return nil, err
  164. }
  165. ph := &PacketHeader{
  166. AssocID: binary.BigEndian.Uint16(fixed[0:2]),
  167. PktID: binary.BigEndian.Uint16(fixed[2:4]),
  168. FragTotal: fixed[4],
  169. FragID: fixed[5],
  170. Size: binary.BigEndian.Uint16(fixed[6:8]),
  171. }
  172. addr, err := ReadAddress(r)
  173. if err != nil {
  174. return nil, err
  175. }
  176. ph.Addr = addr
  177. return ph, nil
  178. }
  179. // WritePacket writes a complete Packet command frame to w.
  180. func WritePacket(w io.Writer, assocID, pktID uint16, fragTotal, fragID uint8, addr *Address, payload []byte) error {
  181. hdr := make([]byte, 10)
  182. hdr[0] = ProtocolVersion
  183. hdr[1] = CmdPacket
  184. binary.BigEndian.PutUint16(hdr[2:4], assocID)
  185. binary.BigEndian.PutUint16(hdr[4:6], pktID)
  186. hdr[6] = fragTotal
  187. hdr[7] = fragID
  188. binary.BigEndian.PutUint16(hdr[8:10], uint16(len(payload)))
  189. if _, err := w.Write(hdr); err != nil {
  190. return err
  191. }
  192. if err := WriteAddress(w, addr); err != nil {
  193. return err
  194. }
  195. _, err := w.Write(payload)
  196. return err
  197. }