Skip to main content

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