X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FFirewall.pm;h=296ec8c55823d686f516dc1b466262f03dd1f63f;hp=74bd8d962eaad4868b0bcaaa9449c568e58a1f63;hb=30f1b1001966ca16048dfe294dd5f91d93aa6eba;hpb=9d6f90e67337dde709a2482b44d2003d15be1a84 diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 74bd8d9..296ec8c 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -10,7 +10,7 @@ use PVE::Exception qw(raise raise_param_exc); use PVE::JSONSchema qw(get_standard_option); use PVE::Cluster; use PVE::ProcFSTools; -use PVE::Tools; +use PVE::Tools qw($IPV4RE); use File::Basename; use File::Path; use IO::File; @@ -35,6 +35,20 @@ eval { $have_pve_manager = 1; }; +PVE::JSONSchema::register_format('IPv4orCIDR', \&pve_verify_ipv4_or_cidr); +sub pve_verify_ipv4_or_cidr { + my ($cidr, $noerr) = @_; + + if ($cidr =~ m!^(?:$IPV4RE)(/(\d+))?$!) { + return $cidr if Net::IP->new($cidr); + return undef if $noerr; + die Net::IP::Error() . "\n"; + } + return undef if $noerr; + die "value does not look like a valid IP address or CIDR network\n"; +} + + my $feature_ipset_nomatch = 0; eval { my (undef, undef, $release) = POSIX::uname(); @@ -2008,15 +2022,15 @@ sub parse_cluster_fw_rules { # we can add single line comments to the end of the rule my $comment = decode('utf8', $1) if $line =~ s/#\s*(.*?)\s*$//; - $line =~ m/^(\!)?\s*((?:\d+)\.(?:\d+)\.(?:\d+)\.(?:\d+))(?:\/(\d+))?\s*$/; + $line =~ m/^(\!)?\s*(\S+)\s*$/; my $nomatch = $1; my $cidr = $2; - $cidr .= "/$3" if defined($3) && $3 != 32; - - if (!Net::IP->new($cidr)) { - my $err = Net::IP::Error(); - warn "$prefix: $cidr - $err\n"; + $cidr =~ s|/32$||; + + eval { pve_verify_ipv4_or_cidr($cidr); }; + if (my $err = $@) { + warn "$prefix: $cidr - $err"; next; } @@ -2143,7 +2157,13 @@ my $format_ipset = sub { my $raw = ''; + my $nethash = {}; foreach my $entry (@$options) { + $nethash->{$entry->{cidr}} = $entry; + } + + foreach my $cidr (sort keys %$nethash) { + my $entry = $nethash->{$cidr}; my $line = $entry->{nomatch} ? '!' : ''; $line .= $entry->{cidr}; $line .= " # " . encode('utf8', $entry->{comment}) @@ -2253,8 +2273,15 @@ sub generate_ipset { push @{$ipset_ruleset->{$name}}, "create $name hash:net family inet hashsize $hashsize maxelem $hashsize"; + # remove duplicates + my $nethash = {}; foreach my $entry (@$options) { - my $cidr = $entry->{cidr}; + $nethash->{$entry->{cidr}} = $entry; + } + + foreach my $cidr (sort keys %$nethash) { + my $entry = $nethash->{$cidr}; + my $cmd = "add $name $cidr"; if ($entry->{nomatch}) { if ($feature_ipset_nomatch) { @@ -2630,6 +2657,13 @@ sub get_ipset_cmdlist { my $active_chains = ipset_get_chains(); my $statushash = get_ruleset_status($ruleset, $active_chains, \&ipset_chain_digest, $verbose); + # remove stale _swap chains + foreach my $chain (keys %$active_chains) { + if ($chain =~ m/^PVEFW-\S+_swap$/) { + $cmdlist .= "destroy $chain\n"; + } + } + foreach my $chain (sort keys %$ruleset) { my $stat = $statushash->{$chain}; die "internal error" if !$stat;