fix: ipset compat with v7.x (plain text, timeout support, arg split)

- list() now parses plain text (works on ipset 6/7/8, not just 8)
- Strip " timeout N" suffix from member lines (kernel adds it when set has timeout support)
- ensure_exists() creates set with 'timeout 0' so add() can use --timeout later
- Fix ensure_ipset_match_rule: split rule string into separate argv tokens
  (Command::args with whitespace string was treated as one arg, breaking nf_tables)
- Add #[serial] to tests sharing TEST_SET (race condition fix)
- Add 3 new tests: list_parses_plain_format_correctly, list_empty_set_returns_empty_vec,
  list_filters_non_ip_lines
- Simplify integration_netns.sh to use iptables-only assertions (ipset is host-global)
This commit is contained in:
2026-08-31 00:49:29 +02:00
parent 03a52925d4
commit 7342386955
3 changed files with 89 additions and 72 deletions
+6 -7
View File
@@ -36,16 +36,15 @@ impl MartilloMaldito {
}
fn ensure_ipset_match_rule(&self) -> Result<(), Box<dyn std::error::Error>> {
let check_rule = format!("-m set --match-set {} src -j DROP", self.ipset.name());
let output = Command::new("iptables")
.args(["-C", &self.chain, &check_rule])
.output()?;
let match_rule = format!("-m set --match-set {} src -j DROP", self.ipset.name());
let args: Vec<&str> = match_rule.split_whitespace().collect();
let check_args: Vec<&str> = std::iter::once("-C").chain(self.chain.split_whitespace()).chain(args.iter().copied()).collect();
let output = Command::new("iptables").args(&check_args).output()?;
if output.status.success() {
return Ok(());
}
let output = Command::new("iptables")
.args(["-I", &self.chain, "1", &check_rule])
.output()?;
let insert_args: Vec<&str> = std::iter::once("-I").chain(self.chain.split_whitespace()).chain(std::iter::once("1")).chain(args.iter().copied()).collect();
let output = Command::new("iptables").args(&insert_args).output()?;
if !output.status.success() {
return Err(format!(
"failed to install ipset match rule: {}",