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}