stun_rs/attributes/
unknown.rs

1use crate::attributes::{AsVerifiable, EncodeAttributeValue, Verifiable};
2use crate::context::AttributeEncoderContext;
3use crate::error::{StunError, StunErrorType};
4use crate::{AttributeType, StunAttribute};
5use std::sync::Arc;
6
7/// Unknown attribute.
8/// This attribute is added to a decoded message when there is not a known handler
9/// to decode an attribute. To minimize impact on memory, the data associated to any
10/// unknown attribute is discarded unless the `experimental` flag is enabled and
11/// the decoder context had been configured to keep the data associated to unknown
12/// attributes.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct Unknown {
15    attr_type: AttributeType,
16    attr_data: Option<Arc<Vec<u8>>>,
17}
18
19impl Unknown {
20    pub(crate) fn new<'a, T>(attr_type: AttributeType, data: T) -> Self
21    where
22        T: Into<Option<&'a [u8]>>,
23    {
24        Self {
25            attr_type,
26            attr_data: data.into().map(Vec::from).map(Arc::new),
27        }
28    }
29
30    /// Returns the STUN attribute type associated to this unknown attribute.
31    pub fn attribute_type(&self) -> AttributeType {
32        self.attr_type
33    }
34
35    /// Returns the raw value associated to this unknown attribute. By default,
36    /// no data will be returned to save the amount of memory required to
37    /// process unknown attributes. If access to such data is required, it must
38    /// be specified by calling the `with_unknown_data` on the
39    /// [`DecoderContextBuilder`](crate::DecoderContextBuilder). This option is only
40    /// enabled through the `experimental` flag.
41    pub fn attribute_data(&self) -> Option<&[u8]> {
42        self.attr_data.as_ref().map(|v| v.as_ref().as_slice())
43    }
44}
45
46impl AsVerifiable for Unknown {
47    fn as_verifiable_ref(&self) -> Option<&dyn Verifiable> {
48        None
49    }
50}
51
52impl EncodeAttributeValue for Unknown {
53    fn encode(&self, _ctx: AttributeEncoderContext) -> Result<usize, StunError> {
54        // Unknown attributes can not be encoded
55        Err(StunError::new(
56            StunErrorType::InvalidParam,
57            format!(
58                "Unknown attribute [{:#02x}] can not be encoded",
59                self.attr_type.as_u16()
60            ),
61        ))
62    }
63
64    fn post_encode(&self, mut _ctx: AttributeEncoderContext) -> Result<(), StunError> {
65        // Unknown attributes can not be encoded
66        Err(StunError::new(
67            StunErrorType::InvalidParam,
68            format!(
69                "Unknown attribute [{:#02x}] can not be decoded",
70                self.attr_type.as_u16()
71            ),
72        ))
73    }
74}
75
76impl From<Unknown> for StunAttribute {
77    fn from(value: Unknown) -> Self {
78        crate::attributes::StunAttribute::Unknown(value)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use crate::{DecoderContextBuilder, MessageDecoderBuilder};
86
87    #[test]
88    fn decode_unknown_attribute() {
89        let test_buffer = [
90            0x01, 0x01, 0x00, 0x08, // Response type and message length
91            0x21, 0x12, 0xa4, 0x42, // Magic cookie
92            0xb7, 0xe7, 0xa7, 0x01, // }
93            0xbc, 0x34, 0xd6, 0x86, // }  Transaction ID
94            0xfa, 0x87, 0xdf, 0xae, // }
95            0xff, 0xff, 0x00, 0x02, // Unknown attribute (2 bytes of padding)
96            0x01, 0x02, 0xff, 0xff,
97        ];
98        let ctx = DecoderContextBuilder::default().build();
99        let decoder = MessageDecoderBuilder::default().with_context(ctx).build();
100
101        let (msg, size) = decoder
102            .decode(&test_buffer)
103            .expect("Can not decode STUN message");
104        assert_eq!(size, 28);
105
106        let attributes = msg.attributes();
107        assert_eq!(attributes.len(), 1);
108
109        let attr = attributes
110            .first()
111            .expect("Can not get first attribute")
112            .as_unknown()
113            .expect("Not unknown attribute");
114        assert_eq!(attr.attribute_type(), AttributeType::from(0xffff));
115        assert_eq!(attr.attribute_data(), None);
116
117        // Keep attribute data for unknown attributes
118        let ctx = DecoderContextBuilder::default().with_unknown_data().build();
119        let decoder = MessageDecoderBuilder::default().with_context(ctx).build();
120        let (msg, size) = decoder
121            .decode(&test_buffer)
122            .expect("Can not decode STUN message");
123        assert_eq!(size, 28);
124
125        let attributes = msg.attributes();
126        assert_eq!(attributes.len(), 1);
127
128        let attr = attributes
129            .first()
130            .expect("Can not get first attribute")
131            .as_unknown()
132            .expect("Not unknown attribute");
133        assert_eq!(attr.attribute_type(), AttributeType::from(0xffff));
134        assert_eq!(attr.attribute_data(), Some([0x01, 0x02].as_ref()));
135
136        // Unknown attributes are not verifiable
137        assert!(attr.as_verifiable_ref().is_none());
138    }
139
140    #[test]
141    fn encode_unknown_attribute() {
142        let dummy_msg: [u8; 0] = [];
143        let mut buffer: [u8; 6] = [0x00; 6];
144        let attr = Unknown::new(
145            AttributeType::from(0xffff),
146            Some([0x01, 0x02, 0x03, 0x04].as_ref()),
147        );
148
149        // Unknown attributes can not be encoded.
150        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
151        let result = attr.encode(ctx);
152        assert_eq!(
153            result.expect_err("Error expected"),
154            StunErrorType::InvalidParam
155        );
156
157        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
158        let result = attr.post_encode(ctx);
159        assert_eq!(
160            result.expect_err("Error expected"),
161            StunErrorType::InvalidParam
162        );
163    }
164
165    #[test]
166    fn unknown_stunt_attribute() {
167        let attr = StunAttribute::Unknown(Unknown::new(AttributeType::from(0x1234), None));
168        assert!(attr.is_unknown());
169        assert!(attr.as_unknown().is_ok());
170        assert!(attr.as_error_code().is_err());
171
172        let dbg_fmt = format!("{:?}", attr);
173        assert_eq!(
174            "Unknown(Unknown { attr_type: AttributeType (0x1234), attr_data: None })",
175            dbg_fmt
176        );
177    }
178}