added well known ports and max size

This commit is contained in:
Monica Moniot
2023-11-07 11:02:42 -05:00
parent 3cc57396ef
commit 3ff4f056fe
5 changed files with 105 additions and 50 deletions
Generated
+5 -5
View File
@@ -10,9 +10,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
@@ -21,13 +21,13 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "nat_emulation"
version = "0.0.2"
version = "1.0.0"
dependencies = [
"rand",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nat_emulation"
version = "0.0.2"
version = "1.0.0"
authors = ["Monica Moniot"]
edition = "2021"
+20 -19
View File
@@ -1,5 +1,6 @@
#[warn(missing_docs)]
mod nat_flags;
pub use nat_flags::{flags, predefines};
pub use nat_flags::{flags, port_ranges, predefines};
mod nat;
pub use nat::{DestType, Nat};
@@ -18,7 +19,7 @@ mod examples {
let client_port = 17;
let server_addr = 22222;
let server_port = 80;
let mut firewall = Nat::no_address_translation(STATEFUL_FIREWALL, client_addr, rng, timeout);
let mut firewall = Nat::no_address_translation(STATEFUL_FIREWALL, client_addr, rng, usize::MAX, timeout);
assert_eq!(firewall.assign_internal_address(), client_addr);
time += 100;
@@ -60,7 +61,7 @@ mod examples {
let server0_addr = 22222;
let server1_addr = 33333;
let server_port = 80;
let mut firewall = Nat::no_address_translation(RESTRICTED_FIREWALL, client_addr, rng, timeout);
let mut firewall = Nat::no_address_translation(RESTRICTED_FIREWALL, client_addr, rng, usize::MAX, timeout);
assert_eq!(firewall.assign_internal_address(), client_addr);
time += 100;
@@ -85,7 +86,7 @@ mod examples {
let server_addr = 22222;
let server0_port = 80;
let server1_port = 17;
let mut firewall = Nat::no_address_translation(PORT_RESTRICTED_FIREWALL, client_addr, rng, timeout);
let mut firewall = Nat::no_address_translation(PORT_RESTRICTED_FIREWALL, client_addr, rng, usize::MAX, timeout);
assert_eq!(firewall.assign_internal_address(), client_addr);
@@ -100,15 +101,15 @@ mod examples {
#[test]
fn easy_nat() {
use nat_emulation::predefines::EASY_NAT;
use nat_emulation::{DestType, Nat};
use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
let rng = rand::rngs::mock::StepRng::new(0, 1);
let mut time = 100;
let timeout = 1000 * 60 * 2;
let nat_ex_addr = 11111;
let mut nat = Nat::new(EASY_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
let mut nat = Nat::new(EASY_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
let client_in_addr = nat.assign_internal_address();
let client_in_port = 17;
let client_in_port = 25565;
let server_ex_addr = 22222;
let server_ex_port = 80;
@@ -143,15 +144,15 @@ mod examples {
#[test]
fn full_cone_nat() {
use nat_emulation::predefines::FULL_CONE_NAT;
use nat_emulation::{DestType, Nat};
use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
let rng = rand::rngs::mock::StepRng::new(0, 1);
let mut time = 100;
let timeout = 1000 * 60 * 2;
let nat_ex_addr = 11111;
let mut nat = Nat::new(FULL_CONE_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
let mut nat = Nat::new(FULL_CONE_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
let client_in_addr = nat.assign_internal_address();
let client_in_port = 17;
let client_in_port = 25565;
let server_ex_addr = 22222;
let server_ex_port = 80;
@@ -174,15 +175,15 @@ mod examples {
#[test]
fn symmetric_nat() {
use nat_emulation::predefines::SYMMETRIC_NAT;
use nat_emulation::{DestType::*, Nat};
use nat_emulation::{port_ranges::PRIVATE, DestType::*, Nat};
let rng = rand::rngs::mock::StepRng::new(0, 1);
let mut time = 100;
let timeout = 1000 * 60 * 2;
let nat_ex_addr = 11111;
let mut nat = Nat::new(SYMMETRIC_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
let mut nat = Nat::new(SYMMETRIC_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
let client_in_addr = nat.assign_internal_address();
let client_in_port = 17;
let client_in_port = 25565;
let server_ex_addr = 22222;
let server_ex_port0 = 80;
let server_ex_port1 = 17;
@@ -215,14 +216,14 @@ mod examples {
#[test]
fn hard_nat() {
use nat_emulation::predefines::HARD_NAT;
use nat_emulation::{DestType::*, Nat};
use nat_emulation::{port_ranges::PRIVATE, DestType::*, Nat};
let rng = rand::rngs::mock::StepRng::new(0, 1);
let mut time = 100;
let timeout = 1000 * 60 * 2;
let mut nat = Nat::new(HARD_NAT, [11110, 11111, 11112, 11113], 90000..=99999, 49152..=u16::MAX, rng, timeout);
let mut nat = Nat::new(HARD_NAT, [11110, 11111, 11112, 11113], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
let client_in_addr = nat.assign_internal_address();
let client_in_port = 17;
let client_in_port = 25565;
let server_ex_addr = 22222;
let server_ex_port0 = 80;
let server_ex_port1 = 17;
@@ -263,16 +264,16 @@ mod examples {
#[test]
fn misbehaving_nat() {
use nat_emulation::predefines::MISBEHAVING_NAT;
use nat_emulation::{DestType, Nat};
use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
let rng = rand::rngs::mock::StepRng::new(0, 1);
let mut time = 100;
let timeout = 1000 * 60 * 2;
let nat_ex_addr = 11111;
let mut nat = Nat::new(MISBEHAVING_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
let mut nat = Nat::new(MISBEHAVING_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
let client_in_addr = nat.assign_internal_address();
let client_in_port = 17;
let client_in_port = 25565;
let server_ex_addr = 22222;
let server_ex_port0 = 80;
let server_ex_port1 = 17;
+39 -5
View File
@@ -4,6 +4,7 @@ use std::ops::RangeInclusive;
use rand::RngCore;
use crate::flags::*;
use crate::nat_flags::port_ranges;
pub enum DestType {
External {
@@ -58,6 +59,8 @@ pub struct Nat<R: RngCore, const M: usize> {
rng: R,
assigned_external_ports: RangeInclusive<u16>,
assigned_internal_addresses: RangeInclusive<u32>,
map_cur_size: usize,
map_max_size: usize,
/// This field defines the set of behaviors this NAT will exhibit.
/// Some NATs will dynamically change their behavior during runtime in response to arbitrary
/// triggers. This classified as a Non-deterministic NAT by rfc4787, and it is awful.
@@ -76,13 +79,14 @@ impl<R: RngCore> Nat<R, 1> {
/// firewall. It can still translate ports however, unless you disable this behavior as well
/// with the `PORT_PRESERVATION_OVERRIDE` flag.
#[inline]
pub fn no_address_translation(flags: u32, assigned_address: u32, rng: R, mapping_timeout: i64) -> Self {
pub fn no_address_translation(flags: u32, assigned_address: u32, rng: R, mapping_max_size: usize, mapping_timeout: i64) -> Self {
Self::new(
flags,
[assigned_address],
assigned_address..=assigned_address,
0..=u16::MAX,
port_ranges::ALL,
rng,
mapping_max_size,
mapping_timeout,
)
}
@@ -97,6 +101,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
internal_addresses: RangeInclusive<u32>,
external_dynamic_ports: RangeInclusive<u16>,
rng: R,
mapping_max_size: usize,
mapping_timeout: i64,
) -> Self {
debug_assert!(
@@ -111,6 +116,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
internal_addresses,
external_dynamic_ports,
rng,
mapping_max_size,
mapping_timeout,
);
ret.external_addresses_len = external_addresses.len();
@@ -135,8 +141,10 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
internal_addresses: RangeInclusive<u32>,
external_dynamic_ports: RangeInclusive<u16>,
rng: R,
mapping_max_size: usize,
mapping_timeout: i64,
) -> Self {
debug_assert!(mapping_max_size > 0, "The mapping max size must be greateer than 0");
debug_assert!(
internal_addresses.start() <= internal_addresses.end(),
"The internal_addresses range must be nonempty"
@@ -149,6 +157,8 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
external_addresses_len: M,
external_addresses: external_addresses,
map: std::array::from_fn(|_| Vec::new()),
map_cur_size: 0,
map_max_size: usize::MAX,
mapping_timeout,
rng,
assigned_external_ports: external_dynamic_ports,
@@ -268,6 +278,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
if routing_table[i].external_port == src_port {
// In port preservation override mode we remove everyone else who is
// using the chosen src_port.
self.map_cur_size -= 1;
routing_table.swap_remove(i);
}
}
@@ -277,17 +288,22 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
// If we can't do any port preservation we have to randomly generate the port and address
let mut random_addr;
let mut random_port;
let mut attempt_until_force = 8;
let mut attempt_until_force = 32;
'regen: loop {
attempt_until_force -= 1;
random_addr = paired_addr_idx.unwrap_or_else(|| {
if M == 1 {
0
} else {
self.rng.next_u64() as usize % self.external_addresses_len
(self.rng.next_u32() % self.external_addresses_len as u32) as usize
}
});
random_port = (self.rng.next_u32() % self.assigned_external_ports.len() as u32) as u16 + self.assigned_external_ports.start();
let range = if self.flags & NO_WELL_KNOWN_PRESERVATION == 0 && port_ranges::WELL_KNOWN.contains(&src_port) {
&port_ranges::WELL_KNOWN
} else {
&self.assigned_external_ports
};
random_port = (self.rng.next_u32() % range.len() as u32) as u16 + range.start();
if self.flags & NO_PORT_PARITY == 0 {
// Force the port to have the same parity as the src_port.
random_port = (random_port & !1u16) | (src_port & 1u16);
@@ -299,6 +315,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
continue 'regen;
}
// Remove this mapping so our random port is unique.
self.map_cur_size -= 1;
routing_table.swap_remove(i);
break;
}
@@ -361,6 +378,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
while i < routing_table.len() {
let route = &mut routing_table[i];
if route.last_used_time < expiry {
self.map_cur_size -= 1;
routing_table.swap_remove(i);
continue;
} else if route.internal_addr == internal_src_addr && route.internal_port == internal_src_port {
@@ -399,6 +417,20 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
}
};
let external_addr = self.external_addresses[external_address_idx];
while self.map_cur_size >= self.map_max_size {
let idx = if M == 1 {
0
} else {
(self.rng.next_u32() % self.external_addresses_len as u32) as usize
};
let routing_table = &mut self.map[idx];
if !routing_table.is_empty() {
let idx = (self.rng.next_u32() % routing_table.len() as u32) as usize;
self.map_cur_size -= 1;
routing_table.swap_remove(idx);
}
}
self.map_cur_size += 1;
self.map[external_address_idx].push(Entry {
internal_addr: internal_src_addr,
internal_port: internal_src_port,
@@ -463,6 +495,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
while i < routing_table.len() {
let route = &mut routing_table[i];
if route.last_used_time < expiry {
self.map_cur_size -= 1;
routing_table.swap_remove(i);
continue;
} else if route.external_port == external_dest_port {
@@ -486,6 +519,7 @@ impl<R: RngCore, const M: usize> Nat<R, M> {
while i < routing_table.len() {
let route = &routing_table[i];
if route.external_port == external_dest_port {
self.map_cur_size -= 1;
routing_table.swap_remove(i);
} else {
i += 1;
+40 -20
View File
@@ -95,6 +95,10 @@ pub mod flags {
///
/// This flag has no effect if `NO_PORT_PRESERVATION` is true.
pub const PORT_PRESERVATION_OVERLOAD: u32 = 1 << 13;
/// By default, if a source port number is in the "well-known" port range, then the NAT will
/// attempt to generate a source port which is also in this range.
/// If true, the NAT will not do this.
pub const NO_WELL_KNOWN_PRESERVATION: u32 = 1 << 14;
}
/// This is a set of pre-defined flags for common NAT types. Each constant represents some
/// common NAT or firewall types one might want to emulate with this library. These are provided for
@@ -116,7 +120,7 @@ pub mod predefines {
/// let client_port = 17;
/// let server_addr = 22222;
/// let server_port = 80;
/// let mut firewall = Nat::no_address_translation(STATEFUL_FIREWALL, client_addr, rng, timeout);
/// let mut firewall = Nat::no_address_translation(STATEFUL_FIREWALL, client_addr, rng, usize::MAX, timeout);
/// assert_eq!(firewall.assign_internal_address(), client_addr);
///
/// time += 100;
@@ -158,7 +162,7 @@ pub mod predefines {
/// let server0_addr = 22222;
/// let server1_addr = 33333;
/// let server_port = 80;
/// let mut firewall = Nat::no_address_translation(RESTRICTED_FIREWALL, client_addr, rng, timeout);
/// let mut firewall = Nat::no_address_translation(RESTRICTED_FIREWALL, client_addr, rng, usize::MAX, timeout);
/// assert_eq!(firewall.assign_internal_address(), client_addr);
///
/// time += 100;
@@ -185,7 +189,7 @@ pub mod predefines {
/// let server_addr = 22222;
/// let server0_port = 80;
/// let server1_port = 17;
/// let mut firewall = Nat::no_address_translation(PORT_RESTRICTED_FIREWALL, client_addr, rng, timeout);
/// let mut firewall = Nat::no_address_translation(PORT_RESTRICTED_FIREWALL, client_addr, rng, usize::MAX, timeout);
///
/// assert_eq!(firewall.assign_internal_address(), client_addr);
///
@@ -206,15 +210,15 @@ pub mod predefines {
/// # Example
/// ```
/// use nat_emulation::predefines::EASY_NAT;
/// use nat_emulation::{DestType, Nat};
/// use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
/// let rng = rand::rngs::mock::StepRng::new(0, 1);
/// let mut time = 100;
/// let timeout = 1000 * 60 * 2;
///
/// let nat_ex_addr = 11111;
/// let mut nat = Nat::new(EASY_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
/// let mut nat = Nat::new(EASY_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
/// let client_in_addr = nat.assign_internal_address();
/// let client_in_port = 17;
/// let client_in_port = 25565;
/// let server_ex_addr = 22222;
/// let server_ex_port = 80;
///
@@ -253,15 +257,15 @@ pub mod predefines {
/// # Example
/// ```
/// use nat_emulation::predefines::FULL_CONE_NAT;
/// use nat_emulation::{DestType, Nat};
/// use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
/// let rng = rand::rngs::mock::StepRng::new(0, 1);
/// let mut time = 100;
/// let timeout = 1000 * 60 * 2;
///
/// let nat_ex_addr = 11111;
/// let mut nat = Nat::new(FULL_CONE_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
/// let mut nat = Nat::new(FULL_CONE_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
/// let client_in_addr = nat.assign_internal_address();
/// let client_in_port = 17;
/// let client_in_port = 25565;
/// let server_ex_addr = 22222;
/// let server_ex_port = 80;
///
@@ -291,15 +295,15 @@ pub mod predefines {
/// # Example
/// ```
/// use nat_emulation::predefines::SYMMETRIC_NAT;
/// use nat_emulation::{DestType::*, Nat};
/// use nat_emulation::{port_ranges::PRIVATE, DestType::*, Nat};
/// let rng = rand::rngs::mock::StepRng::new(0, 1);
/// let mut time = 100;
/// let timeout = 1000 * 60 * 2;
///
/// let nat_ex_addr = 11111;
/// let mut nat = Nat::new(SYMMETRIC_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
/// let mut nat = Nat::new(SYMMETRIC_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
/// let client_in_addr = nat.assign_internal_address();
/// let client_in_port = 17;
/// let client_in_port = 25565;
/// let server_ex_addr = 22222;
/// let server_ex_port0 = 80;
/// let server_ex_port1 = 17;
@@ -331,18 +335,18 @@ pub mod predefines {
/// ```
pub const SYMMETRIC_NAT: u32 = PORT_RESTRICTED_CONE_NAT | ADDRESS_AND_PORT_DEPENDENT_MAPPING;
/// Equivalent to: `SYMMETRIC_NAT | IP_POOLING_BEHAVIOR_ARBITRARY | INBOUND_REFRESH_BEHAVIOR_FALSE | NO_PORT_PARITY`
/// Equivalent to: `SYMMETRIC_NAT | IP_POOLING_BEHAVIOR_ARBITRARY | INBOUND_REFRESH_BEHAVIOR_FALSE | NO_PORT_PARITY | NO_WELL_KNOWN_PRESERVATION`
/// # Example
/// ```
/// use nat_emulation::predefines::HARD_NAT;
/// use nat_emulation::{DestType::*, Nat};
/// use nat_emulation::{port_ranges::PRIVATE, DestType::*, Nat};
/// let rng = rand::rngs::mock::StepRng::new(0, 1);
/// let mut time = 100;
/// let timeout = 1000 * 60 * 2;
///
/// let mut nat = Nat::new(HARD_NAT, [11110, 11111, 11112, 11113], 90000..=99999, 49152..=u16::MAX, rng, timeout);
/// let mut nat = Nat::new(HARD_NAT, [11110, 11111, 11112, 11113], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
/// let client_in_addr = nat.assign_internal_address();
/// let client_in_port = 17;
/// let client_in_port = 25565;
/// let server_ex_addr = 22222;
/// let server_ex_port0 = 80;
/// let server_ex_port1 = 17;
@@ -380,21 +384,22 @@ pub mod predefines {
/// _ => assert!(false),
/// }
/// ```
pub const HARD_NAT: u32 = SYMMETRIC_NAT | IP_POOLING_BEHAVIOR_ARBITRARY | INBOUND_REFRESH_BEHAVIOR_FALSE | NO_PORT_PARITY;
pub const HARD_NAT: u32 =
SYMMETRIC_NAT | IP_POOLING_BEHAVIOR_ARBITRARY | INBOUND_REFRESH_BEHAVIOR_FALSE | NO_PORT_PARITY | NO_WELL_KNOWN_PRESERVATION;
/// Equivalent to: `HARD_NAT | INTERNAL_ADDRESS_AND_PORT_HAIRPINNING | OUTBOUND_REFRESH_BEHAVIOR_FALSE | FILTERED_INBOUND_DESTROYS_MAPPING`
/// # Example
/// ```
/// use nat_emulation::predefines::MISBEHAVING_NAT;
/// use nat_emulation::{DestType, Nat};
/// use nat_emulation::{port_ranges::PRIVATE, DestType, Nat};
/// let rng = rand::rngs::mock::StepRng::new(0, 1);
/// let mut time = 100;
/// let timeout = 1000 * 60 * 2;
///
/// let nat_ex_addr = 11111;
/// let mut nat = Nat::new(MISBEHAVING_NAT, [nat_ex_addr], 90000..=99999, 49152..=u16::MAX, rng, timeout);
/// let mut nat = Nat::new(MISBEHAVING_NAT, [nat_ex_addr], 90000..=99999, PRIVATE, rng, usize::MAX, timeout);
///
/// let client_in_addr = nat.assign_internal_address();
/// let client_in_port = 17;
/// let client_in_port = 25565;
/// let server_ex_addr = 22222;
/// let server_ex_port0 = 80;
/// let server_ex_port1 = 17;
@@ -420,3 +425,18 @@ pub mod predefines {
pub const MISBEHAVING_NAT: u32 =
HARD_NAT | INTERNAL_ADDRESS_AND_PORT_HAIRPINNING | OUTBOUND_REFRESH_BEHAVIOR_FALSE | FILTERED_INBOUND_DESTROYS_MAPPING;
}
/// The standard set of different port ranges used on the internet.
pub mod port_ranges {
use std::ops::RangeInclusive;
/// The well-known port range, ports 1 to 1023.
pub const WELL_KNOWN: RangeInclusive<u16> = 1..=1023;
/// The registered port range, ports 1024 to 49151.
pub const REGISTERED: RangeInclusive<u16> = 1024..=49151;
/// The private, or dynamic, port range, ports 49152 to 65535.
pub const PRIVATE: RangeInclusive<u16> = 49152..=65535;
/// The combined registered and private port ranges, ports 1024 to 65535.
pub const REGISTERED_AND_PRIVATE: RangeInclusive<u16> = 1024..=65535;
/// The valid port numbers from 1 to 65535.
pub const ALL: RangeInclusive<u16> = 1..=65535;
}