faster_stun/attribute/mod.rs
1pub mod address;
2pub mod error;
3
4use crate::{util, StunError};
5
6use std::{convert::TryFrom, net::SocketAddr};
7
8pub use address::Addr;
9pub use error::{Error, Kind as ErrKind};
10
11use bytes::{BufMut, BytesMut};
12use num_enum::TryFromPrimitive;
13
14#[repr(u8)]
15#[derive(TryFromPrimitive, PartialEq, Eq)]
16pub enum Transport {
17 TCP = 0x06,
18 UDP = 0x11,
19}
20
21/// STUN Attributes Registry
22///
23/// [RFC8126]: https://datatracker.ietf.org/doc/html/rfc8126
24/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
25/// [RFC8489]: https://datatracker.ietf.org/doc/html/rfc8489
26///
27/// A STUN attribute type is a hex number in the range 0x0000-0xFFFF.
28/// STUN attribute types in the range 0x0000-0x7FFF are considered
29/// comprehension-required; STUN attribute types in the range
30/// 0x8000-0xFFFF are considered comprehension-optional. A STUN agent
31/// handles unknown comprehension-required and comprehension-optional
32/// attributes differently.
33///
34/// STUN attribute types in the first half of the comprehension-required
35/// range (0x0000-0x3FFF) and in the first half of the comprehension-
36/// optional range (0x8000-0xBFFF) are assigned by IETF Review [RFC8126].
37/// STUN attribute types in the second half of the comprehension-required
38/// range (0x4000-0x7FFF) and in the second half of the comprehension-
39/// optional range (0xC000-0xFFFF) are assigned by Expert Review
40/// [RFC8126]. The responsibility of the expert is to verify that the
41/// selected codepoint(s) are not in use and that the request is not for
42/// an abnormally large number of codepoints. Technical review of the
43/// extension itself is outside the scope of the designated expert
44/// responsibility.
45///
46/// IANA has updated the names for attributes 0x0002, 0x0004, 0x0005,
47/// 0x0007, and 0x000B as well as updated the reference from [RFC5389] to
48/// [RFC8489] for each the following STUN methods.
49///
50/// In addition, [RFC5389] introduced a mistake in the name of attribute
51/// 0x0003; [RFC5389] called it CHANGE-ADDRESS when it was actually
52/// previously called CHANGE-REQUEST. Thus, IANA has updated the
53/// description for 0x0003 to read "Reserved; was CHANGE-REQUEST prior to
54/// [RFC5389]".
55///
56/// Comprehension-required range (0x0000-0x7FFF):
57/// 0x0000: Reserved
58/// 0x0001: MAPPED-ADDRESS
59/// 0x0002: Reserved; was RESPONSE-ADDRESS prior to [RFC5389]
60/// 0x0003: Reserved; was CHANGE-REQUEST prior to [RFC5389]
61/// 0x0004: Reserved; was SOURCE-ADDRESS prior to [RFC5389]
62/// 0x0005: Reserved; was CHANGED-ADDRESS prior to [RFC5389]
63/// 0x0006: USERNAME
64/// 0x0007: Reserved; was PASSWORD prior to [RFC5389]
65/// 0x0008: MESSAGE-INTEGRITY
66/// 0x0009: ERROR-CODE
67/// 0x000A: UNKNOWN-ATTRIBUTES
68/// 0x000B: Reserved; was REFLECTED-FROM prior to [RFC5389]
69/// 0x0014: REALM
70/// 0x0015: NONCE
71/// 0x0020: XOR-MAPPED-ADDRESS
72///
73/// Comprehension-optional range (0x8000-0xFFFF)
74/// 0x8022: SOFTWARE
75/// 0x8023: ALTERNATE-SERVER
76/// 0x8028: FINGERPRINT
77///
78/// IANA has added the following attribute to the "STUN Attributes"
79/// registry:
80///
81/// Comprehension-required range (0x0000-0x7FFF):
82/// 0x001C: MESSAGE-INTEGRITY-SHA256
83/// 0x001D: PASSWORD-ALGORITHM
84/// 0x001E: USERHASH
85///
86/// Comprehension-optional range (0x8000-0xFFFF)
87/// 0x8002: PASSWORD-ALGORITHMS
88/// 0x8003: ALTERNATE-DOMAIN
89#[repr(u16)]
90#[derive(TryFromPrimitive, PartialEq, Eq, Hash, Debug)]
91pub enum AttrKind {
92 UserName = 0x0006,
93 Data = 0x0013,
94 Realm = 0x0014,
95 Nonce = 0x0015,
96 XorPeerAddress = 0x0012,
97 XorRelayedAddress = 0x0016,
98 XorMappedAddress = 0x0020,
99 MappedAddress = 0x0001,
100 ResponseOrigin = 0x802B,
101 Software = 0x8022,
102 MessageIntegrity = 0x0008,
103 ErrorCode = 0x0009,
104 Lifetime = 0x000D,
105 ReqeestedTransport = 0x0019,
106 Fingerprint = 0x8028,
107 ChannelNumber = 0x000C,
108
109 // ice
110 IceControlled = 0x8029,
111 Priority = 0x0024,
112 UseCandidate = 0x0025,
113 IceControlling = 0x802A,
114}
115
116/// dyn faster_stun/turn message attribute.
117#[rustfmt::skip]
118pub trait Property<'a> {
119 type Error;
120 /// current attribute inner type.
121 type Inner;
122 /// get current attribute type.
123 fn kind() -> AttrKind;
124 /// write the current attribute to the buffer.
125 fn into(value: Self::Inner, buf: &mut BytesMut, t: &'a [u8]);
126 /// convert buffer to current attribute.
127 fn try_from(buf: &'a [u8], t: &'a [u8]) -> Result<Self::Inner, Self::Error>;
128}
129
130/// [RFC8265]: https://datatracker.ietf.org/doc/html/rfc8265
131/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
132/// [RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
133///
134/// The USERNAME attribute is used for message integrity. It identifies
135/// the username and password combination used in the message-integrity
136/// check.
137///
138/// The value of USERNAME is a variable-length value containing the
139/// authentication username. It MUST contain a UTF-8-encoded [RFC3629]
140/// sequence of fewer than 509 bytes and MUST have been processed using
141/// the OpaqueString profile [RFC8265]. A compliant implementation MUST
142/// be able to parse a UTF-8-encoded sequence of 763 or fewer octets to
143/// be compatible with [RFC5389].
144pub struct UserName;
145impl<'a> Property<'a> for UserName {
146 type Error = StunError;
147 type Inner = &'a str;
148
149 fn kind() -> AttrKind {
150 AttrKind::UserName
151 }
152
153 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
154 buf.put(value.as_bytes());
155 }
156
157 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
158 Ok(std::str::from_utf8(buf).map_err(|_| StunError::Utf8Error)?)
159 }
160}
161
162/// The DATA attribute is present in all Send and Data indications. The
163/// value portion of this attribute is variable length and consists of
164/// the application data (that is, the data that would immediately follow
165/// the UDP header if the data was been sent directly between the client
166/// and the peer). If the length of this attribute is not a multiple of
167/// 4, then padding must be added after this attribute.
168pub struct Data;
169impl<'a> Property<'a> for Data {
170 type Error = StunError;
171 type Inner = &'a [u8];
172
173 fn kind() -> AttrKind {
174 AttrKind::Data
175 }
176
177 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
178 buf.put(value);
179 }
180
181 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
182 Ok(buf)
183 }
184}
185
186/// [RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
187/// [RFC3261]: https://datatracker.ietf.org/doc/html/rfc3261
188/// [RFC8265]: https://datatracker.ietf.org/doc/html/rfc8265
189///
190/// The REALM attribute may be present in requests and responses. It
191/// contains text that meets the grammar for "realm-value" as described
192/// in [RFC3261] but without the double quotes and their surrounding
193/// whitespace. That is, it is an unquoted realm-value (and is therefore
194/// a sequence of qdtext or quoted-pair). It MUST be a UTF-8-encoded
195/// [RFC3629] sequence of fewer than 128 characters (which can be as long
196/// as 509 bytes when encoding them and as long as 763 bytes when
197/// decoding them) and MUST have been processed using the OpaqueString
198/// profile [RFC8265].
199///
200/// Presence of the REALM attribute in a request indicates that long-term
201/// credentials are being used for authentication. Presence in certain
202/// error responses indicates that the server wishes the client to use a
203/// long-term credential in that realm for authentication.
204pub struct Realm;
205impl<'a> Property<'a> for Realm {
206 type Error = StunError;
207 type Inner = &'a str;
208
209 fn kind() -> AttrKind {
210 AttrKind::Realm
211 }
212
213 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
214 buf.put(value.as_bytes());
215 }
216
217 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
218 Ok(std::str::from_utf8(buf).map_err(|_| StunError::Utf8Error)?)
219 }
220}
221
222/// [RFC3261]: https://datatracker.ietf.org/doc/html/rfc3261
223/// [RFC7616]: https://datatracker.ietf.org/doc/html/rfc7616
224///
225/// The NONCE attribute may be present in requests and responses. It
226/// contains a sequence of qdtext or quoted-pair, which are defined in
227/// [RFC3261]. Note that this means that the NONCE attribute will not
228/// contain the actual surrounding quote characters. The NONCE attribute
229/// MUST be fewer than 128 characters (which can be as long as 509 bytes
230/// when encoding them and a long as 763 bytes when decoding them). See
231/// Section 5.4 of [RFC7616] for guidance on selection of nonce values in
232/// a server.
233pub struct Nonce;
234impl<'a> Property<'a> for Nonce {
235 type Error = StunError;
236 type Inner = &'a str;
237
238 fn kind() -> AttrKind {
239 AttrKind::Nonce
240 }
241
242 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
243 buf.put(value.as_bytes());
244 }
245
246 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
247 Ok(std::str::from_utf8(buf).map_err(|_| StunError::Utf8Error)?)
248 }
249}
250
251/// [RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
252///
253/// The SOFTWARE attribute contains a textual description of the software
254/// being used by the agent sending the message. It is used by clients
255/// and servers. Its value SHOULD include manufacturer and version
256/// number. The attribute has no impact on operation of the protocol and
257/// serves only as a tool for diagnostic and debugging purposes. The
258/// value of SOFTWARE is variable length. It MUST be a UTF-8-encoded
259/// [RFC3629] sequence of fewer than 128 characters (which can be as long
260/// as 509 when encoding them and as long as 763 bytes when decoding
261/// them).
262pub struct Software;
263impl<'a> Property<'a> for Software {
264 type Error = StunError;
265 type Inner = &'a str;
266
267 fn kind() -> AttrKind {
268 AttrKind::Software
269 }
270
271 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
272 buf.put(value.as_bytes());
273 }
274
275 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
276 Ok(std::str::from_utf8(buf).map_err(|_| StunError::Utf8Error)?)
277 }
278}
279
280/// [RFC2104]: https://datatracker.ietf.org/doc/html/rfc2104
281/// [RFC5769]: https://datatracker.ietf.org/doc/html/rfc5769
282///
283/// The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of
284/// the STUN message. The MESSAGE-INTEGRITY attribute can be present in
285/// any STUN message type. Since it uses the SHA-1 hash, the HMAC will
286/// be 20 bytes.
287///
288/// The key for the HMAC depends on which credential mechanism is in use.
289/// Section 9.1.1 defines the key for the short-term credential
290/// mechanism, and Section 9.2.2 defines the key for the long-term
291/// credential mechanism. Other credential mechanisms MUST define the
292/// key that is used for the HMAC.
293///
294/// The text used as input to HMAC is the STUN message, up to and
295/// including the attribute preceding the MESSAGE-INTEGRITY attribute.
296/// The Length field of the STUN message header is adjusted to point to
297/// the end of the MESSAGE-INTEGRITY attribute. The value of the
298/// MESSAGE-INTEGRITY attribute is set to a dummy value.
299///
300/// Once the computation is performed, the value of the MESSAGE-INTEGRITY
301/// attribute is filled in, and the value of the length in the STUN
302/// header is set to its correct value -- the length of the entire
303/// message. Similarly, when validating the MESSAGE-INTEGRITY, the
304/// Length field in the STUN header must be adjusted to point to the end
305/// of the MESSAGE-INTEGRITY attribute prior to calculating the HMAC over
306/// the STUN message, up to and including the attribute preceding the
307/// MESSAGE-INTEGRITY attribute. Such adjustment is necessary when
308/// attributes, such as FINGERPRINT and MESSAGE-INTEGRITY-SHA256, appear
309/// after MESSAGE-INTEGRITY. See also [RFC5769] for examples of such
310/// calculations.
311pub struct MessageIntegrity;
312impl<'a> Property<'a> for MessageIntegrity {
313 type Error = StunError;
314 type Inner = &'a [u8];
315
316 fn kind() -> AttrKind {
317 AttrKind::MessageIntegrity
318 }
319
320 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
321 buf.put(value);
322 }
323
324 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
325 Ok(buf)
326 }
327}
328
329/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
330///
331/// The XOR-PEER-ADDRESS specifies the address and port of the peer as
332/// seen from the TURN server. (For example, the peer's server-reflexive
333/// transport address if the peer is behind a NAT.) It is encoded in the
334/// same way as XOR-MAPPED-ADDRESS [RFC5389].
335pub struct XorPeerAddress;
336impl<'a> Property<'a> for XorPeerAddress {
337 type Error = StunError;
338 type Inner = SocketAddr;
339
340 fn kind() -> AttrKind {
341 AttrKind::XorPeerAddress
342 }
343
344 fn into(value: Self::Inner, buf: &mut BytesMut, token: &[u8]) {
345 Addr::into(&value, token, buf, true)
346 }
347
348 fn try_from(buf: &'a [u8], token: &'a [u8]) -> Result<Self::Inner, Self::Error> {
349 Addr::try_from(buf, token, true)
350 }
351}
352
353/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
354///
355/// The XOR-RELAYED-ADDRESS is present in Allocate responses. It
356/// specifies the address and port that the server allocated to the
357/// client. It is encoded in the same way as XOR-MAPPED-ADDRESS
358/// [RFC5389].
359pub struct XorRelayedAddress;
360impl<'a> Property<'a> for XorRelayedAddress {
361 type Error = StunError;
362 type Inner = SocketAddr;
363
364 fn kind() -> AttrKind {
365 AttrKind::XorRelayedAddress
366 }
367
368 fn into(value: Self::Inner, buf: &mut BytesMut, token: &[u8]) {
369 Addr::into(&value, token, buf, true)
370 }
371
372 fn try_from(buf: &'a [u8], token: &'a [u8]) -> Result<Self::Inner, Self::Error> {
373 Addr::try_from(buf, token, true)
374 }
375}
376
377/// [RFC3489]: https://datatracker.ietf.org/doc/html/rfc3489
378///
379/// The XOR-MAPPED-ADDRESS attribute is identical to the MAPPED-ADDRESS
380/// attribute, except that the reflexive transport address is obfuscated
381/// through the XOR function.
382///
383/// The format of the XOR-MAPPED-ADDRESS is:
384///
385/// ```bash
386/// 0 1 2 3
387/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
388/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
389/// |0 0 0 0 0 0 0 0| Family | X-Port |
390/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391/// | X-Address (Variable)
392/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393/// ```
394///
395/// The Family field represents the IP address family and is encoded
396/// identically to the Family field in MAPPED-ADDRESS.
397///
398/// X-Port is computed by XOR'ing the mapped port with the most
399/// significant 16 bits of the magic cookie. If the IP address family is
400/// IPv4, X-Address is computed by XOR'ing the mapped IP address with the
401/// magic cookie. If the IP address family is IPv6, X-Address is
402/// computed by XOR'ing the mapped IP address with the concatenation of
403/// the magic cookie and the 96-bit transaction ID. In all cases, the
404/// XOR operation works on its inputs in network byte order (that is, the
405/// order they will be encoded in the message).
406///
407/// The rules for encoding and processing the first 8 bits of the
408/// attribute's value, the rules for handling multiple occurrences of the
409/// attribute, and the rules for processing address families are the same
410/// as for MAPPED-ADDRESS.
411///
412/// Note: XOR-MAPPED-ADDRESS and MAPPED-ADDRESS differ only in their
413/// encoding of the transport address. The former encodes the transport
414/// address by XOR'ing it with the magic cookie. The latter encodes it
415/// directly in binary. [RFC3489] originally specified only MAPPED-
416/// ADDRESS. However, deployment experience found that some NATs rewrite
417/// the 32-bit binary payloads containing the NAT's public IP address,
418/// such as STUN's MAPPED-ADDRESS attribute, in the well-meaning but
419/// misguided attempt to provide a generic Application Layer Gateway
420/// (ALG) function. Such behavior interferes with the operation of STUN
421/// and also causes failure of STUN's message-integrity checking.
422pub struct XorMappedAddress;
423impl<'a> Property<'a> for XorMappedAddress {
424 type Error = StunError;
425 type Inner = SocketAddr;
426
427 fn kind() -> AttrKind {
428 AttrKind::XorMappedAddress
429 }
430
431 fn into(value: Self::Inner, buf: &mut BytesMut, token: &[u8]) {
432 Addr::into(&value, token, buf, true)
433 }
434
435 fn try_from(buf: &'a [u8], token: &'a [u8]) -> Result<Self::Inner, Self::Error> {
436 Addr::try_from(buf, token, true)
437 }
438}
439
440/// [RFC3489]: https://datatracker.ietf.org/doc/html/rfc3489
441///
442/// The MAPPED-ADDRESS attribute indicates a reflexive transport address
443/// of the client. It consists of an 8-bit address family and a 16-bit
444/// port, followed by a fixed-length value representing the IP address.
445/// If the address family is IPv4, the address MUST be 32 bits. If the
446/// address family is IPv6, the address MUST be 128 bits. All fields
447/// must be in network byte order.
448///
449/// The format of the MAPPED-ADDRESS attribute is:
450///
451/// ```bash
452/// 0 1 2 3
453/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
454/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
455/// |0 0 0 0 0 0 0 0| Family | Port |
456/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
457/// | |
458/// | Address (32 bits or 128 bits) |
459/// | |
460/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
461/// ```
462///
463/// The address family can take on the following values:
464///
465/// 0x01:IPv4
466/// 0x02:IPv6
467///
468/// The first 8 bits of the MAPPED-ADDRESS MUST be set to 0 and MUST be
469/// ignored by receivers. These bits are present for aligning parameters
470/// on natural 32-bit boundaries.
471///
472/// This attribute is used only by servers for achieving backwards
473/// compatibility with [RFC3489] clients.
474pub struct MappedAddress;
475impl<'a> Property<'a> for MappedAddress {
476 type Error = StunError;
477 type Inner = SocketAddr;
478
479 fn kind() -> AttrKind {
480 AttrKind::MappedAddress
481 }
482
483 fn into(value: Self::Inner, buf: &mut BytesMut, token: &[u8]) {
484 Addr::into(&value, token, buf, false)
485 }
486
487 fn try_from(buf: &'a [u8], token: &'a [u8]) -> Result<Self::Inner, Self::Error> {
488 Addr::try_from(buf, token, false)
489 }
490}
491
492/// The RESPONSE-ORIGIN attribute is inserted by the server and indicates
493/// the source IP address and port the response was sent from. It is
494/// useful for detecting double NAT configurations. It is only present
495/// in Binding Responses.
496pub struct ResponseOrigin;
497impl<'a> Property<'a> for ResponseOrigin {
498 type Error = StunError;
499 type Inner = SocketAddr;
500
501 fn kind() -> AttrKind {
502 AttrKind::ResponseOrigin
503 }
504
505 fn into(value: Self::Inner, buf: &mut BytesMut, token: &[u8]) {
506 Addr::into(&value, token, buf, false)
507 }
508
509 fn try_from(buf: &'a [u8], token: &'a [u8]) -> Result<Self::Inner, Self::Error> {
510 Addr::try_from(buf, token, false)
511 }
512}
513
514/// [RFC7231]: https://datatracker.ietf.org/doc/html/rfc7231
515/// [RFC3261]: https://datatracker.ietf.org/doc/html/rfc3261
516/// [RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
517///
518/// The ERROR-CODE attribute is used in error response messages. It
519/// contains a numeric error code value in the range of 300 to 699 plus a
520/// textual reason phrase encoded in UTF-8 [RFC3629]; it is also
521/// consistent in its code assignments and semantics with SIP [RFC3261]
522/// and HTTP [RFC7231]. The reason phrase is meant for diagnostic
523/// purposes and can be anything appropriate for the error code.
524/// Recommended reason phrases for the defined error codes are included
525/// in the IANA registry for error codes. The reason phrase MUST be a
526/// UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (which
527/// can be as long as 509 bytes when encoding them or 763 bytes when
528/// decoding them).
529///
530/// ```text
531/// 0 1 2 3
532/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
533/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534/// | Reserved, should be 0 |Class| Number |
535/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536/// | Reason Phrase (variable) ..
537/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538/// ```
539pub struct ErrorCode;
540impl<'a> Property<'a> for ErrorCode {
541 type Error = StunError;
542 type Inner = Error<'a>;
543
544 fn kind() -> AttrKind {
545 AttrKind::ErrorCode
546 }
547
548 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
549 value.into(buf)
550 }
551
552 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
553 Error::try_from(buf)
554 }
555}
556
557/// The LIFETIME attribute represents the duration for which the server
558/// will maintain an allocation in the absence of a refresh. The value
559/// portion of this attribute is 4-bytes long and consists of a 32-bit
560/// unsigned integral value representing the number of seconds remaining
561/// until expiration.
562pub struct Lifetime;
563impl<'a> Property<'a> for Lifetime {
564 type Error = StunError;
565 type Inner = u32;
566
567 fn kind() -> AttrKind {
568 AttrKind::Lifetime
569 }
570
571 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
572 buf.put_u32(value)
573 }
574
575 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
576 Ok(util::as_u32(buf))
577 }
578}
579
580/// This attribute is used by the client to request a specific transport
581/// protocol for the allocated transport address. The value of this
582/// attribute is 4 bytes with the following format:
583///
584/// ```bash
585/// 0 1 2 3
586/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
587/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588/// | Protocol | RFFU |
589/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590/// ```
591///
592/// The Protocol field specifies the desired protocol. The codepoints
593/// used in this field are taken from those allowed in the Protocol field
594/// in the IPv4 header and the NextHeader field in the IPv6 header
595/// [Protocol-Numbers]. This specification only allows the use of
596/// codepoint 17 (User Datagram Protocol).
597///
598/// The RFFU field MUST be set to zero on transmission and MUST be
599/// ignored on reception. It is reserved for future uses.
600pub struct ReqeestedTransport;
601impl<'a> Property<'a> for ReqeestedTransport {
602 type Error = StunError;
603 type Inner = Transport;
604
605 fn kind() -> AttrKind {
606 AttrKind::ReqeestedTransport
607 }
608
609 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
610 buf.put_u8(value as u8)
611 }
612
613 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
614 Ok(Transport::try_from(buf[0]).map_err(|_| StunError::InvalidInput)?)
615 }
616}
617
618/// [RFC1952]: https://datatracker.ietf.org/doc/html/rfc1952
619///
620/// The FINGERPRINT attribute MAY be present in all STUN messages.
621///
622/// The value of the attribute is computed as the CRC-32 of the STUN
623/// message up to (but excluding) the FINGERPRINT attribute itself,
624/// XOR'ed with the 32-bit value 0x5354554e. (The XOR operation ensures
625/// that the FINGERPRINT test will not report a false positive on a
626/// packet containing a CRC-32 generated by an application protocol.)
627/// The 32-bit CRC is the one defined in ITU V.42, which
628/// has a generator polynomial of x^32 + x^26 + x^23 + x^22 + x^16 + x^12
629/// + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1. See the sample
630/// code for the CRC-32 in Section 8 of [RFC1952].
631///
632/// When present, the FINGERPRINT attribute MUST be the last attribute in
633/// the message and thus will appear after MESSAGE-INTEGRITY and MESSAGE-
634/// INTEGRITY-SHA256.
635///
636/// The FINGERPRINT attribute can aid in distinguishing STUN packets from
637/// packets of other protocols. See Section 7.
638///
639/// As with MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256, the CRC used
640/// in the FINGERPRINT attribute covers the Length field from the STUN
641/// message header. Therefore, prior to computation of the CRC, this
642/// value must be correct and include the CRC attribute as part of the
643/// message length. When using the FINGERPRINT attribute in a message,
644/// the attribute is first placed into the message with a dummy value;
645/// then, the CRC is computed, and the value of the attribute is updated.
646/// If the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute is
647/// also present, then it must be present with the correct message-
648/// integrity value before the CRC is computed, since the CRC is done
649/// over the value of the MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256
650/// attributes as well.
651pub struct Fingerprint;
652impl<'a> Property<'a> for Fingerprint {
653 type Error = StunError;
654 type Inner = u32;
655
656 fn kind() -> AttrKind {
657 AttrKind::Fingerprint
658 }
659
660 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
661 buf.put_u32(value)
662 }
663
664 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
665 Ok(util::as_u32(buf))
666 }
667}
668
669/// The CHANNEL-NUMBER attribute contains the number of the channel. The
670/// value portion of this attribute is 4 bytes long and consists of a
671/// 16-bit unsigned integer followed by a two-octet RFFU (Reserved For
672/// Future Use) field, which MUST be set to 0 on transmission and MUST be
673/// ignored on reception.
674///
675/// ```bash
676/// 0 1 2 3
677/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
678/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
679/// | Channel Number | RFFU = 0 |
680/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
681/// ```
682pub struct ChannelNumber;
683impl<'a> Property<'a> for ChannelNumber {
684 type Error = StunError;
685 type Inner = u16;
686
687 fn kind() -> AttrKind {
688 AttrKind::ChannelNumber
689 }
690
691 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
692 buf.put_u16(value)
693 }
694
695 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
696 Ok(util::as_u16(buf))
697 }
698}
699
700/// The ICE-CONTROLLING attribute is present in a Binding request. The
701/// attribute indicates that the client believes it is currently in the
702/// controlling role. The content of the attribute is a 64-bit unsigned
703/// integer in network byte order, which contains a random number. As
704/// for the ICE-CONTROLLED attribute, the number is used for solving role
705/// conflicts. An agent MUST use the same number for all Binding
706/// requests, for all streams, within an ICE session, unless it has
707/// received a 487 response, in which case it MUST change the number.
708/// The agent MAY change the number when an ICE restart occurs.
709pub struct IceControlling;
710impl<'a> Property<'a> for IceControlling {
711 type Error = StunError;
712 type Inner = u64;
713
714 fn kind() -> AttrKind {
715 AttrKind::IceControlling
716 }
717
718 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
719 buf.put_u64(value)
720 }
721
722 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
723 Ok(util::as_u64(buf))
724 }
725}
726
727/// The USE-CANDIDATE attribute indicates that the candidate pair
728/// resulting from this check will be used for transmission of data. The
729/// attribute has no content (the Length field of the attribute is zero);
730/// it serves as a flag. It has an attribute value of 0x0025..
731pub struct UseCandidate;
732impl<'a> Property<'a> for UseCandidate {
733 type Error = StunError;
734 type Inner = ();
735
736 fn kind() -> AttrKind {
737 AttrKind::UseCandidate
738 }
739
740 fn into(_: Self::Inner, _: &mut BytesMut, _: &[u8]) {}
741
742 fn try_from(_: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
743 Ok(())
744 }
745}
746
747/// The ICE-CONTROLLED attribute is present in a Binding request. The
748/// attribute indicates that the client believes it is currently in the
749/// controlled role. The content of the attribute is a 64-bit unsigned
750/// integer in network byte order, which contains a random number. The
751/// number is used for solving role conflicts, when it is referred to as
752/// the "tiebreaker value". An ICE agent MUST use the same number for
753/// all Binding requests, for all streams, within an ICE session, unless
754/// it has received a 487 response, in which case it MUST change the
755/// number. The agent MAY change the number when an ICE restart occurs.
756pub struct IceControlled;
757impl<'a> Property<'a> for IceControlled {
758 type Error = StunError;
759 type Inner = u64;
760
761 fn kind() -> AttrKind {
762 AttrKind::IceControlled
763 }
764
765 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
766 buf.put_u64(value)
767 }
768
769 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
770 Ok(util::as_u64(buf))
771 }
772}
773
774/// The PRIORITY attribute indicates the priority that is to be
775/// associated with a peer-reflexive candidate, if one will be discovered
776/// by this check. It is a 32-bit unsigned integer and has an attribute
777/// value of 0x0024.
778pub struct Priority;
779impl<'a> Property<'a> for Priority {
780 type Error = StunError;
781 type Inner = u32;
782
783 fn kind() -> AttrKind {
784 AttrKind::Priority
785 }
786
787 fn into(value: Self::Inner, buf: &mut BytesMut, _: &[u8]) {
788 buf.put_u32(value)
789 }
790
791 fn try_from(buf: &'a [u8], _: &'a [u8]) -> Result<Self::Inner, Self::Error> {
792 Ok(util::as_u32(buf))
793 }
794}