version.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. VersionTLS VersionNumber = 0x51474fff
  18. VersionWhatever VersionNumber = 1 // for when the version doesn't matter
  19. VersionUnknown VersionNumber = math.MaxUint32
  20. )
  21. // SupportedVersions lists the versions that the server supports
  22. // must be in sorted descending order
  23. var SupportedVersions = []VersionNumber{VersionTLS}
  24. // IsValidVersion says if the version is known to quic-go
  25. func IsValidVersion(v VersionNumber) bool {
  26. return v == VersionTLS || IsSupportedVersion(SupportedVersions, v)
  27. }
  28. func (vn VersionNumber) String() string {
  29. switch vn {
  30. case VersionWhatever:
  31. return "whatever"
  32. case VersionUnknown:
  33. return "unknown"
  34. case VersionTLS:
  35. return "TLS dev version (WIP)"
  36. default:
  37. if vn.isGQUIC() {
  38. return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())
  39. }
  40. return fmt.Sprintf("%#x", uint32(vn))
  41. }
  42. }
  43. // ToAltSvc returns the representation of the version for the H2 Alt-Svc parameters
  44. func (vn VersionNumber) ToAltSvc() string {
  45. return fmt.Sprintf("%d", vn)
  46. }
  47. func (vn VersionNumber) isGQUIC() bool {
  48. return vn > gquicVersion0 && vn <= maxGquicVersion
  49. }
  50. func (vn VersionNumber) toGQUICVersion() int {
  51. return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10)
  52. }
  53. // IsSupportedVersion returns true if the server supports this version
  54. func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool {
  55. for _, t := range supported {
  56. if t == v {
  57. return true
  58. }
  59. }
  60. return false
  61. }
  62. // ChooseSupportedVersion finds the best version in the overlap of ours and theirs
  63. // ours is a slice of versions that we support, sorted by our preference (descending)
  64. // theirs is a slice of versions offered by the peer. The order does not matter.
  65. // The bool returned indicates if a matching version was found.
  66. func ChooseSupportedVersion(ours, theirs []VersionNumber) (VersionNumber, bool) {
  67. for _, ourVer := range ours {
  68. for _, theirVer := range theirs {
  69. if ourVer == theirVer {
  70. return ourVer, true
  71. }
  72. }
  73. }
  74. return 0, false
  75. }
  76. // generateReservedVersion generates a reserved version number (v & 0x0f0f0f0f == 0x0a0a0a0a)
  77. func generateReservedVersion() VersionNumber {
  78. b := make([]byte, 4)
  79. _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
  80. return VersionNumber((binary.BigEndian.Uint32(b) | 0x0a0a0a0a) & 0xfafafafa)
  81. }
  82. // GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position
  83. func GetGreasedVersions(supported []VersionNumber) []VersionNumber {
  84. b := make([]byte, 1)
  85. _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
  86. randPos := int(b[0]) % (len(supported) + 1)
  87. greased := make([]VersionNumber, len(supported)+1)
  88. copy(greased, supported[:randPos])
  89. greased[randPos] = generateReservedVersion()
  90. copy(greased[randPos+1:], supported[randPos:])
  91. return greased
  92. }
  93. // StripGreasedVersions strips all greased versions from a slice of versions
  94. func StripGreasedVersions(versions []VersionNumber) []VersionNumber {
  95. realVersions := make([]VersionNumber, 0, len(versions))
  96. for _, v := range versions {
  97. if v&0x0f0f0f0f != 0x0a0a0a0a {
  98. realVersions = append(realVersions, v)
  99. }
  100. }
  101. return realVersions
  102. }