default => 0,
optional => 1
},
+ nftables => {
+ description => "Enable nftables based firewall (tech preview)",
+ type => 'boolean',
+ default => 0,
+ optional => 1,
+ },
};
our $vm_option_properties = {
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack|nf_conntrack_allow_invalid|protection_synflood):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack|nf_conntrack_allow_invalid|protection_synflood|nftables):\s*(0|1)\s*$/i) {
$opt = lc($1);
$value = int($2);
} elsif ($line =~ m/^(log_level_in|log_level_out|tcp_flags_log_level|smurf_log_level):\s*(($loglevels)\s*)?$/i) {
sub resolve_alias {
my ($clusterfw_conf, $fw_conf, $cidr, $scope) = @_;
+ # When we're on the cluster level, the cluster config only gets
+ # saved into fw_conf, so we need some extra handling here (to
+ # stay consistent)
+ my ($cluster_config, $local_config);
+ if (!$clusterfw_conf) {
+ ($cluster_config, $local_config) = ($fw_conf, undef);
+ } else {
+ ($cluster_config, $local_config) = ($clusterfw_conf, $fw_conf);
+ }
+
my $alias = lc($cidr);
my $e;
- if ($scope ne 'dc/' && $fw_conf) {
- $e = $fw_conf->{aliases}->{$alias};
+ if ($scope ne 'dc/' && $local_config) {
+ $e = $local_config->{aliases}->{$alias};
}
- if ($scope ne 'guest/' && !$e && $clusterfw_conf) {
- $e = $clusterfw_conf->{aliases}->{$alias};
+ if ($scope ne 'guest/' && !$e && $cluster_config) {
+ $e = $cluster_config->{aliases}->{$alias};
}
die "no such alias '$cidr'\n" if !$e;;
my $raw = '';
$raw .= "[ALIASES]\n\n";
- foreach my $k (keys %$aliases) {
+ foreach my $k (sort keys %$aliases) {
my $e = $aliases->{$k};
$raw .= "$e->{name} $e->{cidr}";
$raw .= " # " . encode('utf8', $e->{comment})
ebtables_restore_cmdlist(get_ebtables_cmdlist({}));
}
-sub init {
- my $cluster_conf = load_clusterfw_conf();
- my $cluster_options = $cluster_conf->{options};
- my $enable = $cluster_options->{enable};
+sub is_nftables {
+ my ($cluster_conf, $host_conf) = @_;
- return if !$enable;
+ if (!-x "/usr/libexec/proxmox/proxmox-firewall") {
+ return 0;
+ }
+
+ $cluster_conf = load_clusterfw_conf() if !defined($cluster_conf);
+ $host_conf = load_hostfw_conf($cluster_conf) if !defined($host_conf);
+
+ return $host_conf->{options}->{nftables};
+}
+
+sub is_enabled_and_not_nftables {
+ my ($cluster_conf, $host_conf) = @_;
+
+ $cluster_conf = load_clusterfw_conf() if !defined($cluster_conf);
+ $host_conf = load_hostfw_conf($cluster_conf) if !defined($host_conf);
+
+ return $cluster_conf->{options}->{enable} && !is_nftables($cluster_conf, $host_conf);
+}
+
+sub init {
+ return if !is_enabled_and_not_nftables();
# load required modules here
}
+# This is checked in proxmox-firewall to avoid log-spam due to failing to parse the config
+my $FORCE_NFT_DISABLE_FLAG_FILE = "/run/proxmox-nftables-firewall-force-disable";
+
sub update {
my $code = sub {
my $cluster_conf = load_clusterfw_conf();
- my $cluster_options = $cluster_conf->{options};
+ my $hostfw_conf = load_hostfw_conf($cluster_conf);
- if (!$cluster_options->{enable}) {
+ if (!is_enabled_and_not_nftables($cluster_conf, $hostfw_conf)) {
+ unlink($FORCE_NFT_DISABLE_FLAG_FILE)
+ or $!{ENOENT} or warn "failed to unlink flag file '$FORCE_NFT_DISABLE_FLAG_FILE' - $!\n";
PVE::Firewall::remove_pvefw_chains();
return;
}
+ if (! -e $FORCE_NFT_DISABLE_FLAG_FILE) {
+ open(my $_fh, '>', $FORCE_NFT_DISABLE_FLAG_FILE)
+ or warn "failed to create flag file '$FORCE_NFT_DISABLE_FLAG_FILE' – $!\n";
+ }
- my $hostfw_conf = load_hostfw_conf($cluster_conf);
my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = compile($cluster_conf, $hostfw_conf);