Perform reorg into single bin
This commit is contained in:
parent
c795ed15fc
commit
2ed63e526a
@ -38,10 +38,11 @@ rtnetlink = "0.13.0"
|
||||
futures = "0.3.28"
|
||||
prometheus = "0.13.3"
|
||||
lazy_static = "1.4.0"
|
||||
rustc-hash = "1.1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "protomask"
|
||||
path = "src/cli/main.rs"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.deb]
|
||||
section = "network"
|
||||
|
5
libs/README.md
Normal file
5
libs/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Protomask support libraries
|
||||
|
||||
The development of protomask has caused the need for a few new standalone Rust libraries.
|
||||
|
||||
This directory acts as a home for these support libraries until they are ready to be spun off into their own standalone repositories.
|
16
libs/addrmap/Cargo.toml
Normal file
16
libs/addrmap/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "addrmap"
|
||||
version = "0.1.0"
|
||||
authors = ["Evan Pratten <ewpratten@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "Utilities for high-speed IP address mapping"
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/ewpratten/protomask"
|
||||
documentation = "https://docs.rs/protomask"
|
||||
repository = "https://github.com/ewpratten/protomask"
|
||||
license = "GPL-3.0"
|
||||
keywords = []
|
||||
categories = []
|
||||
|
||||
[dependencies]
|
||||
rustc-hash = "1.1.0"
|
0
libs/addrmap/src/ipbimap.rs
Normal file
0
libs/addrmap/src/ipbimap.rs
Normal file
0
libs/addrmap/src/lib.rs
Normal file
0
libs/addrmap/src/lib.rs
Normal file
13
src/lib.rs
13
src/lib.rs
@ -1,13 +0,0 @@
|
||||
//! # Protomask library
|
||||
//!
|
||||
//! *Note: There is a fair chance you are looking for `src/cli/main.rs` instead of this file.*
|
||||
|
||||
#![deny(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
|
||||
pub mod metrics;
|
||||
pub mod nat;
|
||||
mod packet;
|
||||
mod profiling;
|
@ -2,12 +2,15 @@
|
||||
|
||||
use clap::Parser;
|
||||
use config::Config;
|
||||
use logging::enable_logger;
|
||||
use protomask::nat::Nat64;
|
||||
use net::nat::Nat64;
|
||||
use utils::logging::enable_logger;
|
||||
|
||||
use crate::utils::metrics::serve_metrics;
|
||||
|
||||
mod utils;
|
||||
mod net;
|
||||
mod cli;
|
||||
mod config;
|
||||
mod logging;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
@ -44,7 +47,7 @@ pub async fn main() {
|
||||
// Handle metrics requests
|
||||
if let Some(bind_addr) = config.prom_bind_addr {
|
||||
log::info!("Enabling metrics server on {}", bind_addr);
|
||||
tokio::spawn(protomask::metrics::serve_metrics(bind_addr));
|
||||
tokio::spawn(serve_metrics(bind_addr));
|
||||
}
|
||||
|
||||
// Handle packets
|
210
src/nat/table.rs
210
src/nat/table.rs
@ -1,210 +0,0 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use bimap::BiHashMap;
|
||||
use ipnet::Ipv4Net;
|
||||
|
||||
use crate::metrics::{IPV4_POOL_RESERVED, IPV4_POOL_SIZE};
|
||||
|
||||
/// Possible errors thrown in the address reservation process
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum TableError {
|
||||
#[error("Address already reserved: {0}")]
|
||||
AddressAlreadyReserved(IpAddr),
|
||||
#[error("IPv4 address has no IPv6 mapping: {0}")]
|
||||
NoIpv6Mapping(Ipv4Addr),
|
||||
#[error("Address pool depleted")]
|
||||
AddressPoolDepleted,
|
||||
}
|
||||
|
||||
/// A NAT address table
|
||||
#[derive(Debug)]
|
||||
pub struct Nat64Table {
|
||||
/// All possible IPv4 addresses that can be used
|
||||
ipv4_pool: Vec<Ipv4Net>,
|
||||
/// Current reservations
|
||||
reservations: BiHashMap<Ipv6Addr, Ipv4Addr>,
|
||||
/// The timestamp of each reservation (used for pruning)
|
||||
reservation_times: HashMap<(Ipv6Addr, Ipv4Addr), Option<Instant>>,
|
||||
/// The maximum amount of time to reserve an address pair for
|
||||
reservation_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Nat64Table {
|
||||
/// Construct a new NAT64 table
|
||||
///
|
||||
/// **Arguments:**
|
||||
/// - `ipv4_pool`: The pool of IPv4 addresses to use in the mapping process
|
||||
/// - `reservation_timeout`: The amount of time to reserve an address pair for
|
||||
pub fn new(ipv4_pool: Vec<Ipv4Net>, reservation_timeout: Duration) -> Self {
|
||||
// Track the total pool size
|
||||
let total_size: usize = ipv4_pool.iter().map(|net| net.hosts().count()).sum();
|
||||
IPV4_POOL_SIZE.set(total_size as i64);
|
||||
|
||||
Self {
|
||||
ipv4_pool,
|
||||
reservations: BiHashMap::new(),
|
||||
reservation_times: HashMap::new(),
|
||||
reservation_timeout,
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a reservation for an IP address pair for eternity
|
||||
pub fn add_infinite_reservation(
|
||||
&mut self,
|
||||
ipv6: Ipv6Addr,
|
||||
ipv4: Ipv4Addr,
|
||||
) -> Result<(), TableError> {
|
||||
// Check if either address is already reserved
|
||||
self.prune();
|
||||
self.track_utilization();
|
||||
if self.reservations.contains_left(&ipv6) {
|
||||
return Err(TableError::AddressAlreadyReserved(ipv6.into()));
|
||||
} else if self.reservations.contains_right(&ipv4) {
|
||||
return Err(TableError::AddressAlreadyReserved(ipv4.into()));
|
||||
}
|
||||
|
||||
// Add the reservation
|
||||
self.reservations.insert(ipv6, ipv4);
|
||||
self.reservation_times.insert((ipv6, ipv4), None);
|
||||
log::info!("Added infinite reservation: {} -> {}", ipv6, ipv4);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if a given address exists in the table
|
||||
pub fn contains(&self, address: &IpAddr) -> bool {
|
||||
match address {
|
||||
IpAddr::V4(ipv4) => self.reservations.contains_right(ipv4),
|
||||
IpAddr::V6(ipv6) => self.reservations.contains_left(ipv6),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get or assign an IPv4 address for the given IPv6 address
|
||||
pub fn get_or_assign_ipv4(&mut self, ipv6: Ipv6Addr) -> Result<Ipv4Addr, TableError> {
|
||||
// Prune old reservations
|
||||
self.prune();
|
||||
self.track_utilization();
|
||||
|
||||
// If the IPv6 address is already reserved, return the IPv4 address
|
||||
if let Some(ipv4) = self.reservations.get_by_left(&ipv6) {
|
||||
// Update the reservation time
|
||||
self.reservation_times
|
||||
.insert((ipv6, *ipv4), Some(Instant::now()));
|
||||
|
||||
// Return the v4 address
|
||||
return Ok(*ipv4);
|
||||
}
|
||||
|
||||
// Otherwise, try to assign a new IPv4 address
|
||||
for ipv4_net in &self.ipv4_pool {
|
||||
for ipv4 in ipv4_net.hosts() {
|
||||
// Check if this address is available for use
|
||||
if !self.reservations.contains_right(&ipv4) {
|
||||
// Add the reservation
|
||||
self.reservations.insert(ipv6, ipv4);
|
||||
self.reservation_times
|
||||
.insert((ipv6, ipv4), Some(Instant::now()));
|
||||
log::info!("Assigned new reservation: {} -> {}", ipv6, ipv4);
|
||||
return Ok(ipv4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we failed to find an available address
|
||||
Err(TableError::AddressPoolDepleted)
|
||||
}
|
||||
|
||||
/// Try to find an IPv6 address for the given IPv4 address
|
||||
pub fn get_reverse(&mut self, ipv4: Ipv4Addr) -> Result<Ipv6Addr, TableError> {
|
||||
// Prune old reservations
|
||||
self.prune();
|
||||
self.track_utilization();
|
||||
|
||||
// If the IPv4 address is already reserved, return the IPv6 address
|
||||
if let Some(ipv6) = self.reservations.get_by_right(&ipv4) {
|
||||
// Update the reservation time
|
||||
self.reservation_times
|
||||
.insert((*ipv6, ipv4), Some(Instant::now()));
|
||||
|
||||
// Return the v6 address
|
||||
return Ok(*ipv6);
|
||||
}
|
||||
|
||||
// Otherwise, there is no matching reservation
|
||||
Err(TableError::NoIpv6Mapping(ipv4))
|
||||
}
|
||||
}
|
||||
|
||||
impl Nat64Table {
|
||||
/// Prune old reservations
|
||||
fn prune(&mut self) {
|
||||
let now = Instant::now();
|
||||
|
||||
// Prune from the reservation map
|
||||
self.reservations.retain(|v6, v4| {
|
||||
if let Some(Some(time)) = self.reservation_times.get(&(*v6, *v4)) {
|
||||
let keep = now - *time < self.reservation_timeout;
|
||||
if !keep {
|
||||
log::info!("Pruned reservation: {} -> {}", v6, v4);
|
||||
}
|
||||
keep
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
// Remove all times assigned to reservations that no longer exist
|
||||
self.reservation_times.retain(|(v6, v4), _| {
|
||||
self.reservations.contains_left(v6) && self.reservations.contains_right(v4)
|
||||
});
|
||||
}
|
||||
|
||||
fn track_utilization(&self) {
|
||||
// Count static and dynamic in a single pass
|
||||
let (total_dynamic_reservations, total_static_reservations) = self
|
||||
.reservation_times
|
||||
.iter()
|
||||
.map(|((_v6, _v4), time)| match time {
|
||||
Some(_) => (1, 0),
|
||||
None => (0, 1),
|
||||
})
|
||||
.fold((0, 0), |(a1, a2), (b1, b2)| (a1 + b1, a2 + b2));
|
||||
|
||||
// Track the values
|
||||
IPV4_POOL_RESERVED
|
||||
.with_label_values(&["dynamic"])
|
||||
.set(i64::from(total_dynamic_reservations));
|
||||
IPV4_POOL_RESERVED
|
||||
.with_label_values(&["static"])
|
||||
.set(i64::from(total_static_reservations));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_add_infinite_reservation() {
|
||||
let mut table = Nat64Table::new(
|
||||
vec![Ipv4Net::new(Ipv4Addr::new(192, 0, 2, 0), 24).unwrap()],
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
|
||||
// Add a reservation
|
||||
table
|
||||
.add_infinite_reservation("2001:db8::1".parse().unwrap(), "192.0.2.1".parse().unwrap())
|
||||
.unwrap();
|
||||
|
||||
// Check that it worked
|
||||
assert_eq!(
|
||||
table
|
||||
.reservations
|
||||
.get_by_left(&"2001:db8::1".parse().unwrap()),
|
||||
Some(&"192.0.2.1".parse().unwrap())
|
||||
);
|
||||
}
|
||||
}
|
5
src/net/mod.rs
Normal file
5
src/net/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//! Networking logic
|
||||
|
||||
// pub mod device;
|
||||
pub mod nat;
|
||||
pub mod packet;
|
@ -7,7 +7,7 @@ pub enum Nat64Error {
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error(transparent)]
|
||||
PacketHandling(#[from] crate::packet::error::PacketError),
|
||||
PacketHandling(#[from] crate::net::packet::error::PacketError),
|
||||
#[error(transparent)]
|
||||
PacketReceive(#[from] tokio::sync::broadcast::error::RecvError),
|
||||
#[error(transparent)]
|
@ -1,10 +1,5 @@
|
||||
use crate::{
|
||||
metrics::PACKET_COUNTER,
|
||||
packet::{
|
||||
protocols::{ipv4::Ipv4Packet, ipv6::Ipv6Packet},
|
||||
xlat::ip::{translate_ipv4_to_ipv6, translate_ipv6_to_ipv4},
|
||||
}, profiling::PacketTimer,
|
||||
};
|
||||
|
||||
use crate::utils::{profiling::PacketTimer, metrics::PACKET_COUNTER};
|
||||
|
||||
use self::{
|
||||
error::Nat64Error,
|
||||
@ -19,6 +14,8 @@ use std::{
|
||||
};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
use super::packet::{protocols::{ipv4::Ipv4Packet, ipv6::Ipv6Packet}, xlat::ip::{translate_ipv4_to_ipv6, translate_ipv6_to_ipv4}};
|
||||
|
||||
mod error;
|
||||
mod table;
|
||||
mod utils;
|
||||
@ -85,7 +82,6 @@ impl Nat64 {
|
||||
// Separate logic is needed for handling IPv4 vs IPv6 packets, so a check must be done here
|
||||
match packet[0] >> 4 {
|
||||
4 => {
|
||||
|
||||
// Parse the packet
|
||||
let packet: Ipv4Packet<Vec<u8>> = packet.try_into()?;
|
||||
|
||||
@ -107,23 +103,20 @@ impl Nat64 {
|
||||
.inc();
|
||||
|
||||
// Spawn a task to process the packet
|
||||
tokio::spawn(async move {
|
||||
if let Some(output) = unwrap_log(translate_ipv4_to_ipv6(
|
||||
packet,
|
||||
new_source,
|
||||
new_destination,
|
||||
&mut timer,
|
||||
)) {
|
||||
tx.send(output.into()).await.unwrap();
|
||||
if should_print_profiling {
|
||||
timer.log();
|
||||
}
|
||||
PACKET_COUNTER.with_label_values(&["ipv6", "sent"]).inc();
|
||||
if let Some(output) = unwrap_log(translate_ipv4_to_ipv6(
|
||||
packet,
|
||||
new_source,
|
||||
new_destination,
|
||||
&mut timer,
|
||||
)) {
|
||||
tx.send(output.into()).await.unwrap();
|
||||
if should_print_profiling {
|
||||
timer.log();
|
||||
}
|
||||
});
|
||||
PACKET_COUNTER.with_label_values(&["ipv6", "sent"]).inc();
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
|
||||
// Parse the packet
|
||||
let packet: Ipv6Packet<Vec<u8>> = packet.try_into()?;
|
||||
|
||||
@ -161,20 +154,18 @@ impl Nat64 {
|
||||
.inc();
|
||||
|
||||
// Spawn a task to process the packet
|
||||
tokio::spawn(async move {
|
||||
if let Some(output) = unwrap_log(translate_ipv6_to_ipv4(
|
||||
&packet,
|
||||
new_source,
|
||||
new_destination,
|
||||
&mut timer,
|
||||
)) {
|
||||
tx.send(output.into()).await.unwrap();
|
||||
if should_print_profiling {
|
||||
timer.log();
|
||||
}
|
||||
PACKET_COUNTER.with_label_values(&["ipv4", "sent"]).inc();
|
||||
if let Some(output) = unwrap_log(translate_ipv6_to_ipv4(
|
||||
&packet,
|
||||
new_source,
|
||||
new_destination,
|
||||
&mut timer,
|
||||
)) {
|
||||
tx.send(output.into()).await.unwrap();
|
||||
if should_print_profiling {
|
||||
timer.log();
|
||||
}
|
||||
});
|
||||
PACKET_COUNTER.with_label_values(&["ipv4", "sent"]).inc();
|
||||
}
|
||||
}
|
||||
n => {
|
||||
log::warn!("Unknown IP version: {}", n);
|
253
src/net/nat/table.rs
Normal file
253
src/net/nat/table.rs
Normal file
@ -0,0 +1,253 @@
|
||||
|
||||
// use rustc_hash::FxHashMap;
|
||||
|
||||
// #[derive(Debug, Clone, PartialEq, Eq)]
|
||||
// struct IpBimap {
|
||||
// v4_to_v6: FxHashMap<u32, u128>,
|
||||
// v6_to_v4: FxHashMap<u128, u32>,
|
||||
// }
|
||||
|
||||
// impl IpBimap {
|
||||
// /// Construct a new `IpBimap`
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// v4_to_v6: FxHashMap::default(),
|
||||
// v6_to_v4: FxHashMap::default(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Insert a new mapping
|
||||
// pub fn insert(&mut self, v4: u32, v6: u128) {
|
||||
// self.v4_to_v6.insert(v4, v6);
|
||||
// self.v6_to_v4.insert(v6, v4);
|
||||
// }
|
||||
|
||||
// /// Remove a mapping
|
||||
// pub fn remove(&mut self, v4: u32, v6: u128) {
|
||||
// self.v4_to_v6.remove(&v4);
|
||||
// self.v6_to_v4.remove(&v6);
|
||||
// }
|
||||
|
||||
// /// Get the IPv6 address for a given IPv4 address
|
||||
// pub fn get_v6(&self, v4: u32) -> Option<u128> {
|
||||
// self.v4_to_v6.get(&v4).copied()
|
||||
// }
|
||||
|
||||
// /// Get the IPv4 address for a given IPv6 address
|
||||
// pub fn get_v4(&self, v6: u128) -> Option<u32> {
|
||||
// self.v6_to_v4.get(&v6).copied()
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// // use std::{
|
||||
// // collections::HashMap,
|
||||
// // net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
// // time::{Duration, Instant},
|
||||
// // };
|
||||
|
||||
// // use bimap::BiHashMap;
|
||||
// // use ipnet::Ipv4Net;
|
||||
|
||||
// // use crate::utils::metrics::{IPV4_POOL_SIZE, IPV4_POOL_RESERVED};
|
||||
|
||||
|
||||
// // /// Possible errors thrown in the address reservation process
|
||||
// // #[derive(Debug, thiserror::Error)]
|
||||
// // pub enum TableError {
|
||||
// // #[error("Address already reserved: {0}")]
|
||||
// // AddressAlreadyReserved(IpAddr),
|
||||
// // #[error("IPv4 address has no IPv6 mapping: {0}")]
|
||||
// // NoIpv6Mapping(Ipv4Addr),
|
||||
// // #[error("Address pool depleted")]
|
||||
// // AddressPoolDepleted,
|
||||
// // }
|
||||
|
||||
// // /// A NAT address table
|
||||
// // #[derive(Debug)]
|
||||
// // pub struct Nat64Table {
|
||||
// // /// All possible IPv4 addresses that can be used
|
||||
// // ipv4_pool: Vec<Ipv4Net>,
|
||||
// // /// Current reservations
|
||||
// // reservations: BiHashMap<Ipv6Addr, Ipv4Addr>,
|
||||
// // /// The timestamp of each reservation (used for pruning)
|
||||
// // reservation_times: HashMap<(Ipv6Addr, Ipv4Addr), Option<Instant>>,
|
||||
// // /// The maximum amount of time to reserve an address pair for
|
||||
// // reservation_timeout: Duration,
|
||||
// // }
|
||||
|
||||
// // impl Nat64Table {
|
||||
// // /// Construct a new NAT64 table
|
||||
// // ///
|
||||
// // /// **Arguments:**
|
||||
// // /// - `ipv4_pool`: The pool of IPv4 addresses to use in the mapping process
|
||||
// // /// - `reservation_timeout`: The amount of time to reserve an address pair for
|
||||
// // pub fn new(ipv4_pool: Vec<Ipv4Net>, reservation_timeout: Duration) -> Self {
|
||||
// // // Track the total pool size
|
||||
// // let total_size: usize = ipv4_pool.iter().map(|net| net.hosts().count()).sum();
|
||||
// // IPV4_POOL_SIZE.set(total_size as i64);
|
||||
|
||||
// // Self {
|
||||
// // ipv4_pool,
|
||||
// // reservations: BiHashMap::new(),
|
||||
// // reservation_times: HashMap::new(),
|
||||
// // reservation_timeout,
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // /// Make a reservation for an IP address pair for eternity
|
||||
// // pub fn add_infinite_reservation(
|
||||
// // &mut self,
|
||||
// // ipv6: Ipv6Addr,
|
||||
// // ipv4: Ipv4Addr,
|
||||
// // ) -> Result<(), TableError> {
|
||||
// // // Check if either address is already reserved
|
||||
// // self.prune();
|
||||
// // self.track_utilization();
|
||||
// // if self.reservations.contains_left(&ipv6) {
|
||||
// // return Err(TableError::AddressAlreadyReserved(ipv6.into()));
|
||||
// // } else if self.reservations.contains_right(&ipv4) {
|
||||
// // return Err(TableError::AddressAlreadyReserved(ipv4.into()));
|
||||
// // }
|
||||
|
||||
// // // Add the reservation
|
||||
// // self.reservations.insert(ipv6, ipv4);
|
||||
// // self.reservation_times.insert((ipv6, ipv4), None);
|
||||
// // log::info!("Added infinite reservation: {} -> {}", ipv6, ipv4);
|
||||
// // Ok(())
|
||||
// // }
|
||||
|
||||
// // /// Check if a given address exists in the table
|
||||
// // pub fn contains(&self, address: &IpAddr) -> bool {
|
||||
// // match address {
|
||||
// // IpAddr::V4(ipv4) => self.reservations.contains_right(ipv4),
|
||||
// // IpAddr::V6(ipv6) => self.reservations.contains_left(ipv6),
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // /// Get or assign an IPv4 address for the given IPv6 address
|
||||
// // pub fn get_or_assign_ipv4(&mut self, ipv6: Ipv6Addr) -> Result<Ipv4Addr, TableError> {
|
||||
// // // Prune old reservations
|
||||
// // self.prune();
|
||||
// // self.track_utilization();
|
||||
|
||||
// // // If the IPv6 address is already reserved, return the IPv4 address
|
||||
// // if let Some(ipv4) = self.reservations.get_by_left(&ipv6) {
|
||||
// // // Update the reservation time
|
||||
// // self.reservation_times
|
||||
// // .insert((ipv6, *ipv4), Some(Instant::now()));
|
||||
|
||||
// // // Return the v4 address
|
||||
// // return Ok(*ipv4);
|
||||
// // }
|
||||
|
||||
// // // Otherwise, try to assign a new IPv4 address
|
||||
// // for ipv4_net in &self.ipv4_pool {
|
||||
// // for ipv4 in ipv4_net.hosts() {
|
||||
// // // Check if this address is available for use
|
||||
// // if !self.reservations.contains_right(&ipv4) {
|
||||
// // // Add the reservation
|
||||
// // self.reservations.insert(ipv6, ipv4);
|
||||
// // self.reservation_times
|
||||
// // .insert((ipv6, ipv4), Some(Instant::now()));
|
||||
// // log::info!("Assigned new reservation: {} -> {}", ipv6, ipv4);
|
||||
// // return Ok(ipv4);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // // If we get here, we failed to find an available address
|
||||
// // Err(TableError::AddressPoolDepleted)
|
||||
// // }
|
||||
|
||||
// // /// Try to find an IPv6 address for the given IPv4 address
|
||||
// // pub fn get_reverse(&mut self, ipv4: Ipv4Addr) -> Result<Ipv6Addr, TableError> {
|
||||
// // // Prune old reservations
|
||||
// // self.prune();
|
||||
// // self.track_utilization();
|
||||
|
||||
// // // If the IPv4 address is already reserved, return the IPv6 address
|
||||
// // if let Some(ipv6) = self.reservations.get_by_right(&ipv4) {
|
||||
// // // Update the reservation time
|
||||
// // self.reservation_times
|
||||
// // .insert((*ipv6, ipv4), Some(Instant::now()));
|
||||
|
||||
// // // Return the v6 address
|
||||
// // return Ok(*ipv6);
|
||||
// // }
|
||||
|
||||
// // // Otherwise, there is no matching reservation
|
||||
// // Err(TableError::NoIpv6Mapping(ipv4))
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // impl Nat64Table {
|
||||
// // /// Prune old reservations
|
||||
// // fn prune(&mut self) {
|
||||
// // let now = Instant::now();
|
||||
|
||||
// // // Prune from the reservation map
|
||||
// // self.reservations.retain(|v6, v4| {
|
||||
// // if let Some(Some(time)) = self.reservation_times.get(&(*v6, *v4)) {
|
||||
// // let keep = now - *time < self.reservation_timeout;
|
||||
// // if !keep {
|
||||
// // log::info!("Pruned reservation: {} -> {}", v6, v4);
|
||||
// // }
|
||||
// // keep
|
||||
// // } else {
|
||||
// // true
|
||||
// // }
|
||||
// // });
|
||||
|
||||
// // // Remove all times assigned to reservations that no longer exist
|
||||
// // self.reservation_times.retain(|(v6, v4), _| {
|
||||
// // self.reservations.contains_left(v6) && self.reservations.contains_right(v4)
|
||||
// // });
|
||||
// // }
|
||||
|
||||
// // fn track_utilization(&self) {
|
||||
// // // Count static and dynamic in a single pass
|
||||
// // let (total_dynamic_reservations, total_static_reservations) = self
|
||||
// // .reservation_times
|
||||
// // .iter()
|
||||
// // .map(|((_v6, _v4), time)| match time {
|
||||
// // Some(_) => (1, 0),
|
||||
// // None => (0, 1),
|
||||
// // })
|
||||
// // .fold((0, 0), |(a1, a2), (b1, b2)| (a1 + b1, a2 + b2));
|
||||
|
||||
// // // Track the values
|
||||
// // IPV4_POOL_RESERVED
|
||||
// // .with_label_values(&["dynamic"])
|
||||
// // .set(i64::from(total_dynamic_reservations));
|
||||
// // IPV4_POOL_RESERVED
|
||||
// // .with_label_values(&["static"])
|
||||
// // .set(i64::from(total_static_reservations));
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // #[cfg(test)]
|
||||
// // mod tests {
|
||||
// // use super::*;
|
||||
|
||||
// // #[test]
|
||||
// // fn test_add_infinite_reservation() {
|
||||
// // let mut table = Nat64Table::new(
|
||||
// // vec![Ipv4Net::new(Ipv4Addr::new(192, 0, 2, 0), 24).unwrap()],
|
||||
// // Duration::from_secs(60),
|
||||
// // );
|
||||
|
||||
// // // Add a reservation
|
||||
// // table
|
||||
// // .add_infinite_reservation("2001:db8::1".parse().unwrap(), "192.0.2.1".parse().unwrap())
|
||||
// // .unwrap();
|
||||
|
||||
// // // Check that it worked
|
||||
// // assert_eq!(
|
||||
// // table
|
||||
// // .reservations
|
||||
// // .get_by_left(&"2001:db8::1".parse().unwrap()),
|
||||
// // Some(&"192.0.2.1".parse().unwrap())
|
||||
// // );
|
||||
// // }
|
||||
// // }
|
@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use ipnet::Ipv6Net;
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
/// Embed an IPv4 address in an IPv6 prefix
|
||||
pub fn embed_address(ipv4_address: Ipv4Addr, ipv6_prefix: Ipv6Net) -> Ipv6Addr {
|
5
src/net/packet/mod.rs
Normal file
5
src/net/packet/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//! Tools for efficiently creating and modifying packets
|
||||
|
||||
pub mod error;
|
||||
pub mod protocols;
|
||||
pub mod xlat;
|
@ -3,7 +3,7 @@ use pnet_packet::{
|
||||
Packet,
|
||||
};
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct IcmpPacket<T> {
|
@ -5,7 +5,7 @@ use pnet_packet::{
|
||||
Packet,
|
||||
};
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
use super::raw::RawBytes;
|
||||
|
@ -6,7 +6,7 @@ use pnet_packet::{
|
||||
Packet,
|
||||
};
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ipv4Packet<T> {
|
@ -2,7 +2,7 @@ use std::net::Ipv6Addr;
|
||||
|
||||
use pnet_packet::{ip::IpNextHeaderProtocol, Packet};
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Ipv6Packet<T> {
|
@ -1,3 +1,5 @@
|
||||
//! Definitions for each type of packet `protomask` can handle
|
||||
|
||||
pub mod icmp;
|
||||
pub mod icmpv6;
|
||||
pub mod ipv4;
|
@ -1,4 +1,4 @@
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct RawBytes(pub Vec<u8>);
|
@ -6,7 +6,7 @@ use pnet_packet::{
|
||||
};
|
||||
|
||||
use super::raw::RawBytes;
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
/// A TCP packet
|
||||
#[derive(Debug, Clone)]
|
@ -3,7 +3,7 @@ use std::net::{IpAddr, SocketAddr};
|
||||
use pnet_packet::Packet;
|
||||
|
||||
use super::raw::RawBytes;
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
/// A UDP packet
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
@ -4,13 +4,8 @@ use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use pnet_packet::{icmp::IcmpTypes, icmpv6::Icmpv6Types};
|
||||
|
||||
use crate::{
|
||||
metrics::ICMP_COUNTER,
|
||||
packet::{
|
||||
error::PacketError,
|
||||
protocols::{icmp::IcmpPacket, icmpv6::Icmpv6Packet, raw::RawBytes},
|
||||
}, profiling::{PacketTimer, TimerScope},
|
||||
};
|
||||
|
||||
use crate::{utils::{profiling::{TimerScope, PacketTimer}, metrics::ICMP_COUNTER}, net::packet::{protocols::{raw::RawBytes, icmpv6::Icmpv6Packet, icmp::IcmpPacket}, error::PacketError}};
|
||||
|
||||
use super::ip::{translate_ipv4_to_ipv6, translate_ipv6_to_ipv4};
|
||||
|
@ -7,7 +7,7 @@ use pnet_packet::{
|
||||
icmpv6::{Icmpv6Code, Icmpv6Type, Icmpv6Types},
|
||||
};
|
||||
|
||||
use crate::packet::error::PacketError;
|
||||
use crate::net::packet::error::PacketError;
|
||||
|
||||
/// Best effort translation from an ICMP type and code to an ICMPv6 type and code
|
||||
#[allow(clippy::deprecated_cfg_attr)]
|
@ -3,11 +3,10 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use pnet_packet::ip::IpNextHeaderProtocols;
|
||||
|
||||
use crate::{
|
||||
packet::protocols::{icmp::IcmpPacket, tcp::TcpPacket, udp::UdpPacket},
|
||||
packet::{
|
||||
net::packet::{
|
||||
error::PacketError,
|
||||
protocols::{icmpv6::Icmpv6Packet, ipv4::Ipv4Packet, ipv6::Ipv6Packet, raw::RawBytes},
|
||||
}, profiling::{PacketTimer, TimerScope},
|
||||
protocols::{icmpv6::Icmpv6Packet, ipv4::Ipv4Packet, ipv6::Ipv6Packet, raw::RawBytes, icmp::IcmpPacket, udp::UdpPacket, tcp::TcpPacket},
|
||||
}, utils::profiling::{TimerScope, PacketTimer},
|
||||
};
|
||||
|
||||
use super::{
|
@ -1,16 +1,19 @@
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
use crate::{packet::{
|
||||
error::PacketError,
|
||||
protocols::{raw::RawBytes, tcp::TcpPacket},
|
||||
}, profiling::{PacketTimer, TimerScope}};
|
||||
use crate::{
|
||||
net::packet::{
|
||||
error::PacketError,
|
||||
protocols::{raw::RawBytes, tcp::TcpPacket},
|
||||
},
|
||||
utils::profiling::{PacketTimer, TimerScope},
|
||||
};
|
||||
|
||||
/// Translates an IPv4 TCP packet to an IPv6 TCP packet
|
||||
pub fn translate_tcp4_to_tcp6(
|
||||
input: TcpPacket<RawBytes>,
|
||||
new_source_addr: Ipv6Addr,
|
||||
new_destination_addr: Ipv6Addr,
|
||||
timer: &mut PacketTimer
|
||||
timer: &mut PacketTimer,
|
||||
) -> Result<TcpPacket<RawBytes>, PacketError> {
|
||||
// Build the packet
|
||||
timer.start(TimerScope::Tcp);
|
||||
@ -34,7 +37,7 @@ pub fn translate_tcp6_to_tcp4(
|
||||
input: TcpPacket<RawBytes>,
|
||||
new_source_addr: Ipv4Addr,
|
||||
new_destination_addr: Ipv4Addr,
|
||||
timer: &mut PacketTimer
|
||||
timer: &mut PacketTimer,
|
||||
) -> Result<TcpPacket<RawBytes>, PacketError> {
|
||||
// Build the packet
|
||||
timer.start(TimerScope::Tcp);
|
@ -1,11 +1,11 @@
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
use crate::{
|
||||
packet::{
|
||||
net::packet::{
|
||||
error::PacketError,
|
||||
protocols::{raw::RawBytes, udp::UdpPacket},
|
||||
},
|
||||
profiling::{PacketTimer, TimerScope},
|
||||
utils::profiling::{PacketTimer, TimerScope},
|
||||
};
|
||||
|
||||
/// Translates an IPv4 UDP packet to an IPv6 UDP packet
|
||||
@ -47,7 +47,7 @@ pub fn translate_udp6_to_udp4(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::packet::protocols::udp::UdpPacket;
|
||||
use crate::net::packet::protocols::udp::UdpPacket;
|
||||
|
||||
#[test]
|
||||
fn test_translate_udp4_to_udp6() {
|
@ -1,7 +0,0 @@
|
||||
//! Custom packet modification utilities
|
||||
//!
|
||||
//! pnet isn't quite what we need for this project, so the contents of this module wrap it to make it easier to use.
|
||||
|
||||
pub mod error;
|
||||
pub mod protocols;
|
||||
pub mod xlat;
|
3
src/utils/mod.rs
Normal file
3
src/utils/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod logging;
|
||||
pub mod profiling;
|
||||
pub mod metrics;
|
@ -85,7 +85,7 @@ impl PacketTimer {
|
||||
|
||||
pub fn log(&self) {
|
||||
log::trace!(
|
||||
"[Timer report] proto: {}, total: {:05}µs, ipv4_to_ipv6: {:05}µs, ipv6_to_ipv4: {:05}µs, icmp_to_icmpv6: {:05}µs, icmpv6_to_icmp: {:05}µs, udp: {:05}µs, tcp: {:05}µs",
|
||||
"[Timer report] proto: {}, total: {:05}µs, ipv4_to_ipv6: {:05}µs, ipv6_to_ipv4: {:05}µs, icmp_to_icmpv6: {:05}µs, icmpv6_to_icmp: {:05}µs, udp: {:05}ns, tcp: {:05}ns",
|
||||
self.protocol,
|
||||
self.creation_time.elapsed().as_micros(),
|
||||
self.states.get(&TimerScope::Ipv4ToIpv6).map(|val| match val {
|
||||
@ -105,11 +105,11 @@ impl PacketTimer {
|
||||
_=>0
|
||||
}).unwrap_or(0),
|
||||
self.states.get(&TimerScope::Udp).map(|val| match val {
|
||||
TimerState::Ended(duration, _) => duration.as_micros(),
|
||||
TimerState::Ended(duration, _) => duration.as_nanos(),
|
||||
_=>0
|
||||
}).unwrap_or(0),
|
||||
self.states.get(&TimerScope::Tcp).map(|val| match val {
|
||||
TimerState::Ended(duration, _) => duration.as_micros(),
|
||||
TimerState::Ended(duration, _) => duration.as_nanos(),
|
||||
_=>0
|
||||
}).unwrap_or(0),
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user