From 36600c0a5a6c79e0df5418e38fd3c3226f42309a Mon Sep 17 00:00:00 2001 From: Crimson Date: Mon, 11 May 2026 18:45:17 +0500 Subject: [PATCH] =?UTF-8?q?fix10:=20=D1=81=D1=82=D0=B0=D0=B1=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20host=20firewall=20first-?= =?UTF-8?q?run=20=D0=B8=20no-op=20reconcile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - исправлен first-run дефект: delete table вынесен из nft batch\n- добавлен no-op путь при отсутствии host firewall drift\n- исправлен trim для default_input_policy в drift-check\n- добавлены тесты для batch script и policy trim\n- уточнен release-gate в acceptance checklist по INPUT/FORWARD --- docs/ACCEPTANCE_CHECKLIST.md | 1 + traffic_core/src/firewall.rs | 122 ++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 3 deletions(-) diff --git a/docs/ACCEPTANCE_CHECKLIST.md b/docs/ACCEPTANCE_CHECKLIST.md index 160db89..51ca181 100644 --- a/docs/ACCEPTANCE_CHECKLIST.md +++ b/docs/ACCEPTANCE_CHECKLIST.md @@ -128,6 +128,7 @@ - [ ] При невалидном `host_firewall.amnezia_protocols` (`icmp`, `foo`, дубли) `validate-config` завершается ошибкой. - [ ] После `docker restart` anti-torrent правила продолжают восстанавливаться корректно и не ломаются host firewall логикой. - [ ] Проверено, где реально проходит VPN-трафик в вашей Docker-схеме (`INPUT` vs `FORWARD`) и это отражено в эксплуатационной заметке. +- [ ] Для release-кандидата зафиксирован итог проверки `INPUT` vs `FORWARD` на реальном сервере (команды/логи/вывод) и подтверждено, что текущие правила firewall покрывают реальный путь трафика. ## K. Packaging / release diff --git a/traffic_core/src/firewall.rs b/traffic_core/src/firewall.rs index edf998c..dfe3fb2 100644 --- a/traffic_core/src/firewall.rs +++ b/traffic_core/src/firewall.rs @@ -121,12 +121,21 @@ fn apply_host_firewall(cfg: &Config) -> anyhow::Result<()> { return Ok(()); } + if host_firewall_drift_reason(cfg)?.is_none() { + return Ok(()); + } + let policy = cfg .host_firewall .default_input_policy .trim() .to_ascii_lowercase(); + run_allow_notfound( + transport.as_ref(), + &["nft", "delete", "table", "inet", HOST_FW_TABLE], + )?; + apply_host_firewall_batch(cfg, &policy)?; if let Some(reason) = host_firewall_drift_reason(cfg)? { @@ -136,8 +145,12 @@ fn apply_host_firewall(cfg: &Config) -> anyhow::Result<()> { } fn apply_host_firewall_batch(cfg: &Config, policy: &str) -> anyhow::Result<()> { + let batch = build_host_firewall_batch_script(cfg, policy); + run_nft_batch(&batch) +} + +fn build_host_firewall_batch_script(cfg: &Config, policy: &str) -> String { let mut batch = String::new(); - batch.push_str(&format!("delete table inet {HOST_FW_TABLE}\n")); batch.push_str(&format!("add table inet {HOST_FW_TABLE}\n")); batch.push_str(&format!( "add chain inet {HOST_FW_TABLE} input {{ type filter hook input priority filter; policy accept; }}\n" @@ -170,7 +183,7 @@ fn apply_host_firewall_batch(cfg: &Config, policy: &str) -> anyhow::Result<()> { batch.push_str(&format!( "set chain inet {HOST_FW_TABLE} input {{ policy {policy}; }}\n" )); - run_nft_batch(&batch) + batch } fn run_nft_batch(script: &str) -> anyhow::Result<()> { @@ -296,7 +309,10 @@ fn host_firewall_drift_reason_from_text(nt: &str, cfg: &Config) -> Option