]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
cleanup firewall service implementation
[pve-firewall.git] / src / PVE / Firewall.pm
index ef54621a5d3a9455bb0bc60a3001b36dc46a9837..be5354c780799f02dfe184937481e921f1d7f6fb 100644 (file)
@@ -98,7 +98,6 @@ use Data::Dumper;
 my $nodename = PVE::INotify::nodename();
 
 my $pve_fw_lock_filename = "/var/lock/pvefw.lck";
-my $pve_fw_status_filename = "/var/lib/pve-firewall/pvefw.status";
 
 my $default_log_level = 'info';
 
@@ -1243,7 +1242,7 @@ sub ruleset_generate_cmdstr {
                die "invalid security group name '$dest'\n";
            }
        } elsif ($dest =~ m/^${ip_alias_pattern}$/){
-           my $alias = lc($source);
+           my $alias = lc($dest);
            my $e = $cluster_conf->{aliases}->{$alias};
            die "no such alias $dest" if !$e;
            push @cmd, "-d $e->{cidr}";
@@ -1476,6 +1475,26 @@ sub ruleset_create_vm_chain {
     }
 }
 
+sub ruleset_add_group_rule {
+    my ($ruleset, $cluster_conf, $chain, $rule, $direction, $action) = @_;
+
+    my $group = $rule->{action};
+    my $group_chain = "GROUP-$group-$direction";
+    if(!ruleset_chain_exist($ruleset, $group_chain)){
+       generate_group_rules($ruleset, $cluster_conf, $group);
+    }
+       
+    if ($direction eq 'OUT' && $rule->{iface_out}) {
+       ruleset_addrule($ruleset, $chain, "-o $rule->{iface_out} -j $group_chain");
+    } elsif ($direction eq 'IN' && $rule->{iface_in}) {
+       ruleset_addrule($ruleset, $chain, "-i $rule->{iface_in} -j $group_chain");
+    } else {
+       ruleset_addrule($ruleset, $chain, "-j $group_chain");
+    }
+
+    ruleset_addrule($ruleset, $chain, "-m mark --mark 1 -j $action");
+}
+
 sub ruleset_generate_vm_rules {
     my ($ruleset, $rules, $cluster_conf, $chain, $netid, $direction, $options) = @_;
 
@@ -1487,18 +1506,8 @@ sub ruleset_generate_vm_rules {
        next if $rule->{iface} && $rule->{iface} ne $netid;
        next if !$rule->{enable};
        if ($rule->{type} eq 'group') {
-           my $group_chain = "GROUP-$rule->{action}-$direction";
-           if(!ruleset_chain_exist($ruleset, $group_chain)){
-               generate_group_rules($ruleset, $cluster_conf, $rule->{action});
-           }
-           ruleset_addrule($ruleset, $chain, "-j $group_chain");
-           if ($direction eq 'OUT'){
-               ruleset_addrule($ruleset, $chain, "-m mark --mark 1 -j RETURN");
-           }else{
-               my $accept = generate_nfqueue($options);
-               ruleset_addrule($ruleset, $chain, "-m mark --mark 1 -j $accept");
-           }
-
+           ruleset_add_group_rule($ruleset, $cluster_conf, $chain, $rule, $direction,
+                                  $direction eq 'OUT' ? 'RETURN' : $in_accept);
        } else {
            next if $rule->{type} ne $lc_direction;
            eval {
@@ -1553,8 +1562,6 @@ sub ruleset_generate_vm_ipsrules {
 sub generate_venet_rules_direction {
     my ($ruleset, $cluster_conf, $hostfw_conf, $vmfw_conf, $vmid, $ip, $direction) = @_;
 
-    parse_address_list($ip); # make sure we have a valid $ip list
-
     my $lc_direction = lc($direction);
 
     my $rules = $vmfw_conf->{rules};
@@ -1665,9 +1672,14 @@ sub enable_host_firewall {
 
     # add host rules first, so that cluster wide rules can be overwritten
     foreach my $rule (@$rules, @$cluster_rules) {
-       next if $rule->{type} ne 'in';
        $rule->{iface_in} = $rule->{iface} if $rule->{iface};
-       ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, undef, $cluster_conf);
+       if ($rule->{type} eq 'group') {
+           ruleset_add_group_rule($ruleset, $cluster_conf, $chain, $rule, 'IN', $accept_action);
+       } elsif ($rule->{type} eq 'in') {
+           ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, 
+                                 undef, $cluster_conf);
+       }
+       delete $rule->{iface_in};
     }
 
     # implement input policy
@@ -1693,9 +1705,14 @@ sub enable_host_firewall {
 
     # add host rules first, so that cluster wide rules can be overwritten
     foreach my $rule (@$rules, @$cluster_rules) {
-       next if $rule->{type} ne 'out';
        $rule->{iface_out} = $rule->{iface} if $rule->{iface};
-       ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, undef, $cluster_conf);
+       if ($rule->{type} eq 'group') {
+           ruleset_add_group_rule($ruleset, $cluster_conf, $chain, $rule, 'OUT', $accept_action);
+       } elsif ($rule->{type} eq 'out') {
+           ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, 
+                                 undef, $cluster_conf);
+       }
+       delete $rule->{iface_out};
     }
 
     # implement output policy
@@ -1708,10 +1725,14 @@ sub enable_host_firewall {
 
 sub generate_group_rules {
     my ($ruleset, $cluster_conf, $group) = @_;
-    die "no such security group '$group'\n" if !$cluster_conf->{groups}->{$group};
 
     my $rules = $cluster_conf->{groups}->{$group};
 
+    if (!$rules) {
+       warn "no such security group '$group'\n";
+       $rules = []; # create empty chain
+    }
+
     my $chain = "GROUP-${group}-IN";
 
     ruleset_create_chain($ruleset, $chain);
@@ -2429,30 +2450,6 @@ sub round_powerof2 {
     return ++$int;
 }
 
-sub save_pvefw_status {
-    my ($status) = @_;
-
-    die "unknown status '$status' - internal error"
-       if $status !~ m/^(stopped|active)$/;
-
-    mkdir dirname($pve_fw_status_filename);
-    PVE::Tools::file_set_contents($pve_fw_status_filename, $status);
-}
-
-sub read_pvefw_status {
-
-    my $status = 'unknown';
-
-    return 'stopped' if ! -f $pve_fw_status_filename;
-
-    eval {
-       $status = PVE::Tools::file_get_contents($pve_fw_status_filename);
-    };
-    warn $@ if $@;
-
-    return $status;
-}
-
 sub load_clusterfw_conf {
     my ($filename) = @_;
 
@@ -2568,8 +2565,7 @@ sub compile {
     }
 
 
-    my $ipset_ruleset = {};
-    generate_ipset_chains($ipset_ruleset, $cluster_conf);
+    $cluster_conf->{ipset}->{venet0} = [];
 
     my $ruleset = {};
 
@@ -2586,8 +2582,8 @@ sub compile {
     ruleset_chain_add_conn_filters($ruleset, "PVEFW-FORWARD", "ACCEPT");
 
     ruleset_create_chain($ruleset, "PVEFW-VENET-OUT");
-    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i venet0 -j PVEFW-VENET-OUT");
-    ruleset_addrule($ruleset, "PVEFW-INPUT", "-i venet0 -j PVEFW-VENET-OUT");
+    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i venet0 -m set --match-set PVEFW-venet0 src -j PVEFW-VENET-OUT");
+    ruleset_addrule($ruleset, "PVEFW-INPUT", "-i venet0 -m set --match-set PVEFW-venet0 src -j PVEFW-VENET-OUT");
 
     ruleset_create_chain($ruleset, "PVEFW-FWBR-IN");
     ruleset_chain_add_input_filters($ruleset, "PVEFW-FWBR-IN", $hostfw_options, $cluster_conf, $loglevel);
@@ -2600,7 +2596,7 @@ sub compile {
     ruleset_create_chain($ruleset, "PVEFW-VENET-IN");
     ruleset_chain_add_input_filters($ruleset, "PVEFW-VENET-IN", $hostfw_options, $cluster_conf, $loglevel);
 
-    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o venet0 -j PVEFW-VENET-IN");
+    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o venet0 -m set --match-set PVEFW-venet0 dst -j PVEFW-VENET-IN");
 
     generate_std_chains($ruleset, $hostfw_options);
 
@@ -2608,7 +2604,7 @@ sub compile {
 
     enable_host_firewall($ruleset, $hostfw_conf, $cluster_conf) if $hostfw_enable;
 
-    ruleset_addrule($ruleset, "PVEFW-OUTPUT", "-o venet0 -j PVEFW-VENET-IN");
+    ruleset_addrule($ruleset, "PVEFW-OUTPUT", "-o venet0 -m set --match-set PVEFW-venet0 dst -j PVEFW-VENET-IN");
 
     # generate firewall rules for QEMU VMs
     foreach my $vmid (keys %{$vmdata->{qemu}}) {
@@ -2642,6 +2638,16 @@ sub compile {
        if ($conf->{ip_address} && $conf->{ip_address}->{value}) {
            my $ip = $conf->{ip_address}->{value};
            $ip =~ s/\s+/,/g;
+           parse_address_list($ip); # make sure we have a valid $ip list
+
+           my @ips = split(',', $ip);
+
+           foreach my $singleip (@ips) {
+               my $venet0ipset = {};
+               $venet0ipset->{cidr} = $singleip;
+               push @{$cluster_conf->{ipset}->{venet0}}, $venet0ipset;
+           }
+
            generate_venet_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $vmfw_conf, $vmid, $ip, 'IN');
            generate_venet_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $vmfw_conf, $vmid, $ip, 'OUT');
        }
@@ -2665,6 +2671,9 @@ sub compile {
        ruleset_insertrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate RELATED,ESTABLISHED -j PVEFW-IPS");
     }
 
+    my $ipset_ruleset = {};
+    generate_ipset_chains($ipset_ruleset, $cluster_conf);
+
     return ($ruleset, $ipset_ruleset);
 }
 
@@ -2935,7 +2944,7 @@ sub remove_pvefw_chains {
 }
 
 sub update {
-    my ($start, $verbose) = @_;
+    my ($verbose) = @_;
 
     my $code = sub {
 
@@ -2944,9 +2953,7 @@ sub update {
 
        my $enable = $cluster_options->{enable};
 
-       my $status = read_pvefw_status();
-
-       die "Firewall is disabled - cannot start\n" if !$enable && $start;
+       die "Firewall is disabled - cannot start\n" if !$enable;
 
        if (!$enable) {
            PVE::Firewall::remove_pvefw_chains();
@@ -2958,14 +2965,7 @@ sub update {
 
        my ($ruleset, $ipset_ruleset) = compile($cluster_conf, $hostfw_conf);
 
-       if ($start || $status eq 'active') {
-
-           save_pvefw_status('active') if ($status ne 'active');
-
-           apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $verbose);
-       } else {
-           print "Firewall not active (status = $status)\n" if $verbose;
-       }
+       apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $verbose);
     };
 
     run_locked($code);