version.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package protocol
  2. import (
  3. "crypto/rand"
  4. "encoding/binary"
  5. "fmt"
  6. "math"
  7. )
  8. // VersionNumber is a version number as int
  9. type VersionNumber uint32
  10. // gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions
  11. const (
  12. gquicVersion0 = 0x51303030
  13. maxGquicVersion = 0x51303439
  14. )
  15. // The version numbers, making grepping easier
  16. const (
  17. Version39 VersionNumber = gquicVersion0 + 3*0x100 + 0x9
  18. Version43 VersionNumber = gquicVersion0 + 4*0x100 + 0x3
  19. Version44 VersionNumber = gquicVersion0 + 4*0x100 + 0x4
  20. VersionTLS VersionNumber = 101
  21. VersionWhatever VersionNumber = 0 // for when the version doesn't matter
  22. VersionUnknown VersionNumber = math.MaxUint32
  23. )
  24. // SupportedVersions lists the versions that the server supports
  25. // must be in sorted descending order
  26. var SupportedVersions = []VersionNumber{
  27. Version44,
  28. Version43,
  29. Version39,
  30. }
  31. // IsValidVersion says if the version is known to quic-go
  32. func IsValidVersion(v VersionNumber) bool {
  33. return v == VersionTLS || IsSupportedVersion(SupportedVersions, v)
  34. }
  35. // UsesTLS says if this QUIC version uses TLS 1.3 for the handshake
  36. func (vn VersionNumber) UsesTLS() bool {
  37. return !vn.isGQUIC()
  38. }
  39. func (vn VersionNumber) String() string {
  40. switch vn {
  41. case VersionWhatever:
  42. return "whatever"
  43. case VersionUnknown:
  44. return "unknown"
  45. case VersionTLS:
  46. return "TLS dev version (WIP)"
  47. default:
  48. if vn.isGQUIC() {
  49. return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())
  50. }
  51. return fmt.Sprintf("%#x", uint32(vn))
  52. }
  53. }
  54. // ToAltSvc returns the representation of the version for the H2 Alt-Svc parameters
  55. func (vn VersionNumber) ToAltSvc() string {
  56. if vn.isGQUIC() {
  57. return fmt.Sprintf("%d", vn.toGQUICVersion())
  58. }
  59. return fmt.Sprintf("%d", vn)
  60. }
  61. // CryptoStreamID gets the Stream ID of the crypto stream
  62. func (vn VersionNumber) CryptoStreamID() StreamID {
  63. if vn.isGQUIC() {
  64. return 1
  65. }
  66. return 0
  67. }
  68. // UsesIETFFrameFormat tells if this version uses the IETF frame format
  69. func (vn VersionNumber) UsesIETFFrameFormat() bool {
  70. return !vn.isGQUIC()
  71. }
  72. // UsesIETFHeaderFormat tells if this version uses the IETF header format
  73. func (vn VersionNumber) UsesIETFHeaderFormat() bool {
  74. return !vn.isGQUIC() || vn >= Version44
  75. }
  76. // UsesLengthInHeader tells if this version uses the Length field in the IETF header
  77. func (vn VersionNumber) UsesLengthInHeader() bool {
  78. return !vn.isGQUIC()
  79. }
  80. // UsesTokenInHeader tells if this version uses the Token field in the IETF header
  81. func (vn VersionNumber) UsesTokenInHeader() bool {
  82. return !vn.isGQUIC()
  83. }
  84. // UsesStopWaitingFrames tells if this version uses STOP_WAITING frames
  85. func (vn VersionNumber) UsesStopWaitingFrames() bool {
  86. return vn.isGQUIC() && vn <= Version43
  87. }
  88. // UsesVarintPacketNumbers tells if this version uses 7/14/30 bit packet numbers
  89. func (vn VersionNumber) UsesVarintPacketNumbers() bool {
  90. return !vn.isGQUIC()
  91. }
  92. // StreamContributesToConnectionFlowControl says if a stream contributes to connection-level flow control
  93. func (vn VersionNumber) StreamContributesToConnectionFlowControl(id StreamID) bool {
  94. if id == vn.CryptoStreamID() {
  95. return false
  96. }
  97. if vn.isGQUIC() && id == 3 {
  98. return false
  99. }
  100. return true
  101. }
  102. func (vn VersionNumber) isGQUIC() bool {
  103. return vn > gquicVersion0 && vn <= maxGquicVersion
  104. }
  105. func (vn VersionNumber) toGQUICVersion() int {
  106. return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10)
  107. }
  108. // IsSupportedVersion returns true if the server supports this version
  109. func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool {
  110. for _, t := range supported {
  111. if t == v {
  112. return true
  113. }
  114. }
  115. return false
  116. }
  117. // ChooseSupportedVersion finds the best version in the overlap of ours and theirs
  118. // ours is a slice of versions that we support, sorted by our preference (descending)
  119. // theirs is a slice of versions offered by the peer. The order does not matter.
  120. // The bool returned indicates if a matching version was found.
  121. func ChooseSupportedVersion(ours, theirs []VersionNumber) (VersionNumber, bool) {
  122. for _, ourVer := range ours {
  123. for _, theirVer := range theirs {
  124. if ourVer == theirVer {
  125. return ourVer, true
  126. }
  127. }
  128. }
  129. return 0, false
  130. }
  131. // generateReservedVersion generates a reserved version number (v & 0x0f0f0f0f == 0x0a0a0a0a)
  132. func generateReservedVersion() VersionNumber {
  133. b := make([]byte, 4)
  134. _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
  135. return VersionNumber((binary.BigEndian.Uint32(b) | 0x0a0a0a0a) & 0xfafafafa)
  136. }
  137. // GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position
  138. func GetGreasedVersions(supported []VersionNumber) []VersionNumber {
  139. b := make([]byte, 1)
  140. _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
  141. randPos := int(b[0]) % (len(supported) + 1)
  142. greased := make([]VersionNumber, len(supported)+1)
  143. copy(greased, supported[:randPos])
  144. greased[randPos] = generateReservedVersion()
  145. copy(greased[randPos+1:], supported[randPos:])
  146. return greased
  147. }
  148. // StripGreasedVersions strips all greased versions from a slice of versions
  149. func StripGreasedVersions(versions []VersionNumber) []VersionNumber {
  150. realVersions := make([]VersionNumber, 0, len(versions))
  151. for _, v := range versions {
  152. if v&0x0f0f0f0f != 0x0a0a0a0a {
  153. realVersions = append(realVersions, v)
  154. }
  155. }
  156. return realVersions
  157. }