]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
Introduce new management ipset
[pve-firewall.git] / src / PVE / Firewall.pm
index 49ea0c0f49dc03e1767ae1b85c89aac7e5620a4d..be81778c97d8f5503c2dcca5421fe5055c6f6eba 100644 (file)
@@ -705,11 +705,14 @@ my $ipv4_mask_hash_clusternet = {
     '255.255.255.252' => 30,
 };
 
-my $cluster_network;
+my $__cluster_network;
 
-sub get_cluster_network {
+sub cluster_network {
+    my ($new_value) = @_;
 
-    return $cluster_network if defined($cluster_network);
+    $__cluster_network = $new_value if defined($new_value);
+
+    return $__cluster_network if defined($__cluster_network);
 
     eval {
        my $nodename = PVE::INotify::nodename();
@@ -726,14 +729,14 @@ sub get_cluster_network {
            my $cidr = "$entry->{dest}/$mask";
            my $testnet = Net::IP->new($cidr);
            if ($testnet->overlaps($testip)) {
-               $cluster_network = $cidr;
+               $__cluster_network = $cidr;
                return;
            }
        }
     };
     warn $@ if $@;
 
-    return $cluster_network;
+    return $__cluster_network;
 }
 
 sub parse_address_list {
@@ -1684,20 +1687,6 @@ sub enable_host_firewall {
     ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
     ruleset_chain_add_input_filters($ruleset, $chain, $options, $cluster_conf, $loglevel);
 
-    my $clusternet = get_cluster_network();
-
-    if ($clusternet) {
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -p tcp --dport 8006 -j ACCEPT");  # PVE API
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -p tcp --dport 5900:5999 -j ACCEPT");  # PVE VNC Console 
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -p tcp --dport 3128 -j ACCEPT");  # SPICE Proxy
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -p tcp --dport 22 -j ACCEPT");  # SSH
-       # corosync
-       my $corosync_rule = "-p udp -m conntrack --ctstate NEW --dport 5404:5405 -j ACCEPT"
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -d $clusternet $corosync_rule");
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -m addrtype --dst-type MULTICAST $corosync_rule");
-    }
-
     # we use RETURN because we need to check also tap rules
     my $accept_action = 'RETURN';
 
@@ -1713,6 +1702,22 @@ sub enable_host_firewall {
        delete $rule->{iface_in};
     }
 
+    # allow standard traffic for management ipset (includes cluster network)
+    my $mngmntsrc = "-m set --match-set PVEFW-management src";
+    ruleset_addrule($ruleset, $chain, "$mngmntsrc -p tcp --dport 8006 -j $accept_action");  # PVE API
+    ruleset_addrule($ruleset, $chain, "$mngmntsrc -p tcp --dport 5900:5999 -j $accept_action");  # PVE VNC Console 
+    ruleset_addrule($ruleset, $chain, "$mngmntsrc -p tcp --dport 3128 -j $accept_action");  # SPICE Proxy
+    ruleset_addrule($ruleset, $chain, "$mngmntsrc -p tcp --dport 22 -j $accept_action");  # SSH
+   
+    my $clusternet = cluster_network();
+
+    # corosync
+    if ($clusternet) {
+       my $corosync_rule = "-p udp --dport 5404:5405 -j $accept_action";
+       ruleset_addrule($ruleset, $chain, "-s $clusternet -d $clusternet $corosync_rule");
+       ruleset_addrule($ruleset, $chain, "-s $clusternet -m addrtype --dst-type MULTICAST $corosync_rule");
+    }
+
     # implement input policy
     my $policy = $cluster_options->{policy_in} || 'DROP'; # allow nothing by default
     ruleset_add_chain_policy($ruleset, $chain, 0, $policy, $loglevel, $accept_action);
@@ -1727,12 +1732,6 @@ sub enable_host_firewall {
 
     ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
 
-    if ($clusternet) {
-       my $corosync_rule = "-p udp -m conntrack --ctstate NEW --dport 5404:5405 -j ACCEPT";
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -d $clusternet $corosync_rule");
-       ruleset_addrule($ruleset, $chain, "-s $clusternet -m addrtype --dst-type MULTICAST $corosync_rule");
-    }
-
     # we use RETURN because we may want to check other thigs later
     $accept_action = 'RETURN';
 
@@ -1748,6 +1747,18 @@ sub enable_host_firewall {
        delete $rule->{iface_out};
     }
 
+    # allow standard traffic on cluster network
+    if ($clusternet) {
+       ruleset_addrule($ruleset, $chain, "-d $clusternet -p tcp --dport 8006 -j $accept_action");  # PVE API
+       ruleset_addrule($ruleset, $chain, "-d $clusternet -p tcp --dport 22 -j $accept_action");  # SSH
+       ruleset_addrule($ruleset, $chain, "-d $clusternet -p tcp --dport 5900:5999 -j $accept_action");  # PVE VNC Console 
+       ruleset_addrule($ruleset, $chain, "-d $clusternet -p tcp --dport 3128 -j $accept_action");  # SPICE Proxy
+       my $corosync_rule = "-p udp --dport 5404:5405 -j $accept_action";
+       ruleset_addrule($ruleset, $chain, "-d $clusternet $corosync_rule");
+       ruleset_addrule($ruleset, $chain, "-m addrtype --dst-type MULTICAST $corosync_rule");
+    }
+
     # implement output policy
     $policy = $cluster_options->{policy_out} || 'ACCEPT'; # allow everything by default
     ruleset_add_chain_policy($ruleset, $chain, 0, $policy, $loglevel, $accept_action);
@@ -1961,7 +1972,7 @@ sub parse_clusterfw_option {
     return ($opt, $value);
 }
 
-sub parse_clusterfw_alias {
+sub parse_alias {
     my ($line) = @_;
 
     # we can add single line comments to the end of the line
@@ -1985,7 +1996,11 @@ sub parse_clusterfw_alias {
 sub parse_vm_fw_rules {
     my ($filename, $fh) = @_;
 
-    my $res = { rules => [], options => {}};
+    my $res = { 
+       rules => [], 
+       options => {},
+       aliases => {},
+    };
 
     my $section;
 
@@ -2017,6 +2032,15 @@ sub parse_vm_fw_rules {
            next;
        }
 
+       if ($section eq 'aliases') {
+           eval {
+               my $data = parse_alias($line);
+               $res->{aliases}->{lc($data->{name})} = $data;
+           };
+           warn "$prefix: $@" if $@;
+           next;
+       }
+
        my $rule;
        eval { $rule = parse_fw_rule($line, 1, 1); };
        if (my $err = $@) {
@@ -2149,7 +2173,7 @@ sub parse_cluster_fw_rules {
            warn "$prefix: $@" if $@;
        } elsif ($section eq 'aliases') {
            eval {
-               my $data = parse_clusterfw_alias($line);
+               my $data = parse_alias($line);
                $res->{aliases}->{lc($data->{name})} = $data;
            };
            warn "$prefix: $@" if $@;
@@ -2360,6 +2384,9 @@ sub save_vmfw_conf {
     my $options = $vmfw_conf->{options};
     $raw .= &$format_options($options) if scalar(keys %$options);
 
+    my $aliases = $vmfw_conf->{aliases};
+    $raw .= &$format_aliases($aliases) if scalar(keys %$aliases);
+
     my $rules = $vmfw_conf->{rules} || [];
     if (scalar(@$rules)) {
        $raw .= "[RULES]\n\n";
@@ -2593,11 +2620,9 @@ sub compile {
     if ($vmdata) { # test mode
        my $testdir = $vmdata->{testdir} || die "no test directory specified";
        my $filename = "$testdir/cluster.fw";
-       die "missing test file '$filename'\n" if ! -f $filename;
        $cluster_conf = load_clusterfw_conf($filename);
 
        $filename = "$testdir/host.fw";
-       die "missing test file '$filename'\n" if ! -f $filename;
        $hostfw_conf = load_hostfw_conf($filename);
 
        $vmfw_configs = read_vm_firewall_configs($vmdata, $testdir);
@@ -2612,7 +2637,10 @@ sub compile {
 
 
     $cluster_conf->{ipset}->{venet0} = [];
-
+    my $clusternet = cluster_network() || '127.0.0.0/8';
+    push @{$cluster_conf->{ipset}->{management}}, { cidr => $clusternet };
+   
     my $ruleset = {};
 
     ruleset_create_chain($ruleset, "PVEFW-INPUT");
@@ -2657,7 +2685,7 @@ sub compile {
        my $conf = $vmdata->{qemu}->{$vmid};
        my $vmfw_conf = $vmfw_configs->{$vmid};
        next if !$vmfw_conf;
-       next if defined($vmfw_conf->{options}->{enable}) && ($vmfw_conf->{options}->{enable} == 0);
+       next if !$vmfw_conf->{options}->{enable};
 
        foreach my $netid (keys %$conf) {
            next if $netid !~ m/^net(\d+)$/;
@@ -2679,7 +2707,7 @@ sub compile {
 
        my $vmfw_conf = $vmfw_configs->{$vmid};
        next if !$vmfw_conf;
-       next if defined($vmfw_conf->{options}->{enable}) && ($vmfw_conf->{options}->{enable} == 0);
+       next if !$vmfw_conf->{options}->{enable};
 
        if ($conf->{ip_address} && $conf->{ip_address}->{value}) {
            my $ip = $conf->{ip_address}->{value};