nat: active SNAT binding tracking + display
NatTable gains bindings: Vec<NatBinding> field. record_snat()
called after successful SNAT rewrite captures original→translated
src_addr/port mapping. Bindings capped at 1024 entries (FIFO).
format_bindings() returns:
Active SNAT bindings: 3
10.0.0.1:1234 -> 192.168.1.100:40001
10.0.0.2:5678 -> 192.168.1.100:40002
Useful for diagnosing NAT issues and seeing which internal
connections are being source-NAT'd. Mirrors Linux
/proc/net/ip_conntrack display.
All 31 tests pass.
This commit is contained in:
@@ -70,6 +70,7 @@ impl Default for NatBinding {
|
||||
#[derive(Debug)]
|
||||
pub struct NatTable {
|
||||
pub rules: Vec<NatRule>,
|
||||
pub bindings: Vec<NatBinding>,
|
||||
next_id: u32,
|
||||
ephemeral_port: u16,
|
||||
}
|
||||
@@ -78,6 +79,7 @@ impl NatTable {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
rules: Vec::new(),
|
||||
bindings: Vec::new(),
|
||||
next_id: 1,
|
||||
ephemeral_port: 40000,
|
||||
}
|
||||
@@ -117,6 +119,31 @@ impl NatTable {
|
||||
None
|
||||
}
|
||||
|
||||
/// Record an active SNAT binding for display purposes.
|
||||
/// Called after a successful SNAT rewrite.
|
||||
pub fn record_snat(
|
||||
&mut self,
|
||||
orig_src: IpAddress,
|
||||
trans_src: IpAddress,
|
||||
orig_sport: u16,
|
||||
trans_sport: u16,
|
||||
) {
|
||||
// Cap bindings to prevent unbounded growth.
|
||||
if self.bindings.len() >= 1024 {
|
||||
self.bindings.remove(0);
|
||||
}
|
||||
self.bindings.push(NatBinding {
|
||||
orig_src,
|
||||
trans_src,
|
||||
orig_dst: IpAddress::v4(0, 0, 0, 0),
|
||||
trans_dst: IpAddress::v4(0, 0, 0, 0),
|
||||
orig_sport,
|
||||
trans_sport,
|
||||
orig_dport: 0,
|
||||
trans_dport: 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn lookup_dnat(
|
||||
&self,
|
||||
hook: Hook,
|
||||
@@ -162,6 +189,20 @@ impl NatTable {
|
||||
out
|
||||
}
|
||||
|
||||
pub fn format_bindings(&self) -> String {
|
||||
if self.bindings.is_empty() {
|
||||
return "no active bindings\n".to_string();
|
||||
}
|
||||
let mut out = format!("Active SNAT bindings: {}\n", self.bindings.len());
|
||||
for b in &self.bindings {
|
||||
out.push_str(&alloc::format!(
|
||||
" {}:{} -> {}:{}\n",
|
||||
b.orig_src, b.orig_sport, b.trans_src, b.trans_sport,
|
||||
));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: u32) -> bool {
|
||||
if let Some(idx) = self.rules.iter().position(|r| r.id == id) {
|
||||
self.rules.remove(idx);
|
||||
|
||||
Reference in New Issue
Block a user