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