stun_types/
lib.rs

1// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![deny(missing_debug_implementations)]
10#![deny(missing_docs)]
11#![cfg_attr(docsrs, feature(doc_cfg))]
12
13//! # stun-types
14//!
15//! An implementation of parsing and writing STUN messages and attributes based on trait
16//! implementations.
17//!
18//! This is based on the following standards:
19//! - [RFC8489] - 'Session Traversal Utilities for NAT (STUN)'
20//! - [RFC5389] - 'Session Traversal Utilities for NAT (STUN)'
21//! - [RFC3489] - 'STUN - Simple Traversal of User Datagram Protocol (UDP)
22//!   Through Network Address Translators (NATs)'
23//!
24//! ## [Message](crate::message::Message)
25//!
26//! ### Message Parsing
27//!
28//! Message parsing is zerocopy by default through the [`RawAttribute`](crate::attribute::RawAttribute)
29//! struct. Converting to a concrete attribute implementation (such as
30//! [`Software`](crate::attribute::Software)) may incur a copy depending on the attribute
31//! implementation.
32//!
33//! ### Message writing
34//!
35//! The destination for a written Message is completely customizable through the
36//! [`MessageWrite`](crate::message::MessageWrite) trait. It is therefore possible to write directly
37//! into network provided buffers for increased performance and throughput.
38//!
39//! [`MessageWriteVec`](crate::message::MessageWriteVec) provides a simple implementation of
40//! message writing that will write into a newly allocated `Vec<u8>`.
41//!
42//! ## [Attribute](crate::attribute::Attribute)
43//!
44//! An [`Attribute`](crate::attribute::Attribute) implementation can be implemented entirely
45//! outside of this crate and used exactly the same as an Attribute implemented within this crate.
46//! Look at [`attribute`] module level documentation for an example of defining your own
47//! [`Attribute`](crate::attribute::Attribute).
48//!
49//! For TURN-related attributes, have a look at the [turn-types] crate which uses this crate to
50//! implement STUN attributes for TURN.
51//!
52//! [RFC8489]: https://tools.ietf.org/html/rfc8489
53//! [RFC5389]: https://tools.ietf.org/html/rfc5389
54//! [RFC3489]: https://tools.ietf.org/html/rfc3489
55//! [turn-types]: https://docs.rs/turn-types/latest/turn_types/
56//!
57//! ## Examples
58//!
59//! See the [`message`] and [`attribute`] module documentation for examples of use.
60
61#![no_std]
62
63use core::{
64    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
65    str::FromStr,
66};
67
68use crate::message::StunParseError;
69
70pub mod attribute;
71pub mod data;
72pub mod message;
73
74extern crate alloc;
75
76#[cfg(any(feature = "std", test))]
77extern crate std;
78
79/// The transport family
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[repr(u32)]
82pub enum TransportType {
83    /// The UDP transport
84    Udp,
85    /// The TCP transport
86    Tcp,
87}
88
89/// Errors when parsing a [`TransportType`]
90#[derive(Debug, thiserror::Error)]
91pub enum ParseTransportTypeError {
92    /// An unknown transport value was provided
93    #[error("Unknown transport value was provided")]
94    UnknownTransport,
95}
96
97impl FromStr for TransportType {
98    type Err = ParseTransportTypeError;
99
100    fn from_str(s: &str) -> Result<Self, Self::Err> {
101        if s.eq_ignore_ascii_case("UDP") {
102            Ok(TransportType::Udp)
103        } else if s.eq_ignore_ascii_case("TCP") {
104            Ok(TransportType::Tcp)
105        } else {
106            Err(ParseTransportTypeError::UnknownTransport)
107        }
108    }
109}
110
111impl core::fmt::Display for TransportType {
112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113        match &self {
114            TransportType::Udp => f.pad("UDP"),
115            TransportType::Tcp => f.pad("TCP"),
116        }
117    }
118}
119
120/// The address family of a socket
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum AddressFamily {
123    /// IP version 4 address.
124    IPV4,
125    /// IP version 6 address.
126    IPV6,
127}
128
129impl AddressFamily {
130    pub(crate) fn to_byte(self) -> u8 {
131        match self {
132            AddressFamily::IPV4 => 0x1,
133            AddressFamily::IPV6 => 0x2,
134        }
135    }
136
137    pub(crate) fn from_byte(byte: u8) -> Result<AddressFamily, StunParseError> {
138        match byte {
139            0x1 => Ok(AddressFamily::IPV4),
140            0x2 => Ok(AddressFamily::IPV6),
141            _ => Err(StunParseError::InvalidAttributeData),
142        }
143    }
144}
145
146impl From<&SocketAddr> for AddressFamily {
147    fn from(value: &SocketAddr) -> Self {
148        match value {
149            SocketAddr::V4(_) => Self::IPV4,
150            SocketAddr::V6(_) => Self::IPV6,
151        }
152    }
153}
154
155impl From<&SocketAddrV4> for AddressFamily {
156    fn from(_value: &SocketAddrV4) -> Self {
157        Self::IPV4
158    }
159}
160
161impl From<&SocketAddrV6> for AddressFamily {
162    fn from(_value: &SocketAddrV6) -> Self {
163        Self::IPV6
164    }
165}
166
167impl From<&IpAddr> for AddressFamily {
168    fn from(value: &IpAddr) -> Self {
169        match value {
170            IpAddr::V4(_) => Self::IPV4,
171            IpAddr::V6(_) => Self::IPV6,
172        }
173    }
174}
175
176impl From<&Ipv4Addr> for AddressFamily {
177    fn from(_value: &Ipv4Addr) -> Self {
178        Self::IPV4
179    }
180}
181
182impl From<&Ipv6Addr> for AddressFamily {
183    fn from(_value: &Ipv6Addr) -> Self {
184        Self::IPV6
185    }
186}
187
188impl core::fmt::Display for AddressFamily {
189    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190        match self {
191            AddressFamily::IPV4 => write!(f, "IPV4"),
192            AddressFamily::IPV6 => write!(f, "IPV6"),
193        }
194    }
195}
196
197/// Prelude module for traits
198pub mod prelude {
199    pub use crate::attribute::{
200        Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeWrite,
201        AttributeWriteExt,
202    };
203    pub use crate::message::{MessageWrite, MessageWriteExt};
204}
205
206#[cfg(test)]
207pub(crate) mod tests {
208    use alloc::borrow::ToOwned;
209    use alloc::format;
210    use alloc::string::{String, ToString};
211    use tracing::subscriber::DefaultGuard;
212    use tracing_subscriber::layer::SubscriberExt;
213    use tracing_subscriber::Layer;
214
215    use super::*;
216
217    pub fn test_init_log() -> DefaultGuard {
218        let level_filter = std::env::var("STUN_LOG")
219            .or(std::env::var("RUST_LOG"))
220            .ok()
221            .and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
222            .unwrap_or(
223                tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
224            );
225        let registry = tracing_subscriber::registry().with(
226            tracing_subscriber::fmt::layer()
227                .with_file(true)
228                .with_line_number(true)
229                .with_level(true)
230                .with_target(false)
231                .with_test_writer()
232                .with_filter(level_filter),
233        );
234        tracing::subscriber::set_default(registry)
235    }
236
237    #[test]
238    fn parse_transport_type() {
239        assert!(matches!("UDP".parse(), Ok(TransportType::Udp)));
240        assert!(matches!("TCP".parse(), Ok(TransportType::Tcp)));
241        assert!(matches!("udp".parse(), Ok(TransportType::Udp)));
242        assert!(matches!("tcp".parse(), Ok(TransportType::Tcp)));
243        assert!(matches!(
244            TransportType::from_str("Random"),
245            Err(ParseTransportTypeError::UnknownTransport)
246        ));
247    }
248
249    #[test]
250    fn transport_type_str() {
251        assert_eq!(TransportType::Udp.to_string(), String::from("UDP"));
252        assert_eq!(TransportType::Tcp.to_string(), String::from("TCP"));
253    }
254
255    #[test]
256    fn address_family() {
257        assert_eq!(AddressFamily::IPV4.to_byte(), 1);
258        assert_eq!(AddressFamily::from_byte(1).unwrap(), AddressFamily::IPV4);
259        assert_eq!(format!("{}", AddressFamily::IPV4), "IPV4".to_owned());
260        assert_eq!(AddressFamily::IPV6.to_byte(), 2);
261        assert_eq!(AddressFamily::from_byte(2).unwrap(), AddressFamily::IPV6);
262        assert_eq!(format!("{}", AddressFamily::IPV6), "IPV6".to_owned());
263        assert!(matches!(
264            AddressFamily::from_byte(3),
265            Err(StunParseError::InvalidAttributeData)
266        ));
267        let ipv4_addr: SocketAddr = "127.0.0.1:1".parse().unwrap();
268        assert_eq!(AddressFamily::from(&ipv4_addr), AddressFamily::IPV4);
269        assert_eq!(AddressFamily::from(&ipv4_addr.ip()), AddressFamily::IPV4);
270        let SocketAddr::V4(ipv4_addr) = ipv4_addr else {
271            unreachable!();
272        };
273        assert_eq!(AddressFamily::from(&ipv4_addr), AddressFamily::IPV4);
274        assert_eq!(AddressFamily::from(ipv4_addr.ip()), AddressFamily::IPV4);
275        let ipv6_addr: SocketAddr = "[::1]:1".parse().unwrap();
276        assert_eq!(AddressFamily::from(&ipv6_addr), AddressFamily::IPV6);
277        assert_eq!(AddressFamily::from(&ipv6_addr.ip()), AddressFamily::IPV6);
278        let SocketAddr::V6(ipv6_addr) = ipv6_addr else {
279            unreachable!();
280        };
281        assert_eq!(AddressFamily::from(&ipv6_addr), AddressFamily::IPV6);
282        assert_eq!(AddressFamily::from(ipv6_addr.ip()), AddressFamily::IPV6);
283    }
284}