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