1 #[cfg(test)] 2 mod nat_test; 3 4 use crate::error::*; 5 use crate::vnet::chunk::Chunk; 6 use crate::vnet::net::UDP_STR; 7 8 use std::collections::{HashMap, HashSet}; 9 use std::net::IpAddr; 10 use std::ops::Add; 11 use std::sync::atomic::{AtomicU16, Ordering}; 12 use std::sync::Arc; 13 use std::time::SystemTime; 14 use tokio::sync::Mutex; 15 use tokio::time::Duration; 16 17 const DEFAULT_NAT_MAPPING_LIFE_TIME: Duration = Duration::from_secs(30); 18 19 // EndpointDependencyType defines a type of behavioral dependendency on the 20 // remote endpoint's IP address or port number. This is used for the two 21 // kinds of behaviors: 22 // - Port Mapping behavior 23 // - Filtering behavior 24 // See: https://tools.ietf.org/html/rfc4787 25 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] 26 pub enum EndpointDependencyType { 27 // EndpointIndependent means the behavior is independent of the endpoint's address or port 28 #[default] 29 EndpointIndependent, 30 // EndpointAddrDependent means the behavior is dependent on the endpoint's address 31 EndpointAddrDependent, 32 // EndpointAddrPortDependent means the behavior is dependent on the endpoint's address and port 33 EndpointAddrPortDependent, 34 } 35 36 // NATMode defines basic behavior of the NAT 37 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] 38 pub enum NatMode { 39 // NATModeNormal means the NAT behaves as a standard NAPT (RFC 2663). 40 #[default] 41 Normal, 42 // NATModeNAT1To1 exhibits 1:1 DNAT where the external IP address is statically mapped to 43 // a specific local IP address with port number is preserved always between them. 44 // When this mode is selected, mapping_behavior, filtering_behavior, port_preservation and 45 // mapping_life_time of NATType are ignored. 46 Nat1To1, 47 } 48 49 // NATType has a set of parameters that define the behavior of NAT. 50 #[derive(Default, Debug, Copy, Clone)] 51 pub struct NatType { 52 pub mode: NatMode, 53 pub mapping_behavior: EndpointDependencyType, 54 pub filtering_behavior: EndpointDependencyType, 55 pub hair_pining: bool, // Not implemented yet 56 pub port_preservation: bool, // Not implemented yet 57 pub mapping_life_time: Duration, 58 } 59 60 #[derive(Default, Debug, Clone)] 61 pub(crate) struct NatConfig { 62 pub(crate) name: String, 63 pub(crate) nat_type: NatType, 64 pub(crate) mapped_ips: Vec<IpAddr>, // mapped IPv4 65 pub(crate) local_ips: Vec<IpAddr>, // local IPv4, required only when the mode is NATModeNAT1To1 66 } 67 68 #[derive(Debug, Clone)] 69 pub(crate) struct Mapping { 70 proto: String, // "udp" or "tcp" 71 local: String, // "<local-ip>:<local-port>" 72 mapped: String, // "<mapped-ip>:<mapped-port>" 73 bound: String, // key: "[<remote-ip>[:<remote-port>]]" 74 filters: Arc<Mutex<HashSet<String>>>, // key: "[<remote-ip>[:<remote-port>]]" 75 expires: Arc<Mutex<SystemTime>>, // time to expire 76 } 77 78 impl Default for Mapping { default() -> Self79 fn default() -> Self { 80 Mapping { 81 proto: String::new(), // "udp" or "tcp" 82 local: String::new(), // "<local-ip>:<local-port>" 83 mapped: String::new(), // "<mapped-ip>:<mapped-port>" 84 bound: String::new(), // key: "[<remote-ip>[:<remote-port>]]" 85 filters: Arc::new(Mutex::new(HashSet::new())), // key: "[<remote-ip>[:<remote-port>]]" 86 expires: Arc::new(Mutex::new(SystemTime::now())), // time to expire 87 } 88 } 89 } 90 91 #[derive(Default, Debug, Clone)] 92 pub(crate) struct NetworkAddressTranslator { 93 pub(crate) name: String, 94 pub(crate) nat_type: NatType, 95 pub(crate) mapped_ips: Vec<IpAddr>, // mapped IPv4 96 pub(crate) local_ips: Vec<IpAddr>, // local IPv4, required only when the mode is NATModeNAT1To1 97 pub(crate) outbound_map: Arc<Mutex<HashMap<String, Arc<Mapping>>>>, // key: "<proto>:<local-ip>:<local-port>[:remote-ip[:remote-port]] 98 pub(crate) inbound_map: Arc<Mutex<HashMap<String, Arc<Mapping>>>>, // key: "<proto>:<mapped-ip>:<mapped-port>" 99 pub(crate) udp_port_counter: Arc<AtomicU16>, 100 } 101 102 impl NetworkAddressTranslator { new(config: NatConfig) -> Result<Self>103 pub(crate) fn new(config: NatConfig) -> Result<Self> { 104 let mut nat_type = config.nat_type; 105 106 if nat_type.mode == NatMode::Nat1To1 { 107 // 1:1 NAT behavior 108 nat_type.mapping_behavior = EndpointDependencyType::EndpointIndependent; 109 nat_type.filtering_behavior = EndpointDependencyType::EndpointIndependent; 110 nat_type.port_preservation = true; 111 nat_type.mapping_life_time = Duration::from_secs(0); 112 113 if config.mapped_ips.is_empty() { 114 return Err(Error::ErrNatRequriesMapping); 115 } 116 if config.mapped_ips.len() != config.local_ips.len() { 117 return Err(Error::ErrMismatchLengthIp); 118 } 119 } else { 120 // Normal (NAPT) behavior 121 nat_type.mode = NatMode::Normal; 122 if nat_type.mapping_life_time == Duration::from_secs(0) { 123 nat_type.mapping_life_time = DEFAULT_NAT_MAPPING_LIFE_TIME; 124 } 125 } 126 127 Ok(NetworkAddressTranslator { 128 name: config.name, 129 nat_type, 130 mapped_ips: config.mapped_ips, 131 local_ips: config.local_ips, 132 outbound_map: Arc::new(Mutex::new(HashMap::new())), 133 inbound_map: Arc::new(Mutex::new(HashMap::new())), 134 udp_port_counter: Arc::new(AtomicU16::new(0)), 135 }) 136 } 137 get_paired_mapped_ip(&self, loc_ip: &IpAddr) -> Option<&IpAddr>138 pub(crate) fn get_paired_mapped_ip(&self, loc_ip: &IpAddr) -> Option<&IpAddr> { 139 for (i, ip) in self.local_ips.iter().enumerate() { 140 if ip == loc_ip { 141 return self.mapped_ips.get(i); 142 } 143 } 144 None 145 } 146 get_paired_local_ip(&self, mapped_ip: &IpAddr) -> Option<&IpAddr>147 pub(crate) fn get_paired_local_ip(&self, mapped_ip: &IpAddr) -> Option<&IpAddr> { 148 for (i, ip) in self.mapped_ips.iter().enumerate() { 149 if ip == mapped_ip { 150 return self.local_ips.get(i); 151 } 152 } 153 None 154 } 155 translate_outbound( &self, from: &(dyn Chunk + Send + Sync), ) -> Result<Option<Box<dyn Chunk + Send + Sync>>>156 pub(crate) async fn translate_outbound( 157 &self, 158 from: &(dyn Chunk + Send + Sync), 159 ) -> Result<Option<Box<dyn Chunk + Send + Sync>>> { 160 let mut to = from.clone_to(); 161 162 if from.network() == UDP_STR { 163 if self.nat_type.mode == NatMode::Nat1To1 { 164 // 1:1 NAT behavior 165 let src_addr = from.source_addr(); 166 if let Some(src_ip) = self.get_paired_mapped_ip(&src_addr.ip()) { 167 to.set_source_addr(&format!("{}:{}", src_ip, src_addr.port()))?; 168 } else { 169 log::debug!( 170 "[{}] drop outbound chunk {} with not route", 171 self.name, 172 from 173 ); 174 return Ok(None); // silently discard 175 } 176 } else { 177 // Normal (NAPT) behavior 178 let bound = match self.nat_type.mapping_behavior { 179 EndpointDependencyType::EndpointIndependent => "".to_owned(), 180 EndpointDependencyType::EndpointAddrDependent => { 181 from.get_destination_ip().to_string() 182 } 183 EndpointDependencyType::EndpointAddrPortDependent => { 184 from.destination_addr().to_string() 185 } 186 }; 187 188 let filter_key = match self.nat_type.filtering_behavior { 189 EndpointDependencyType::EndpointIndependent => "".to_owned(), 190 EndpointDependencyType::EndpointAddrDependent => { 191 from.get_destination_ip().to_string() 192 } 193 EndpointDependencyType::EndpointAddrPortDependent => { 194 from.destination_addr().to_string() 195 } 196 }; 197 198 let o_key = format!("udp:{}:{}", from.source_addr(), bound); 199 let name = self.name.clone(); 200 201 let m_mapped = if let Some(m) = self.find_outbound_mapping(&o_key).await { 202 let mut filters = m.filters.lock().await; 203 if !filters.contains(&filter_key) { 204 log::debug!( 205 "[{}] permit access from {} to {}", 206 name, 207 filter_key, 208 m.mapped 209 ); 210 filters.insert(filter_key); 211 } 212 m.mapped.clone() 213 } else { 214 // Create a new Mapping 215 let udp_port_counter = self.udp_port_counter.load(Ordering::SeqCst); 216 let mapped_port = 0xC000 + udp_port_counter; 217 if udp_port_counter == 0xFFFF - 0xC000 { 218 self.udp_port_counter.store(0, Ordering::SeqCst); 219 } else { 220 self.udp_port_counter.fetch_add(1, Ordering::SeqCst); 221 } 222 223 let m = if let Some(mapped_ips_first) = self.mapped_ips.first() { 224 Mapping { 225 proto: "udp".to_owned(), 226 local: from.source_addr().to_string(), 227 bound, 228 mapped: format!("{mapped_ips_first}:{mapped_port}"), 229 filters: Arc::new(Mutex::new(HashSet::new())), 230 expires: Arc::new(Mutex::new( 231 SystemTime::now().add(self.nat_type.mapping_life_time), 232 )), 233 } 234 } else { 235 return Err(Error::ErrNatRequriesMapping); 236 }; 237 238 { 239 let mut outbound_map = self.outbound_map.lock().await; 240 outbound_map.insert(o_key.clone(), Arc::new(m.clone())); 241 } 242 243 let i_key = format!("udp:{}", m.mapped); 244 245 log::debug!( 246 "[{}] created a new NAT binding oKey={} i_key={}", 247 self.name, 248 o_key, 249 i_key 250 ); 251 log::debug!( 252 "[{}] permit access from {} to {}", 253 self.name, 254 filter_key, 255 m.mapped 256 ); 257 258 { 259 let mut filters = m.filters.lock().await; 260 filters.insert(filter_key); 261 } 262 263 let m_mapped = m.mapped.clone(); 264 { 265 let mut inbound_map = self.inbound_map.lock().await; 266 inbound_map.insert(i_key, Arc::new(m)); 267 } 268 m_mapped 269 }; 270 271 to.set_source_addr(&m_mapped)?; 272 } 273 274 log::debug!( 275 "[{}] translate outbound chunk from {} to {}", 276 self.name, 277 from, 278 to 279 ); 280 281 return Ok(Some(to)); 282 } 283 284 Err(Error::ErrNonUdpTranslationNotSupported) 285 } 286 translate_inbound( &self, from: &(dyn Chunk + Send + Sync), ) -> Result<Option<Box<dyn Chunk + Send + Sync>>>287 pub(crate) async fn translate_inbound( 288 &self, 289 from: &(dyn Chunk + Send + Sync), 290 ) -> Result<Option<Box<dyn Chunk + Send + Sync>>> { 291 let mut to = from.clone_to(); 292 293 if from.network() == UDP_STR { 294 if self.nat_type.mode == NatMode::Nat1To1 { 295 // 1:1 NAT behavior 296 let dst_addr = from.destination_addr(); 297 if let Some(dst_ip) = self.get_paired_local_ip(&dst_addr.ip()) { 298 let dst_port = from.destination_addr().port(); 299 to.set_destination_addr(&format!("{dst_ip}:{dst_port}"))?; 300 } else { 301 return Err(Error::Other(format!( 302 "drop {} as {:?}", 303 from, 304 Error::ErrNoAssociatedLocalAddress 305 ))); 306 } 307 } else { 308 // Normal (NAPT) behavior 309 let filter_key = match self.nat_type.filtering_behavior { 310 EndpointDependencyType::EndpointIndependent => "".to_owned(), 311 EndpointDependencyType::EndpointAddrDependent => { 312 from.get_source_ip().to_string() 313 } 314 EndpointDependencyType::EndpointAddrPortDependent => { 315 from.source_addr().to_string() 316 } 317 }; 318 319 let i_key = format!("udp:{}", from.destination_addr()); 320 if let Some(m) = self.find_inbound_mapping(&i_key).await { 321 { 322 let filters = m.filters.lock().await; 323 if !filters.contains(&filter_key) { 324 return Err(Error::Other(format!( 325 "drop {} as the remote {} {:?}", 326 from, 327 filter_key, 328 Error::ErrHasNoPermission 329 ))); 330 } 331 } 332 333 // See RFC 4847 Section 4.3. Mapping Refresh 334 // a) Inbound refresh may be useful for applications with no outgoing 335 // UDP traffic. However, allowing inbound refresh may allow an 336 // external attacker or misbehaving application to keep a Mapping 337 // alive indefinitely. This may be a security risk. Also, if the 338 // process is repeated with different ports, over time, it could 339 // use up all the ports on the NAT. 340 341 to.set_destination_addr(&m.local)?; 342 } else { 343 return Err(Error::Other(format!( 344 "drop {} as {:?}", 345 from, 346 Error::ErrNoNatBindingFound 347 ))); 348 } 349 } 350 351 log::debug!( 352 "[{}] translate inbound chunk from {} to {}", 353 self.name, 354 from, 355 to 356 ); 357 358 return Ok(Some(to)); 359 } 360 361 Err(Error::ErrNonUdpTranslationNotSupported) 362 } 363 364 // caller must hold the mutex find_outbound_mapping(&self, o_key: &str) -> Option<Arc<Mapping>>365 pub(crate) async fn find_outbound_mapping(&self, o_key: &str) -> Option<Arc<Mapping>> { 366 let mapping_life_time = self.nat_type.mapping_life_time; 367 let mut expired = false; 368 let (in_key, out_key) = { 369 let outbound_map = self.outbound_map.lock().await; 370 if let Some(m) = outbound_map.get(o_key) { 371 let now = SystemTime::now(); 372 373 { 374 let mut expires = m.expires.lock().await; 375 // check if this Mapping is expired 376 if now.duration_since(*expires).is_ok() { 377 expired = true; 378 } else { 379 *expires = now.add(mapping_life_time); 380 } 381 } 382 ( 383 NetworkAddressTranslator::get_inbound_map_key(m), 384 NetworkAddressTranslator::get_outbound_map_key(m), 385 ) 386 } else { 387 (String::new(), String::new()) 388 } 389 }; 390 391 if expired { 392 { 393 let mut inbound_map = self.inbound_map.lock().await; 394 inbound_map.remove(&in_key); 395 } 396 { 397 let mut outbound_map = self.outbound_map.lock().await; 398 outbound_map.remove(&out_key); 399 } 400 } 401 402 let outbound_map = self.outbound_map.lock().await; 403 outbound_map.get(o_key).map(Arc::clone) 404 } 405 406 // caller must hold the mutex find_inbound_mapping(&self, i_key: &str) -> Option<Arc<Mapping>>407 pub(crate) async fn find_inbound_mapping(&self, i_key: &str) -> Option<Arc<Mapping>> { 408 let mut expired = false; 409 let (in_key, out_key) = { 410 let inbound_map = self.inbound_map.lock().await; 411 if let Some(m) = inbound_map.get(i_key) { 412 let now = SystemTime::now(); 413 414 { 415 let expires = m.expires.lock().await; 416 // check if this Mapping is expired 417 if now.duration_since(*expires).is_ok() { 418 expired = true; 419 } 420 } 421 ( 422 NetworkAddressTranslator::get_inbound_map_key(m), 423 NetworkAddressTranslator::get_outbound_map_key(m), 424 ) 425 } else { 426 (String::new(), String::new()) 427 } 428 }; 429 430 if expired { 431 { 432 let mut inbound_map = self.inbound_map.lock().await; 433 inbound_map.remove(&in_key); 434 } 435 { 436 let mut outbound_map = self.outbound_map.lock().await; 437 outbound_map.remove(&out_key); 438 } 439 } 440 441 let inbound_map = self.inbound_map.lock().await; 442 inbound_map.get(i_key).map(Arc::clone) 443 } 444 445 // caller must hold the mutex get_outbound_map_key(m: &Mapping) -> String446 fn get_outbound_map_key(m: &Mapping) -> String { 447 format!("{}:{}:{}", m.proto, m.local, m.bound) 448 } 449 get_inbound_map_key(m: &Mapping) -> String450 fn get_inbound_map_key(m: &Mapping) -> String { 451 format!("{}:{}", m.proto, m.mapped) 452 } 453 inbound_map_len(&self) -> usize454 async fn inbound_map_len(&self) -> usize { 455 let inbound_map = self.inbound_map.lock().await; 456 inbound_map.len() 457 } 458 outbound_map_len(&self) -> usize459 async fn outbound_map_len(&self) -> usize { 460 let outbound_map = self.outbound_map.lock().await; 461 outbound_map.len() 462 } 463 } 464