Skip to main content

rtc_stun/
attributes.rs

1//! STUN attribute types.
2//!
3//! Every attribute is a type code, a length and a value ([`RawAttribute`](crate::attributes::RawAttribute)). This module defines
4//! the code points — those from STUN itself ([RFC 5389]) plus the ones TURN, ICE and the NAT
5//! behaviour discovery extensions add — while the typed accessors live in
6//! [`textattrs`](crate::textattrs), [`xoraddr`](crate::xoraddr),
7//! [`error_code`](crate::error_code) and friends.
8//!
9//! Codes below `0x8000` are *comprehension-required*: a receiver that does not understand one
10//! must reject the message. Codes at or above `0x8000` are comprehension-optional and may be
11//! ignored, which is how `FINGERPRINT` and the ICE attributes can be added without breaking
12//! older peers.
13//!
14//! [RFC 5389]: https://datatracker.ietf.org/doc/html/rfc5389
15
16#[cfg(test)]
17mod attributes_test;
18
19use crate::message::*;
20use shared::error::*;
21
22use std::fmt;
23
24/// Attributes is list of message attributes.
25#[derive(Default, PartialEq, Eq, Debug, Clone)]
26pub struct Attributes(pub Vec<RawAttribute>);
27
28impl Attributes {
29    /// get returns first attribute from list by the type.
30    /// If attribute is present the RawAttribute is returned and the
31    /// boolean is true. Otherwise the returned RawAttribute will be
32    /// empty and boolean will be false.
33    pub fn get(&self, t: AttrType) -> (RawAttribute, bool) {
34        for candidate in &self.0 {
35            if candidate.typ == t {
36                return (candidate.clone(), true);
37            }
38        }
39
40        (RawAttribute::default(), false)
41    }
42}
43
44/// AttrType is attribute type.
45#[derive(PartialEq, Debug, Eq, Default, Copy, Clone)]
46pub struct AttrType(pub u16);
47
48impl fmt::Display for AttrType {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        let other = format!("0x{:x}", self.0);
51
52        let s = match *self {
53            ATTR_MAPPED_ADDRESS => "MAPPED-ADDRESS",
54            ATTR_USERNAME => "USERNAME",
55            ATTR_ERROR_CODE => "ERROR-CODE",
56            ATTR_MESSAGE_INTEGRITY => "MESSAGE-INTEGRITY",
57            ATTR_UNKNOWN_ATTRIBUTES => "UNKNOWN-ATTRIBUTES",
58            ATTR_REALM => "REALM",
59            ATTR_NONCE => "NONCE",
60            ATTR_XORMAPPED_ADDRESS => "XOR-MAPPED-ADDRESS",
61            ATTR_SOFTWARE => "SOFTWARE",
62            ATTR_ALTERNATE_SERVER => "ALTERNATE-SERVER",
63            ATTR_FINGERPRINT => "FINGERPRINT",
64            ATTR_PRIORITY => "PRIORITY",
65            ATTR_USE_CANDIDATE => "USE-CANDIDATE",
66            ATTR_ICE_CONTROLLED => "ICE-CONTROLLED",
67            ATTR_ICE_CONTROLLING => "ICE-CONTROLLING",
68            ATTR_CHANNEL_NUMBER => "CHANNEL-NUMBER",
69            ATTR_LIFETIME => "LIFETIME",
70            ATTR_XOR_PEER_ADDRESS => "XOR-PEER-ADDRESS",
71            ATTR_DATA => "DATA",
72            ATTR_XOR_RELAYED_ADDRESS => "XOR-RELAYED-ADDRESS",
73            ATTR_EVEN_PORT => "EVEN-PORT",
74            ATTR_REQUESTED_TRANSPORT => "REQUESTED-TRANSPORT",
75            ATTR_DONT_FRAGMENT => "DONT-FRAGMENT",
76            ATTR_RESERVATION_TOKEN => "RESERVATION-TOKEN",
77            ATTR_CONNECTION_ID => "CONNECTION-ID",
78            ATTR_REQUESTED_ADDRESS_FAMILY => "REQUESTED-ADDRESS-FAMILY",
79            ATTR_MESSAGE_INTEGRITY_SHA256 => "MESSAGE-INTEGRITY-SHA256",
80            ATTR_PASSWORD_ALGORITHM => "PASSWORD-ALGORITHM",
81            ATTR_USER_HASH => "USERHASH",
82            ATTR_PASSWORD_ALGORITHMS => "PASSWORD-ALGORITHMS",
83            ATTR_ALTERNATE_DOMAIN => "ALTERNATE-DOMAIN",
84            _ => other.as_str(),
85        };
86
87        write!(f, "{s}")
88    }
89}
90
91impl AttrType {
92    /// required returns true if type is from comprehension-required range (0x0000-0x7FFF).
93    pub fn required(&self) -> bool {
94        self.0 <= 0x7FFF
95    }
96
97    /// optional returns true if type is from comprehension-optional range (0x8000-0xFFFF).
98    pub fn optional(&self) -> bool {
99        self.0 >= 0x8000
100    }
101
102    /// value returns uint16 representation of attribute type.
103    pub fn value(&self) -> u16 {
104        self.0
105    }
106}
107
108/// Attributes from comprehension-required range (0x0000-0x7FFF).
109/// MAPPED-ADDRESS.
110pub const ATTR_MAPPED_ADDRESS: AttrType = AttrType(0x0001);
111/// USERNAME.
112pub const ATTR_USERNAME: AttrType = AttrType(0x0006);
113/// MESSAGE-INTEGRITY.
114pub const ATTR_MESSAGE_INTEGRITY: AttrType = AttrType(0x0008);
115/// ERROR-CODE.
116pub const ATTR_ERROR_CODE: AttrType = AttrType(0x0009);
117/// UNKNOWN-ATTRIBUTES.
118pub const ATTR_UNKNOWN_ATTRIBUTES: AttrType = AttrType(0x000A);
119/// REALM.
120pub const ATTR_REALM: AttrType = AttrType(0x0014);
121/// NONCE.
122pub const ATTR_NONCE: AttrType = AttrType(0x0015);
123/// XOR-MAPPED-ADDRESS.
124pub const ATTR_XORMAPPED_ADDRESS: AttrType = AttrType(0x0020);
125
126/// Attributes from comprehension-optional range (0x8000-0xFFFF).
127/// SOFTWARE.
128pub const ATTR_SOFTWARE: AttrType = AttrType(0x8022);
129/// ALTERNATE-SERVER.
130pub const ATTR_ALTERNATE_SERVER: AttrType = AttrType(0x8023);
131/// FINGERPRINT.
132pub const ATTR_FINGERPRINT: AttrType = AttrType(0x8028);
133
134/// Attributes from RFC 5245 ICE.
135/// PRIORITY.
136pub const ATTR_PRIORITY: AttrType = AttrType(0x0024);
137/// USE-CANDIDATE.
138pub const ATTR_USE_CANDIDATE: AttrType = AttrType(0x0025);
139/// ICE-CONTROLLED.
140pub const ATTR_ICE_CONTROLLED: AttrType = AttrType(0x8029);
141/// ICE-CONTROLLING.
142pub const ATTR_ICE_CONTROLLING: AttrType = AttrType(0x802A);
143/// NETWORK-COST.
144pub const ATTR_NETWORK_COST: AttrType = AttrType(0xC057);
145
146/// Attributes from RFC 5766 TURN.
147/// CHANNEL-NUMBER.
148pub const ATTR_CHANNEL_NUMBER: AttrType = AttrType(0x000C);
149/// LIFETIME.
150pub const ATTR_LIFETIME: AttrType = AttrType(0x000D);
151/// XOR-PEER-ADDRESS.
152pub const ATTR_XOR_PEER_ADDRESS: AttrType = AttrType(0x0012);
153/// DATA.
154pub const ATTR_DATA: AttrType = AttrType(0x0013);
155/// XOR-RELAYED-ADDRESS.
156pub const ATTR_XOR_RELAYED_ADDRESS: AttrType = AttrType(0x0016);
157/// EVEN-PORT.
158pub const ATTR_EVEN_PORT: AttrType = AttrType(0x0018);
159/// REQUESTED-TRANSPORT.
160pub const ATTR_REQUESTED_TRANSPORT: AttrType = AttrType(0x0019);
161/// DONT-FRAGMENT.
162pub const ATTR_DONT_FRAGMENT: AttrType = AttrType(0x001A);
163/// RESERVATION-TOKEN.
164pub const ATTR_RESERVATION_TOKEN: AttrType = AttrType(0x0022);
165
166/// Attributes from RFC 5780 NAT Behavior Discovery
167/// CHANGE-REQUEST.
168pub const ATTR_CHANGE_REQUEST: AttrType = AttrType(0x0003);
169/// PADDING.
170pub const ATTR_PADDING: AttrType = AttrType(0x0026);
171/// RESPONSE-PORT.
172pub const ATTR_RESPONSE_PORT: AttrType = AttrType(0x0027);
173/// CACHE-TIMEOUT.
174pub const ATTR_CACHE_TIMEOUT: AttrType = AttrType(0x8027);
175/// RESPONSE-ORIGIN.
176pub const ATTR_RESPONSE_ORIGIN: AttrType = AttrType(0x802b);
177/// OTHER-ADDRESS.
178pub const ATTR_OTHER_ADDRESS: AttrType = AttrType(0x802C);
179
180/// Attributes from RFC 3489, removed by RFC 5389,
181///  but still used by RFC5389-implementing software like Vovida.org, reTURNServer, etc.
182/// SOURCE-ADDRESS.
183pub const ATTR_SOURCE_ADDRESS: AttrType = AttrType(0x0004);
184/// CHANGED-ADDRESS.
185pub const ATTR_CHANGED_ADDRESS: AttrType = AttrType(0x0005);
186
187/// Attributes from RFC 6062 TURN Extensions for TCP Allocations.
188/// CONNECTION-ID.
189pub const ATTR_CONNECTION_ID: AttrType = AttrType(0x002a);
190
191/// Attributes from RFC 6156 TURN IPv6.
192/// REQUESTED-ADDRESS-FAMILY.
193pub const ATTR_REQUESTED_ADDRESS_FAMILY: AttrType = AttrType(0x0017);
194
195/// Attributes from An Origin Attribute for the STUN Protocol.
196pub const ATTR_ORIGIN: AttrType = AttrType(0x802F);
197
198/// Attributes from RFC 8489 STUN.
199/// MESSAGE-INTEGRITY-SHA256.
200pub const ATTR_MESSAGE_INTEGRITY_SHA256: AttrType = AttrType(0x001C);
201/// PASSWORD-ALGORITHM.
202pub const ATTR_PASSWORD_ALGORITHM: AttrType = AttrType(0x001D);
203/// USER-HASH.
204pub const ATTR_USER_HASH: AttrType = AttrType(0x001E);
205/// PASSWORD-ALGORITHMS.
206pub const ATTR_PASSWORD_ALGORITHMS: AttrType = AttrType(0x8002);
207/// ALTERNATE-DOMAIN.
208pub const ATTR_ALTERNATE_DOMAIN: AttrType = AttrType(0x8003);
209
210/// RawAttribute is a Type-Length-Value (TLV) object that
211/// can be added to a STUN message. Attributes are divided into two
212/// types: comprehension-required and comprehension-optional.  STUN
213/// agents can safely ignore comprehension-optional attributes they
214/// don't understand, but cannot successfully process a message if it
215/// contains comprehension-required attributes that are not
216/// understood.
217#[derive(Default, Debug, Clone, PartialEq, Eq)]
218pub struct RawAttribute {
219    /// Which attribute this is.
220    pub typ: AttrType,
221    /// The value length in bytes; recomputed when encoding, so it is ignored there.
222    pub length: u16, // ignored while encoding
223    /// The attribute's raw value.
224    pub value: Vec<u8>,
225}
226
227impl fmt::Display for RawAttribute {
228    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229        write!(f, "{}: {:?}", self.typ, self.value)
230    }
231}
232
233impl Setter for RawAttribute {
234    /// add_to implements Setter, adding attribute as a.Type with a.Value and ignoring
235    /// the Length field.
236    fn add_to(&self, m: &mut Message) -> Result<()> {
237        m.add(self.typ, &self.value);
238        Ok(())
239    }
240}
241
242pub(crate) const PADDING: usize = 4;
243
244/// STUN aligns attributes on 32-bit boundaries, attributes whose content
245/// is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of
246/// padding so that its value contains a multiple of 4 bytes.  The
247/// padding bits are ignored, and may be any value.
248///
249/// https://tools.ietf.org/html/rfc5389#section-15
250pub(crate) fn nearest_padded_value_length(l: usize) -> usize {
251    let mut n = PADDING * (l / PADDING);
252    if n < l {
253        n += PADDING
254    }
255    n
256}
257
258/// This method converts uint16 vlue to AttrType. If it finds an old attribute
259/// type value, it also translates it to the new value to enable backward
260/// compatibility.
261pub(crate) fn compat_attr_type(val: u16) -> AttrType {
262    if val == 0x8020 {
263        // draft-ietf-behave-rfc3489bis-02, MS-TURN
264        ATTR_XORMAPPED_ADDRESS // new: 0x0020 (from draft-ietf-behave-rfc3489bis-03 on)
265    } else {
266        AttrType(val)
267    }
268}