webrtc_stun/
attributes.rs

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