From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 186251FF142 for ; Tue, 07 Apr 2026 09:37:12 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 5AA07F1D6; Tue, 7 Apr 2026 09:37:36 +0200 (CEST) From: Arthur Bied-Charreton To: pve-devel@lists.proxmox.com Subject: [PATCH pve-firewall 1/5] Add helpers for updating alias and ipset references Date: Tue, 7 Apr 2026 09:36:54 +0200 Message-ID: <20260407073658.90818-2-a.bied-charreton@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260407073658.90818-1-a.bied-charreton@proxmox.com> References: <20260407073658.90818-1-a.bied-charreton@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.097 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: NN5CRASN3RIELM3YYSFZEFGLVHLPNUD7 X-Message-ID-Hash: NN5CRASN3RIELM3YYSFZEFGLVHLPNUD7 X-MailFrom: abied-charreton@jett.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Both ipsets and aliases require similar logic, where we need to be able to iterate over all firewall configs in the cluster (cluster, nodes and guests) to find and update all references to a given object. Add filter_map() and foreach_conf_in_env() as shared helpers that take closures, allowing the ipset and alias handlers to reuse some of the traversal logic. Signed-off-by: Arthur Bied-Charreton --- src/PVE/API2/Firewall/Helpers.pm | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/PVE/API2/Firewall/Helpers.pm b/src/PVE/API2/Firewall/Helpers.pm index 0fb71f7..8a8759a 100644 --- a/src/PVE/API2/Firewall/Helpers.pm +++ b/src/PVE/API2/Firewall/Helpers.pm @@ -4,8 +4,74 @@ use strict; use warnings; use PVE::Cluster; +use PVE::Firewall; use PVE::Network::SDN::Vnets; use PVE::RPCEnvironment; +use base 'Exporter'; +our @EXPORT_OK = qw(filter_map foreach_conf_in_env); + +# Apply $action to each item in $items for which $matches->($item) is true. Remove item +# if $matches->($item) is true and $action->($item) returns undef. +# +# Returns the updated items arrayref and a boolean indicating whether any item was matched. +sub filter_map { + my ($items, $action, $matches) = @_; + my @result; + my $modified = 0; + for my $item (@{ $items // [] }) { + if ($matches->($item)) { + $modified = 1; + my $new = $action->($item); + push @result, $new if defined $new; + } else { + push @result, $item; + } + } + return (\@result, $modified); +} + +# Apply $rewrite to the main firewall config and, if $rule_env is 'cluster', to all guest +# and host firewall configs across the cluster. Configs where $rewrite returns true are saved. +# The caller is responsible for locking and saving the cluster config. Guest and host +# configs are locked by this function. +sub foreach_conf_in_env { + my ($conf, $rule_env, $rewrite) = @_; + + $rewrite->($conf, $rule_env, 0); + + return if $rule_env ne 'cluster'; + + my $vmlist = PVE::Cluster::get_vmlist(); + for my $vmid (keys %{ ($vmlist // {})->{ids} // {} }) { + PVE::Firewall::lock_vmfw_conf( + $vmid, + 10, + sub { + my $type = $vmlist->{ids}->{$vmid}->{type}; + my $env = $type eq 'lxc' ? 'ct' : 'vm'; + my $guest_conf = PVE::Firewall::load_vmfw_conf($conf, $env, $vmid); + if ($rewrite->($guest_conf, 'cluster', 1)) { + PVE::Firewall::save_vmfw_conf($vmid, $guest_conf); + } + }, + ); + } + + for my $node (@{ PVE::Cluster::get_nodelist() }) { + my $host_conf_path = "/etc/pve/nodes/$node/host.fw"; + PVE::Firewall::lock_hostfw_conf( + $node, + 10, + sub { + my $host_conf = PVE::Firewall::load_hostfw_conf($conf, $host_conf_path); + return if !defined($host_conf); + if ($rewrite->($host_conf, 'cluster', 0)) { + PVE::Firewall::save_hostfw_conf($host_conf, $host_conf_path); + } + }, + ); + } +} sub get_allowed_vnets { my $rpcenv = eval { PVE::RPCEnvironment::get() }; -- 2.47.3