Добавлен fallback диагностики FORWARD через nft и расширен вывод status
This commit is contained in:
+120
-1
@@ -118,7 +118,7 @@ pub fn collect_port_path_diagnostics(
|
||||
let docker_userland_proxy = detect_userland_proxy().unwrap_or(TriState::Unknown);
|
||||
let published_udp_port = discover_published_udp_port(container_name, expected_udp_port).ok();
|
||||
let (host_forward_policy_drop, docker_forward_rules_present) =
|
||||
inspect_iptables_forward_state().unwrap_or((TriState::Unknown, TriState::Unknown));
|
||||
inspect_forward_state().unwrap_or((TriState::Unknown, TriState::Unknown));
|
||||
|
||||
PortPathDiagnostics {
|
||||
docker_userland_proxy,
|
||||
@@ -146,6 +146,42 @@ fn inspect_iptables_forward_state() -> anyhow::Result<(TriState, TriState)> {
|
||||
Ok(parse_forward_policy_and_docker_rules(&fwd))
|
||||
}
|
||||
|
||||
fn inspect_forward_state() -> anyhow::Result<(TriState, TriState)> {
|
||||
let iptables_state =
|
||||
inspect_iptables_forward_state().unwrap_or((TriState::Unknown, TriState::Unknown));
|
||||
let nft_state = inspect_nft_forward_state().unwrap_or((TriState::Unknown, TriState::Unknown));
|
||||
Ok(merge_forward_states(iptables_state, nft_state))
|
||||
}
|
||||
|
||||
fn inspect_nft_forward_state() -> anyhow::Result<(TriState, TriState)> {
|
||||
let ruleset = run_capture(&["nft", "list", "ruleset"])?;
|
||||
Ok(parse_nft_forward_policy_and_docker_rules(&ruleset))
|
||||
}
|
||||
|
||||
fn merge_forward_states(a: (TriState, TriState), b: (TriState, TriState)) -> (TriState, TriState) {
|
||||
(merge_policy_drop(a.0, b.0), merge_docker_rules(a.1, b.1))
|
||||
}
|
||||
|
||||
fn merge_policy_drop(a: TriState, b: TriState) -> TriState {
|
||||
if a == TriState::True || b == TriState::True {
|
||||
TriState::True
|
||||
} else if a == TriState::False || b == TriState::False {
|
||||
TriState::False
|
||||
} else {
|
||||
TriState::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_docker_rules(a: TriState, b: TriState) -> TriState {
|
||||
if a == TriState::True || b == TriState::True {
|
||||
TriState::True
|
||||
} else if a == TriState::False && b == TriState::False {
|
||||
TriState::False
|
||||
} else {
|
||||
TriState::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_userland_proxy_from_docker_info(raw: &str) -> TriState {
|
||||
let Ok(v) = serde_json::from_str::<Value>(raw) else {
|
||||
return TriState::Unknown;
|
||||
@@ -279,6 +315,34 @@ fn parse_forward_policy_and_docker_rules(raw: &str) -> (TriState, TriState) {
|
||||
(policy_drop, docker_rules)
|
||||
}
|
||||
|
||||
fn parse_nft_forward_policy_and_docker_rules(raw: &str) -> (TriState, TriState) {
|
||||
let nt = normalize_nft_forward_text(raw);
|
||||
|
||||
let policy_drop = if nt.contains("hook forward") && nt.contains("policy drop") {
|
||||
TriState::True
|
||||
} else if nt.contains("hook forward") && nt.contains("policy accept") {
|
||||
TriState::False
|
||||
} else {
|
||||
TriState::Unknown
|
||||
};
|
||||
|
||||
let docker_rules = if nt.contains("docker") && nt.contains("forward") {
|
||||
TriState::True
|
||||
} else {
|
||||
TriState::Unknown
|
||||
};
|
||||
|
||||
(policy_drop, docker_rules)
|
||||
}
|
||||
|
||||
fn normalize_nft_forward_text(raw: &str) -> String {
|
||||
raw.to_ascii_lowercase()
|
||||
.replace(['\n', '\t', '{', '}', ';', '"'], " ")
|
||||
.split_whitespace()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -432,6 +496,61 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nft_forward_policy_and_docker_rules_works() {
|
||||
let raw = r#"
|
||||
table inet docker_filter {
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy accept;
|
||||
jump DOCKER-USER
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
parse_nft_forward_policy_and_docker_rules(raw),
|
||||
(TriState::False, TriState::True)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nft_forward_policy_drop_detects_drop_forward_chain() {
|
||||
let raw = r#"
|
||||
table inet filter {
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
parse_nft_forward_policy_and_docker_rules(raw),
|
||||
(TriState::True, TriState::Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_forward_states_preserves_nft_docker_rules() {
|
||||
assert_eq!(
|
||||
merge_forward_states(
|
||||
(TriState::Unknown, TriState::Unknown),
|
||||
(TriState::False, TriState::True)
|
||||
),
|
||||
(TriState::False, TriState::True)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_forward_states_is_conservative_on_drop_policy() {
|
||||
assert_eq!(
|
||||
merge_forward_states(
|
||||
(TriState::True, TriState::Unknown),
|
||||
(TriState::False, TriState::True)
|
||||
),
|
||||
(TriState::True, TriState::True)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warning_is_emitted_for_risky_forward_state() {
|
||||
let diag = PortPathDiagnostics {
|
||||
|
||||
@@ -313,6 +313,8 @@ fn print_degraded_sections(cfg: &Config) -> anyhow::Result<()> {
|
||||
println!("Docker/Amnezia port path:");
|
||||
println!(" docker_userland_proxy: unknown");
|
||||
println!(" published_udp_port: unknown");
|
||||
println!(" host_forward_policy_drop: unknown");
|
||||
println!(" docker_forward_rules_present: unknown");
|
||||
println!(" note: FORWARD is Docker-managed; awg2-harness does not modify host FORWARD");
|
||||
|
||||
println!("Anti-torrent:");
|
||||
@@ -465,6 +467,14 @@ fn print_docker_amnezia_port_path(diag: &docker::PortPathDiagnostics) {
|
||||
),
|
||||
None => println!(" published_udp_port: unknown"),
|
||||
}
|
||||
println!(
|
||||
" host_forward_policy_drop: {}",
|
||||
diag.host_forward_policy_drop.as_str()
|
||||
);
|
||||
println!(
|
||||
" docker_forward_rules_present: {}",
|
||||
diag.docker_forward_rules_present.as_str()
|
||||
);
|
||||
println!(" note: FORWARD is Docker-managed; awg2-harness does not modify host FORWARD");
|
||||
if let Some(w) = diag.warning() {
|
||||
println!(" warning: {w}");
|
||||
|
||||
Reference in New Issue
Block a user