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