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. 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 { 34 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). 78 pub fn required(&self) -> bool { 79 self.0 <= 0x7FFF 80 } 81 82 /// optional returns true if type is from comprehension-optional range (0x8000-0xFFFF). 83 pub fn optional(&self) -> bool { 84 self.0 >= 0x8000 85 } 86 87 /// value returns uint16 representation of attribute type. 88 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 { 169 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. 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 191 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) 202 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