File: attributes.go

package info (click to toggle)
golang-github-pion-stun 0.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 868 kB
  • sloc: sh: 50; makefile: 40
file content (254 lines) | stat: -rw-r--r-- 8,262 bytes parent folder | download | duplicates (2)
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)
}