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