Skip to content

added firewall-reload command #1301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ docs: ## build the docs on the host
$(MAKE) -C docs

NV_UNIT_FILES = contrib/systemd/system/netavark-dhcp-proxy.service \
contrib/systemd/system/netavark-firewalld-reload.service
contrib/systemd/system/netavark-firewalld-reload.service \
contrib/systemd/system/netavark-nftables-reload.service

%.service: %.service.in
sed -e 's;@@NETAVARK@@;$(LIBEXECPODMAN)/netavark;g' $< >[email protected].$$ \
Expand All @@ -106,6 +107,7 @@ install: $(NV_UNIT_FILES)
install ${SELINUXOPT} -m 644 contrib/systemd/system/netavark-dhcp-proxy.socket ${DESTDIR}${SYSTEMDDIR}/netavark-dhcp-proxy.socket
install ${SELINUXOPT} -m 644 contrib/systemd/system/netavark-dhcp-proxy.service ${DESTDIR}${SYSTEMDDIR}/netavark-dhcp-proxy.service
install ${SELINUXOPT} -m 644 contrib/systemd/system/netavark-firewalld-reload.service ${DESTDIR}${SYSTEMDDIR}/netavark-firewalld-reload.service
install ${SELINUXOPT} -m 644 contrib/systemd/system/netavark-nftables-reload.service ${DESTDIR}${SYSTEMDDIR}/netavark-nftables-reload.service

.PHONY: uninstall
uninstall:
Expand Down
16 changes: 16 additions & 0 deletions contrib/systemd/system/netavark-nftables-reload.service.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Unit]
Description=Restore Netavark firewall rules after nftables service is reloaded
# This ensures our service is always started/restarted along with nftables.
# It also ensures this service is stopped if nftables is stopped.
PartOf=nftables.service
# This ensures nftables has finished starting before we run.
After=nftables.service

[Service]
Type=oneshot
# This uses the placeholder, which will be replaced by the Makefile during the build.
ExecStart=@@NETAVARK@@ firewall-reload

[Install]
# This tells systemd that this service should be enabled when nftables is enabled.
WantedBy=nftables.service
3 changes: 3 additions & 0 deletions rpm/netavark.spec
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,12 @@ cd docs
%preun
%systemd_preun %{name}-dhcp-proxy.service
%systemd_preun %{name}-firewalld-reload.service
%systemd_preun %{name}-nftables-reload.service

%postun
%systemd_postun %{name}-dhcp-proxy.service
%systemd_postun %{name}-firewalld-reload.service
%systemd_postun %{name}-nftables-reload.service

%files
%license LICENSE
Expand All @@ -136,6 +138,7 @@ cd docs
%{_unitdir}/%{name}-dhcp-proxy.service
%{_unitdir}/%{name}-dhcp-proxy.socket
%{_unitdir}/%{name}-firewalld-reload.service
%{_unitdir}/%{name}-nftables-reload.service

%changelog
%autochangelog
56 changes: 56 additions & 0 deletions src/commands/firewall_reload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::{
error::{ErrorWrap, NetavarkResult},
firewall::{get_supported_firewall_driver, state::read_fw_config},
network::constants,
};
use std::{
ffi::{OsStr, OsString},
path::Path,
};
use zbus::blocking::Connection;

pub fn firewall_reload(config_dir: Option<OsString>) -> NetavarkResult<()> {
// Set the path to the directory where Podman stores the container network state.
let config_dir = Path::new(
config_dir
.as_deref()
.unwrap_or(OsStr::new(constants::DEFAULT_CONFIG_DIR)), // path to the config dir mainatined by podman
);
log::debug!("looking for firewall configs in {config_dir:?}");

let conn = Connection::system().ok();

reload_rules(config_dir, &conn)?;

Ok(())
}

// This function is copied directly from firewalld_reload.rs.
fn reload_rules(config_dir: &Path, conn: &Option<Connection>) -> NetavarkResult<()> {
reload_rules_inner(config_dir, conn)?;
Ok(())
}

// This is the core logic, also copied directly.
fn reload_rules_inner(config_dir: &Path, conn: &Option<Connection>) -> NetavarkResult<()> {
// read_fw_config reads all the JSON files from `/run/containers/netavark/`
let conf = read_fw_config(config_dir).wrap("read firewall config")?;

// If there are no config files, there are no running containers, so we do nothing.
if let Some(conf) = conf {
// Get the appropriate firewall driver
let fw_driver = get_supported_firewall_driver(Some(conf.driver))?;

// Loop through each network configuration and restore its rules.
for net in conf.net_confs {
fw_driver.setup_network(net, conn)?;
}
// Loop through each container's port mappings and restore them.
for port in &conf.port_confs {
fw_driver.setup_port_forward(port.into(), conn)?;
}
log::info!("Successfully reloaded firewall rules");
}

Ok(())
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::ffi::OsString;
use crate::error::{NetavarkError, NetavarkResult};

pub mod dhcp_proxy;
pub mod firewall_reload;
pub mod firewalld_reload;
pub mod setup;
pub mod teardown;
Expand Down
5 changes: 5 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::ffi::OsString;
use clap::{Parser, Subcommand};

use netavark::commands::dhcp_proxy;
use netavark::commands::firewall_reload;
use netavark::commands::firewalld_reload;
use netavark::commands::setup;
use netavark::commands::teardown;
Expand Down Expand Up @@ -51,6 +52,9 @@ enum SubCommand {
/// Listen for the firewalld reload event and reload fw rules
#[command(name = "firewalld-reload")]
FirewallDReload,
// Re-applies firewall rules for all networks.
#[command(name = "firewall-reload")]
FirewallReload,
}

fn main() {
Expand Down Expand Up @@ -84,6 +88,7 @@ fn main() {
SubCommand::Version(version) => version.exec(),
SubCommand::DHCPProxy(proxy) => dhcp_proxy::serve(proxy),
SubCommand::FirewallDReload => firewalld_reload::listen(config),
SubCommand::FirewallReload => firewall_reload::firewall_reload(config),
};

match result {
Expand Down
30 changes: 30 additions & 0 deletions test/250-bridge-nftables.bats
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,36 @@ net/ipv4/conf/podman1/rp_filter = 2"
@test "$fw_driver - port forwarding ipv4 - tcp with firewalld reload" {
test_port_fw firewalld_reload=true
}
@test "$fw_driver - test firewall-reload" {
# setup a simple bridge network
run_netavark --file ${TESTSDIR}/testfiles/simplebridge.json setup $(get_container_netns_path)

# verify the rules are there initially
check_simple_bridge_nftables

# check that the firewall config files exist
net_id=$(jq -r '.network_info.podman.id' < "${TESTSDIR}/testfiles/simplebridge.json")
config_file="$NETAVARK_TMPDIR/config/firewall/networks/$net_id"
run_helper test -f "$config_file"
assert "$status" == "0" "network config file $config_file should exist"
# flush all nftables rules
run_in_host_netns nft flush ruleset

# verify the netavark table is gone
expected_rc=1 run_in_host_netns nft list table inet netavark
assert "$output" =~ "Error: No such file or directory" "netavark table should be gone"

# run firewall-reload to restore the rules
RUST_LOG=netavark=debug run_netavark firewall-reload
assert "$output" =~ "\[INFO netavark::commands::firewall_reload\] Successfully reloaded firewall rules" "firewall-reload success message"

# check that the rules are back
check_simple_bridge_nftables

# teardown the network
run_netavark --file ${TESTSDIR}/testfiles/simplebridge.json teardown $(get_container_netns_path)
}


function check_simple_bridge_nftables() {
# check nftables POSTROUTING chain
Expand Down