]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
avoid calls to iptables_rule_exist()
[pve-firewall.git] / src / PVE / Firewall.pm
index 02c602fe17c037ebc6840612066ce6268e07b3f2..8ba1ba9bad89ab273e9b2b5da60f1f0d1ba4366a 100644 (file)
@@ -833,6 +833,8 @@ sub iptables_get_chains {
 
     my $table = '';
 
+    my $hooks = {};
+
     my $parser = sub {
        my $line = shift;
 
@@ -854,6 +856,8 @@ sub iptables_get_chains {
            my ($chain, $sig) = ($1, $2);
            return if !&$is_pvefw_chain($chain);
            $res->{$chain} = $sig;
+       } elsif ($line =~ m/^-A\s+(INPUT|OUTPUT|FORWARD)\s+-j\s+PVEFW-\1$/) {
+           $hooks->{$1} = 1;
        } else {
            # simply ignore the rest
            return;
@@ -862,11 +866,21 @@ sub iptables_get_chains {
 
     run_command("/sbin/iptables-save", outfunc => $parser);
 
-    return $res;
+    return wantarray ? ($res, $hooks) : $res;
+}
+
+sub iptables_chain_digest {
+    my ($rules) = @_;
+    my $digest = Digest::SHA->new('sha1');
+    foreach my $rule (@$rules) { # order is important
+       $digest->add($rule);
+    }
+    return $digest->b64digest;
 }
 
 sub ipset_chain_digest {
     my ($rules) = @_;
+
     my $digest = Digest::SHA->new('sha1');
     foreach my $rule (sort @$rules) { # note: sorted
        $digest->add($rule);
@@ -1770,7 +1784,7 @@ sub parse_cluster_fw_rules {
     my $section;
     my $group;
 
-    my $res = { rules => {}, options => {}, groups => {}, ipset => {} };
+    my $res = { rules => [], options => {}, groups => {}, ipset => {} };
 
     my $digest = Digest::SHA->new('sha1');
 
@@ -2245,19 +2259,13 @@ sub compile {
 }
 
 sub get_ruleset_status {
-    my ($ruleset, $verbose, $ipset) = @_;
-
-    my $active_chains = undef;
-    if($ipset){
-       $active_chains = ipset_get_chains();
-    }else{
-       $active_chains = iptables_get_chains();
-    }
+    my ($ruleset, $active_chains, $digest_fn, $verbose) = @_;
 
     my $statushash = {};
 
     foreach my $chain (sort keys %$ruleset) {
-       my $sig = ipset_chain_digest($ruleset->{$chain});
+       my $sig = &$digest_fn($ruleset->{$chain});
+
        $statushash->{$chain}->{sig} = $sig;
 
        my $oldsig = $active_chains->{$chain};
@@ -2295,12 +2303,13 @@ sub print_sig_rule {
     return "-A $chain -m comment --comment \"PVESIG:$sig\"\n";
 }
 
-sub get_rulset_cmdlist {
+sub get_ruleset_cmdlist {
     my ($ruleset, $verbose) = @_;
 
     my $cmdlist = "*filter\n"; # we pass this to iptables-restore;
-
-    my $statushash = get_ruleset_status($ruleset, $verbose);
+    my ($active_chains, $hooks) = iptables_get_chains();
+    my $statushash = get_ruleset_status($ruleset, $active_chains, \&iptables_chain_digest, $verbose);
 
     # create missing chains first
     foreach my $chain (sort keys %$ruleset) {
@@ -2311,18 +2320,10 @@ sub get_rulset_cmdlist {
        $cmdlist .= ":$chain - [0:0]\n";
     }
 
-    my $rule = "INPUT -j PVEFW-INPUT";
-    if (!PVE::Firewall::iptables_rule_exist($rule)) {
-       $cmdlist .= "-A $rule\n";
-    }
-    $rule = "OUTPUT -j PVEFW-OUTPUT";
-    if (!PVE::Firewall::iptables_rule_exist($rule)) {
-       $cmdlist .= "-A $rule\n";
-    }
-
-    $rule = "FORWARD -j PVEFW-FORWARD";
-    if (!PVE::Firewall::iptables_rule_exist($rule)) {
-       $cmdlist .= "-A $rule\n";
+    foreach my $h (qw(INPUT OUTPUT FORWARD)) {
+       if (!$hooks->{$h}) {
+           $cmdlist .= "-A $h -j PVEFW-$h\n";
+       }
     }
 
     foreach my $chain (sort keys %$ruleset) {
@@ -2357,7 +2358,7 @@ sub get_rulset_cmdlist {
     }
 
     my $changes = $cmdlist ne "*filter\n" ? 1 : 0;
+
     $cmdlist .= "COMMIT\n";
 
     return wantarray ? ($cmdlist, $changes) : $cmdlist;
@@ -2368,7 +2369,8 @@ sub get_ipset_cmdlist {
 
     my $cmdlist = "";
 
-    my $statushash = get_ruleset_status($ruleset, $verbose, 1);
+    my $active_chains = ipset_get_chains();
+    my $statushash = get_ruleset_status($ruleset, $active_chains, \&ipset_chain_digest, $verbose);
 
     foreach my $chain (sort keys %$ruleset) {
        my $stat = $statushash->{$chain};
@@ -2416,7 +2418,7 @@ sub apply_ruleset {
 
     my $ipsetcmdlist = get_ipset_cmdlist($ipset_ruleset, $verbose);
 
-    my $cmdlist = get_rulset_cmdlist($ruleset, $verbose);
+    my $cmdlist = get_ruleset_cmdlist($ruleset, $verbose);
 
     print $ipsetcmdlist if $verbose;
 
@@ -2427,7 +2429,8 @@ sub apply_ruleset {
     iptables_restore_cmdlist($cmdlist);
 
     # test: re-read status and check if everything is up to date
-    my $statushash = get_ruleset_status($ruleset);
+    my $active_chains = iptables_get_chains();
+    my $statushash = get_ruleset_status($ruleset, $active_chains, \&iptables_chain_digest, $verbose);
 
     my $errors;
     foreach my $chain (sort keys %$ruleset) {
@@ -2465,6 +2468,29 @@ sub update_nf_conntrack_max {
     }
 }
 
+sub remove_pvefw_chains {
+
+    my ($chash, $hooks) = iptables_get_chains();
+    my $cmdlist = "*filter\n";
+
+    foreach my $h (qw(INPUT OUTPUT FORWARD)) {
+       if ($hooks->{$h}) {
+           $cmdlist .= "-D $h -j PVEFW-$h\n";
+       }
+    }
+    foreach my $chain (keys %$chash) {
+       $cmdlist .= "-F $chain\n";
+    }
+
+    foreach my $chain (keys %$chash) {
+       $cmdlist .= "-X $chain\n";
+    }
+    $cmdlist .= "COMMIT\n";
+
+    iptables_restore_cmdlist($cmdlist);
+}
+
 sub update {
     my ($start, $verbose) = @_;