From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox-firewall 2/2] firewall: add subcommands to proxmox-firewall binary
Date: Mon, 14 Apr 2025 17:44:54 +0200 [thread overview]
Message-ID: <20250414154455.274151-3-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20250414154455.274151-1-s.hanreich@proxmox.com>
pve-firewall supports several subcommands for starting / stopping the
firewall, as well as debugging. proxmox-firewall currently only ran in
foreground when executed and had no real means of dumping the
generated ruleset other than running it with log level trace and
capturing the log output.
The commands introduced in this patch series are:
* start - runs proxmox-firewall in foreground
* skeleton - prints the rule skeleton, included in the binary
* compile - prints the commands generated from the firewall
configuration files
For now, start retains the exact same behavior as the binary had
before introducing subcommands, so calling it with start as subcommand
is equivalent to invoking it without the start subcommand before.
The skeleton and compile subcommands can be used to dump the nftables
rules generated by proxmox-firewall. They print the ruleset in the
format expected by nft directly to STDOUT, so it can be piped to the
nft binary directly:
$ proxmox-firewall skeleton | nft -f -
$ proxmox-firewall compile | nft -j -f -
start always prints its logs to the journal, all other commands print
the logs to stderr. Since there isn't really a reason anymore to run
proxmox-firewall in the foreground via start (there are now specific
commands for debugging), this should be fine.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
debian/control | 1 +
debian/proxmox-firewall.service | 2 +-
proxmox-firewall/Cargo.toml | 2 +
proxmox-firewall/src/bin/proxmox-firewall.rs | 103 +++++++++++++++++--
4 files changed, 97 insertions(+), 11 deletions(-)
diff --git a/debian/control b/debian/control
index be6e584..15d9cad 100644
--- a/debian/control
+++ b/debian/control
@@ -7,6 +7,7 @@ Build-Depends: cargo:native,
librust-anyhow-1+default-dev,
librust-insta-1+default-dev (>= 1.21-~~),
librust-insta-1+json-dev (>= 1.21-~~),
+ librust-pico-args-0.5+default-dev,
librust-proxmox-log-0.2+default-dev (>= 0.2.9-~~),
librust-proxmox-sys-0.6+default-dev,
librust-proxmox-ve-config-dev (>= 0.2.3-~~),
diff --git a/debian/proxmox-firewall.service b/debian/proxmox-firewall.service
index ececa75..398670f 100644
--- a/debian/proxmox-firewall.service
+++ b/debian/proxmox-firewall.service
@@ -4,7 +4,7 @@ Wants=pve-cluster.service pvefw-logger.service
After=pvefw-logger.service pve-cluster.service network.target systemd-modules-load.service
[Service]
-ExecStart=/usr/libexec/proxmox/proxmox-firewall
+ExecStart=/usr/libexec/proxmox/proxmox-firewall start
Type=simple
[Install]
diff --git a/proxmox-firewall/Cargo.toml b/proxmox-firewall/Cargo.toml
index a7031a3..3302060 100644
--- a/proxmox-firewall/Cargo.toml
+++ b/proxmox-firewall/Cargo.toml
@@ -13,6 +13,8 @@ license = "AGPL-3"
[dependencies]
anyhow = "1"
+pico-args = "0.5"
+
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"
diff --git a/proxmox-firewall/src/bin/proxmox-firewall.rs b/proxmox-firewall/src/bin/proxmox-firewall.rs
index 70dca73..273daec 100644
--- a/proxmox-firewall/src/bin/proxmox-firewall.rs
+++ b/proxmox-firewall/src/bin/proxmox-firewall.rs
@@ -2,7 +2,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
-use anyhow::{Context, Error};
+use anyhow::{bail, format_err, Context, Error};
+use pico_args::Arguments;
use proxmox_firewall::config::{FirewallConfig, PveFirewallConfigLoader, PveNftConfigLoader};
use proxmox_firewall::firewall::Firewall;
@@ -10,6 +11,18 @@ use proxmox_log as log;
use proxmox_log::{LevelFilter, Logger};
use proxmox_nftables::{client::NftError, NftClient};
+const HELP: &str = r#"
+USAGE:
+ proxmox-firewall <COMMAND>
+
+COMMANDS:
+ help Prints this help message.
+ skeleton Prints the firewall rule skeleton as accepted by 'nft -f -'
+ compile Compile and print firewall rules as accepted by 'nft -j -f -'
+ start Execute proxmox-firewall service in foreground
+"#;
+
+
const RULE_BASE: &str = include_str!("../../resources/proxmox-firewall.nft");
const FORCE_DISABLE_FLAG_FILE: &str = "/run/proxmox-nftables-firewall-force-disable";
@@ -27,10 +40,13 @@ fn remove_firewall() -> Result<(), std::io::Error> {
Ok(())
}
-fn handle_firewall() -> Result<(), Error> {
+fn create_firewall_instance() -> Result<Firewall, Error> {
let config = FirewallConfig::new(&PveFirewallConfigLoader::new(), &PveNftConfigLoader::new())?;
+ Ok(Firewall::new(config))
+}
- let firewall = Firewall::new(config);
+fn handle_firewall() -> Result<(), Error> {
+ let firewall = create_firewall_instance()?;
if !firewall.is_enabled() {
return remove_firewall().with_context(|| "could not remove firewall tables".to_string());
@@ -55,15 +71,19 @@ fn handle_firewall() -> Result<(), Error> {
Ok(())
}
-fn init_logger() -> Result<(), Error> {
- Logger::from_env("PVE_LOG", LevelFilter::WARN)
- .journald()
- .init()
-}
+fn init_logger(command: Command) -> Result<(), Error> {
+ let mut logger = Logger::from_env("PVE_LOG", LevelFilter::WARN);
-fn main() -> Result<(), Error> {
- init_logger()?;
+ if command == Command::Start {
+ logger = logger.journald();
+ } else {
+ logger = logger.stderr_pve();
+ }
+
+ logger.init()
+}
+fn run_firewall() -> Result<(), Error> {
let term = Arc::new(AtomicBool::new(false));
signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&term))?;
@@ -97,3 +117,66 @@ fn main() -> Result<(), Error> {
remove_firewall()
.with_context(|| "Could not remove firewall rules")
}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Command {
+ Compile,
+ Help,
+ Skeleton,
+ Start,
+}
+
+impl std::str::FromStr for Command {
+ type Err = Error;
+
+ fn from_str(value: &str) -> Result<Self, Self::Err> {
+ Ok(match value {
+ "help" => Command::Help,
+ "compile" => Command::Compile,
+ "skeleton" => Command::Skeleton,
+ "start" => Command::Start,
+ cmd => {
+ bail!("{cmd} is not a valid command")
+ },
+ })
+ }
+}
+
+fn run_command(command: Command) -> Result<(), Error> {
+ init_logger(command)?;
+
+ match command {
+ Command::Help => {
+ println!("{}", HELP);
+ Ok(())
+ },
+ Command::Compile => {
+ let commands = create_firewall_instance()?.full_host_fw()?;
+ let json = serde_json::to_string_pretty(&commands)?;
+
+ println!("{json}");
+ Ok(())
+ },
+ Command::Skeleton => {
+ println!("{}", RULE_BASE);
+ Ok(())
+ },
+ Command::Start => run_firewall(),
+ }
+}
+
+fn main() -> Result<(), Error> {
+ let mut args = Arguments::from_env();
+
+ let parsed_command = args.subcommand()?
+ .ok_or_else(|| format_err!("no subcommand specified"))?
+ .parse();
+
+ if let Ok(command) = parsed_command {
+ run_command(command)
+ } else {
+ eprintln!("Invalid command specified!\n{}", HELP);
+ std::process::exit(1);
+ }
+
+}
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-04-14 15:45 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-14 15:44 [pve-devel] [PATCH docs/proxmox-firewall 0/3] migrate proxmox-firewall to proxmox-log + introduce subcommands Stefan Hanreich
2025-04-14 15:44 ` [pve-devel] [PATCH proxmox-firewall 1/2] firewall: use proxmox_log Stefan Hanreich
2025-04-14 15:44 ` Stefan Hanreich [this message]
2025-04-23 11:46 ` [pve-devel] [PATCH proxmox-firewall 2/2] firewall: add subcommands to proxmox-firewall binary Gabriel Goller
2025-04-14 15:44 ` [pve-devel] [PATCH pve-docs 1/1] firewall: update 'useful commands' section with new subcommands Stefan Hanreich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250414154455.274151-3-s.hanreich@proxmox.com \
--to=s.hanreich@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal