diff --git a/netstack/src/filter/table.rs b/netstack/src/filter/table.rs index ebdab4b930..e6512c7093 100644 --- a/netstack/src/filter/table.rs +++ b/netstack/src/filter/table.rs @@ -523,8 +523,48 @@ mod tests { assert_eq!(t.rules[0].match_count, 0, "reset_counters must clear rule.match_count"); assert_eq!(t.chain_counters.get(&Hook::InputLocal).copied().unwrap_or((0, 0)), (0, 0), - "reset_counters must clear chain_counters"); - assert_eq!(t.rules.len(), 1, - "reset_counters must preserve rules"); - } -} \ No newline at end of file + "reset_counters must clear chain_counters"); + assert_eq!(t.rules.len(), 1, + "reset_counters must preserve rules"); + } + + use proptest::prelude::*; + + proptest! { + #[test] + fn prop_filter_add_remove_roundtrip( + _id_seed in 0u32..1000u32, + hook_idx in 0usize..5, + verdict_idx in 0usize..4, + ) { + use crate::filter::rule::{Protocol, StateMatch}; + use crate::filter::{Hook, Verdict}; + let hook = [Hook::PreRouting, Hook::InputLocal, Hook::Forward, Hook::OutputLocal, Hook::PostRouting][hook_idx]; + let verdict = [Verdict::Accept, Verdict::Drop, Verdict::Log, Verdict::Reject][verdict_idx]; + let mut table = FilterTable::new(); + let rule = FilterRule { + id: 0, + hook, + src_addr: None, + src_prefix_len: 0, + dst_addr: None, + dst_prefix_len: 0, + protocol: None, + src_port: None, + dst_port: None, + in_dev: None, + out_dev: None, + state_match: None, + verdict, + match_count: 0, + }; + let _added_id = table.add(rule); + assert_eq!(table.rules.len(), 1, "rule was added"); + let id_to_remove = table.rules.iter().next().map(|r| r.id); + if let Some(id) = id_to_remove { + assert!(table.remove(id), "remove returns true for the added id"); + } + assert_eq!(table.rules.len(), 0, "remove clears the slot"); + } + } + } \ No newline at end of file