|
1 | 1 | use super::{FirewallArguments, FirewallPolicy};
|
2 | 2 | use ipnetwork::IpNetwork;
|
3 | 3 | use pfctl::{DropAction, FilterRuleAction, Uid};
|
| 4 | +use std::process::Stdio; |
4 | 5 | use std::{
|
5 | 6 | env,
|
6 | 7 | net::{IpAddr, Ipv4Addr},
|
@@ -49,7 +50,13 @@ impl Firewall {
|
49 | 50 | pub fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> {
|
50 | 51 | self.enable()?;
|
51 | 52 | self.add_anchor()?;
|
52 |
| - self.set_rules(policy) |
| 53 | + self.set_rules(policy)?; |
| 54 | + |
| 55 | + // When entering a secured state, clear connection states |
| 56 | + // Otherwise, an existing connection may be approved by some other anchor, and leak |
| 57 | + clear_all_states(); |
| 58 | + |
| 59 | + Ok(()) |
53 | 60 | }
|
54 | 61 |
|
55 | 62 | pub fn reset_policy(&mut self) -> Result<()> {
|
@@ -668,3 +675,24 @@ enum RuleLogging {
|
668 | 675 | Drop,
|
669 | 676 | All,
|
670 | 677 | }
|
| 678 | + |
| 679 | +/// Clear all PF connection states by calling 'pfctl -F rules'. This could be done more nicely |
| 680 | +/// using the `DIOCKILLSTATES` or `DIOCCLRSTATES` ioctl. |
| 681 | +/// |
| 682 | +/// See http://man.openbsd.org/pf.4, `DIOCKILLSTATES`, and `DIOCCLRSTATES` for more info. |
| 683 | +fn clear_all_states() { |
| 684 | + let status = std::process::Command::new("/sbin/pfctl") |
| 685 | + .args(["-F", "states"]) |
| 686 | + .stdout(Stdio::null()) |
| 687 | + .stderr(Stdio::null()) |
| 688 | + .status(); |
| 689 | + match status { |
| 690 | + Ok(status) if status.success() => (), |
| 691 | + Ok(status) => { |
| 692 | + log::error!("Failed to clear PF states. pfctl failed: {status}"); |
| 693 | + } |
| 694 | + Err(error) => { |
| 695 | + log::error!("Failed to clear PF states: {error}"); |
| 696 | + } |
| 697 | + } |
| 698 | +} |
0 commit comments