attributes.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package stun
  4. import (
  5. "errors"
  6. "fmt"
  7. )
  8. // Attributes is list of message attributes.
  9. type Attributes []RawAttribute
  10. // Get returns first attribute from list by the type.
  11. // If attribute is present the RawAttribute is returned and the
  12. // boolean is true. Otherwise the returned RawAttribute will be
  13. // empty and boolean will be false.
  14. func (a Attributes) Get(t AttrType) (RawAttribute, bool) {
  15. for _, candidate := range a {
  16. if candidate.Type == t {
  17. return candidate, true
  18. }
  19. }
  20. return RawAttribute{}, false
  21. }
  22. // AttrType is attribute type.
  23. type AttrType uint16
  24. // Required returns true if type is from comprehension-required range (0x0000-0x7FFF).
  25. func (t AttrType) Required() bool {
  26. return t <= 0x7FFF
  27. }
  28. // Optional returns true if type is from comprehension-optional range (0x8000-0xFFFF).
  29. func (t AttrType) Optional() bool {
  30. return t >= 0x8000
  31. }
  32. // Attributes from comprehension-required range (0x0000-0x7FFF).
  33. const (
  34. AttrMappedAddress AttrType = 0x0001 // MAPPED-ADDRESS
  35. AttrUsername AttrType = 0x0006 // USERNAME
  36. AttrMessageIntegrity AttrType = 0x0008 // MESSAGE-INTEGRITY
  37. AttrErrorCode AttrType = 0x0009 // ERROR-CODE
  38. AttrUnknownAttributes AttrType = 0x000A // UNKNOWN-ATTRIBUTES
  39. AttrRealm AttrType = 0x0014 // REALM
  40. AttrNonce AttrType = 0x0015 // NONCE
  41. AttrXORMappedAddress AttrType = 0x0020 // XOR-MAPPED-ADDRESS
  42. )
  43. // Attributes from comprehension-optional range (0x8000-0xFFFF).
  44. const (
  45. AttrSoftware AttrType = 0x8022 // SOFTWARE
  46. AttrAlternateServer AttrType = 0x8023 // ALTERNATE-SERVER
  47. AttrFingerprint AttrType = 0x8028 // FINGERPRINT
  48. )
  49. // Attributes from RFC 5245 ICE.
  50. const (
  51. AttrPriority AttrType = 0x0024 // PRIORITY
  52. AttrUseCandidate AttrType = 0x0025 // USE-CANDIDATE
  53. AttrICEControlled AttrType = 0x8029 // ICE-CONTROLLED
  54. AttrICEControlling AttrType = 0x802A // ICE-CONTROLLING
  55. )
  56. // Attributes from RFC 5766 TURN.
  57. const (
  58. AttrChannelNumber AttrType = 0x000C // CHANNEL-NUMBER
  59. AttrLifetime AttrType = 0x000D // LIFETIME
  60. AttrXORPeerAddress AttrType = 0x0012 // XOR-PEER-ADDRESS
  61. AttrData AttrType = 0x0013 // DATA
  62. AttrXORRelayedAddress AttrType = 0x0016 // XOR-RELAYED-ADDRESS
  63. AttrEvenPort AttrType = 0x0018 // EVEN-PORT
  64. AttrRequestedTransport AttrType = 0x0019 // REQUESTED-TRANSPORT
  65. AttrDontFragment AttrType = 0x001A // DONT-FRAGMENT
  66. AttrReservationToken AttrType = 0x0022 // RESERVATION-TOKEN
  67. )
  68. // Attributes from RFC 5780 NAT Behavior Discovery
  69. const (
  70. AttrChangeRequest AttrType = 0x0003 // CHANGE-REQUEST
  71. AttrPadding AttrType = 0x0026 // PADDING
  72. AttrResponsePort AttrType = 0x0027 // RESPONSE-PORT
  73. AttrCacheTimeout AttrType = 0x8027 // CACHE-TIMEOUT
  74. AttrResponseOrigin AttrType = 0x802b // RESPONSE-ORIGIN
  75. AttrOtherAddress AttrType = 0x802C // OTHER-ADDRESS
  76. )
  77. // Attributes from RFC 3489, removed by RFC 5389,
  78. //
  79. // but still used by RFC5389-implementing software like Vovida.org, reTURNServer, etc.
  80. const (
  81. AttrSourceAddress AttrType = 0x0004 // SOURCE-ADDRESS
  82. AttrChangedAddress AttrType = 0x0005 // CHANGED-ADDRESS
  83. )
  84. // Attributes from RFC 6062 TURN Extensions for TCP Allocations.
  85. const (
  86. AttrConnectionID AttrType = 0x002a // CONNECTION-ID
  87. )
  88. // Attributes from RFC 6156 TURN IPv6.
  89. const (
  90. AttrRequestedAddressFamily AttrType = 0x0017 // REQUESTED-ADDRESS-FAMILY
  91. )
  92. // Attributes from An Origin Attribute for the STUN Protocol.
  93. const (
  94. AttrOrigin AttrType = 0x802F
  95. )
  96. // Attributes from RFC 8489 STUN.
  97. const (
  98. AttrMessageIntegritySHA256 AttrType = 0x001C // MESSAGE-INTEGRITY-SHA256
  99. AttrPasswordAlgorithm AttrType = 0x001D // PASSWORD-ALGORITHM
  100. AttrUserhash AttrType = 0x001E // USERHASH
  101. AttrPasswordAlgorithms AttrType = 0x8002 // PASSWORD-ALGORITHMS
  102. AttrAlternateDomain AttrType = 0x8003 // ALTERNATE-DOMAIN
  103. )
  104. // Value returns uint16 representation of attribute type.
  105. func (t AttrType) Value() uint16 {
  106. return uint16(t)
  107. }
  108. func attrNames() map[AttrType]string {
  109. return map[AttrType]string{
  110. AttrMappedAddress: "MAPPED-ADDRESS",
  111. AttrUsername: "USERNAME",
  112. AttrErrorCode: "ERROR-CODE",
  113. AttrMessageIntegrity: "MESSAGE-INTEGRITY",
  114. AttrUnknownAttributes: "UNKNOWN-ATTRIBUTES",
  115. AttrRealm: "REALM",
  116. AttrNonce: "NONCE",
  117. AttrXORMappedAddress: "XOR-MAPPED-ADDRESS",
  118. AttrSoftware: "SOFTWARE",
  119. AttrAlternateServer: "ALTERNATE-SERVER",
  120. AttrFingerprint: "FINGERPRINT",
  121. AttrPriority: "PRIORITY",
  122. AttrUseCandidate: "USE-CANDIDATE",
  123. AttrICEControlled: "ICE-CONTROLLED",
  124. AttrICEControlling: "ICE-CONTROLLING",
  125. AttrChannelNumber: "CHANNEL-NUMBER",
  126. AttrLifetime: "LIFETIME",
  127. AttrXORPeerAddress: "XOR-PEER-ADDRESS",
  128. AttrData: "DATA",
  129. AttrXORRelayedAddress: "XOR-RELAYED-ADDRESS",
  130. AttrEvenPort: "EVEN-PORT",
  131. AttrRequestedTransport: "REQUESTED-TRANSPORT",
  132. AttrDontFragment: "DONT-FRAGMENT",
  133. AttrReservationToken: "RESERVATION-TOKEN",
  134. AttrConnectionID: "CONNECTION-ID",
  135. AttrRequestedAddressFamily: "REQUESTED-ADDRESS-FAMILY",
  136. AttrMessageIntegritySHA256: "MESSAGE-INTEGRITY-SHA256",
  137. AttrPasswordAlgorithm: "PASSWORD-ALGORITHM",
  138. AttrUserhash: "USERHASH",
  139. AttrPasswordAlgorithms: "PASSWORD-ALGORITHMS",
  140. AttrAlternateDomain: "ALTERNATE-DOMAIN",
  141. }
  142. }
  143. func (t AttrType) String() string {
  144. s, ok := attrNames()[t]
  145. if !ok {
  146. // Just return hex representation of unknown attribute type.
  147. return fmt.Sprintf("0x%x", uint16(t))
  148. }
  149. return s
  150. }
  151. // RawAttribute is a Type-Length-Value (TLV) object that
  152. // can be added to a STUN message. Attributes are divided into two
  153. // types: comprehension-required and comprehension-optional. STUN
  154. // agents can safely ignore comprehension-optional attributes they
  155. // don't understand, but cannot successfully process a message if it
  156. // contains comprehension-required attributes that are not
  157. // understood.
  158. type RawAttribute struct {
  159. Type AttrType
  160. Length uint16 // ignored while encoding
  161. Value []byte
  162. }
  163. // AddTo implements Setter, adding attribute as a.Type with a.Value and ignoring
  164. // the Length field.
  165. func (a RawAttribute) AddTo(m *Message) error {
  166. m.Add(a.Type, a.Value)
  167. return nil
  168. }
  169. // Equal returns true if a == b.
  170. func (a RawAttribute) Equal(b RawAttribute) bool {
  171. if a.Type != b.Type {
  172. return false
  173. }
  174. if a.Length != b.Length {
  175. return false
  176. }
  177. if len(b.Value) != len(a.Value) {
  178. return false
  179. }
  180. for i, v := range a.Value {
  181. if b.Value[i] != v {
  182. return false
  183. }
  184. }
  185. return true
  186. }
  187. func (a RawAttribute) String() string {
  188. return fmt.Sprintf("%s: 0x%x", a.Type, a.Value)
  189. }
  190. // ErrAttributeNotFound means that attribute with provided attribute
  191. // type does not exist in message.
  192. var ErrAttributeNotFound = errors.New("attribute not found")
  193. // Get returns byte slice that represents attribute value,
  194. // if there is no attribute with such type,
  195. // ErrAttributeNotFound is returned.
  196. func (m *Message) Get(t AttrType) ([]byte, error) {
  197. v, ok := m.Attributes.Get(t)
  198. if !ok {
  199. return nil, ErrAttributeNotFound
  200. }
  201. return v.Value, nil
  202. }
  203. // STUN aligns attributes on 32-bit boundaries, attributes whose content
  204. // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of
  205. // padding so that its value contains a multiple of 4 bytes. The
  206. // padding bits are ignored, and may be any value.
  207. //
  208. // https://tools.ietf.org/html/rfc5389#section-15
  209. const padding = 4
  210. func nearestPaddedValueLength(l int) int {
  211. n := padding * (l / padding)
  212. if n < l {
  213. n += padding
  214. }
  215. return n
  216. }
  217. // This method converts uint16 vlue to AttrType. If it finds an old attribute
  218. // type value, it also translates it to the new value to enable backward
  219. // compatibility. (See: https://github.com/pion/stun/issues/21)
  220. func compatAttrType(val uint16) AttrType {
  221. if val == 0x8020 { // draft-ietf-behave-rfc3489bis-02, MS-TURN
  222. return AttrXORMappedAddress // new: 0x0020 (from draft-ietf-behave-rfc3489bis-03 on)
  223. }
  224. return AttrType(val)
  225. }