Skip to main content

rust_p2p_core/nat/
mod.rs

1//! NAT (Network Address Translation) detection and information.
2//!
3//! This module provides types and functions for detecting and working with NAT.
4//! It helps identify the NAT type (Cone vs Symmetric) and tracks public/private
5//! address mappings.
6//!
7//! # Examples
8//!
9//! ```rust,no_run
10//! use rust_p2p_core::nat::{NatType, NatInfo};
11//!
12//! let nat_info = NatInfo {
13//!     nat_type: NatType::Cone,
14//!     public_ips: vec![],
15//!     // ... other fields
16//! #   public_udp_ports: vec![],
17//! #   mapping_tcp_addr: vec![],
18//! #   mapping_udp_addr: vec![],
19//! #   public_port_range: 0,
20//! #   local_ipv4: std::net::Ipv4Addr::UNSPECIFIED,
21//! #   local_ipv4s: vec![],
22//! #   ipv6: None,
23//! #   local_udp_ports: vec![],
24//! #   local_tcp_port: 0,
25//! #   public_tcp_port: 0,
26//! };
27//!
28//! if nat_info.nat_type.is_cone() {
29//!     println!("Cone NAT - easier to traverse");
30//! }
31//! ```
32
33use crate::extend::addr::is_ipv6_global;
34use serde::{Deserialize, Serialize};
35use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
36
37/// Type of NAT (Network Address Translation).
38///
39/// # Variants
40///
41/// - `Cone` - Port mapping is consistent, easier for hole punching
42/// - `Symmetric` - Port mapping changes per destination, harder to traverse
43///
44/// # Examples
45///
46/// ```rust
47/// use rust_p2p_core::nat::NatType;
48///
49/// let nat = NatType::Cone;
50/// assert!(nat.is_cone());
51/// assert!(!nat.is_symmetric());
52/// ```
53#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)]
54pub enum NatType {
55    #[default]
56    Cone,
57    Symmetric,
58}
59
60impl NatType {
61    /// Returns true if this is a Cone NAT.
62    #[inline]
63    pub fn is_cone(&self) -> bool {
64        self == &NatType::Cone
65    }
66
67    /// Returns true if this is a Symmetric NAT.
68    #[inline]
69    pub fn is_symmetric(&self) -> bool {
70        self == &NatType::Symmetric
71    }
72}
73
74/// Comprehensive NAT information about the local network.
75///
76/// Contains details about NAT type, public/private addresses, and port mappings
77/// discovered through STUN and other NAT traversal techniques.
78///
79/// # Fields
80///
81/// - `nat_type` - The detected NAT type (Cone or Symmetric)
82/// - `public_ips` - List of public IPv4 addresses
83/// - `public_udp_ports` - Public ports mapped for UDP
84/// - `local_ipv4` - Primary local IPv4 address
85/// - `ipv6` - Public IPv6 address if available
86#[derive(Clone, Debug, Serialize, Deserialize)]
87pub struct NatInfo {
88    /// nat type of the network
89    pub nat_type: NatType,
90    /// the set of public Ipv4
91    pub public_ips: Vec<Ipv4Addr>,
92    /// the set of public ports mapped from the nat
93    pub public_udp_ports: Vec<u16>,
94    /// the set of mapped addresses where `TCP` serves on
95    pub mapping_tcp_addr: Vec<SocketAddr>,
96    /// the set of mapped addresses where `UDP` serves on
97    pub mapping_udp_addr: Vec<SocketAddr>,
98    /// The predicted range of public ports, it is used when the nat_type is symmetric
99    pub public_port_range: u16,
100    /// local IP address
101    pub local_ipv4: Ipv4Addr,
102    #[serde(default)]
103    pub local_ipv4s: Vec<Ipv4Addr>,
104    /// The public IPv6 address
105    pub ipv6: Option<Ipv6Addr>,
106    /// The local ports where the `UDP` services bind
107    pub local_udp_ports: Vec<u16>,
108    /// The local ports where the `TCP` services bind
109    pub local_tcp_port: u16,
110    /// The public port of `TCP` service, which works when there is either `nat1` or no `nat` exists
111    pub public_tcp_port: u16,
112}
113impl NatInfo {
114    pub(crate) fn flag(&self) -> Option<SocketAddr> {
115        let vec = self.public_ipv4_addr();
116        if let Some(v) = vec.first() {
117            return Some(*v);
118        }
119        let vec = self.public_ipv4_tcp();
120        if let Some(v) = vec.first() {
121            return Some(*v);
122        }
123        let vec = self.local_ipv4_addrs();
124        if let Some(v) = vec.first() {
125            return Some(*v);
126        }
127        let option = self.local_ipv4_tcp();
128        if option.is_some() {
129            return option;
130        }
131        None
132    }
133    pub fn ipv6_udp_addr(&self) -> Vec<SocketAddr> {
134        if let Some(ipv6) = self.ipv6 {
135            if is_ipv6_global(&ipv6) {
136                return self
137                    .local_udp_ports
138                    .iter()
139                    .map(|&port| SocketAddrV6::new(ipv6, port, 0, 0).into())
140                    .collect();
141            }
142        }
143        vec![]
144    }
145    pub fn ipv6_tcp_addr(&self) -> Option<SocketAddr> {
146        self.ipv6
147            .map(|ipv6| SocketAddrV6::new(ipv6, self.local_tcp_port, 0, 0).into())
148    }
149    pub fn public_ipv4_addr(&self) -> Vec<SocketAddr> {
150        if self.public_ips.is_empty() || self.public_udp_ports.is_empty() {
151            return vec![];
152        }
153        if self.public_ips.len() == 1 {
154            let ip = self.public_ips[0];
155            return self
156                .public_udp_ports
157                .iter()
158                .map(|&port| SocketAddrV4::new(ip, port).into())
159                .collect();
160        }
161        let port = self.public_udp_ports[0];
162        self.public_ips
163            .iter()
164            .map(|&ip| SocketAddrV4::new(ip, port).into())
165            .collect()
166    }
167    pub fn local_ipv4_addrs(&self) -> Vec<SocketAddr> {
168        if self.local_udp_ports.is_empty() {
169            return vec![];
170        }
171        if !self.local_ipv4s.is_empty() {
172            let mut rs = Vec::with_capacity(self.local_ipv4s.len() * self.local_udp_ports.len());
173            for ip in self.local_ipv4s.iter() {
174                if ip.is_unspecified() || ip.is_multicast() || ip.is_broadcast() {
175                    continue;
176                }
177                for port in self.local_udp_ports.iter() {
178                    rs.push(SocketAddrV4::new(*ip, *port).into());
179                }
180            }
181            return rs;
182        }
183        if self.local_ipv4.is_unspecified()
184            || self.local_ipv4.is_multicast()
185            || self.local_ipv4.is_broadcast()
186        {
187            return vec![];
188        }
189        self.local_udp_ports
190            .iter()
191            .map(|&port| SocketAddrV4::new(self.local_ipv4, port).into())
192            .collect()
193    }
194    pub fn local_ipv4_tcp(&self) -> Option<SocketAddr> {
195        if self.local_ipv4.is_unspecified()
196            || self.local_ipv4.is_multicast()
197            || self.local_ipv4.is_broadcast()
198            || self.local_tcp_port == 0
199        {
200            return None;
201        }
202        Some(SocketAddrV4::new(self.local_ipv4, self.local_tcp_port).into())
203    }
204    pub fn public_ipv4_tcp(&self) -> Vec<SocketAddr> {
205        if self.public_tcp_port == 0 {
206            return vec![];
207        }
208        self.public_ips
209            .iter()
210            .map(|&ip| SocketAddrV4::new(ip, self.public_tcp_port).into())
211            .collect()
212    }
213}