X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FFirewall.pm;h=cacfedcf19b936947f3bdbdf50632853c05791a4;hp=be81778c97d8f5503c2dcca5421fe5055c6f6eba;hb=b1ef6d2e715d6aeaf67d53ca3270f0d247c407d9;hpb=eb399cef4838774a16964cc5d11e4bcbfb07fbd2 diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index be81778..cacfedc 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -687,7 +687,7 @@ sub get_etc_protocols { return $etc_protocols; } -my $ipv4_mask_hash_clusternet = { +my $ipv4_mask_hash_localnet = { '255.255.0.0' => 16, '255.255.128.0' => 17, '255.255.192.0' => 18, @@ -705,14 +705,14 @@ my $ipv4_mask_hash_clusternet = { '255.255.255.252' => 30, }; -my $__cluster_network; +my $__local_network; -sub cluster_network { +sub local_network { my ($new_value) = @_; - $__cluster_network = $new_value if defined($new_value); + $__local_network = $new_value if defined($new_value); - return $__cluster_network if defined($__cluster_network); + return $__local_network if defined($__local_network); eval { my $nodename = PVE::INotify::nodename(); @@ -723,20 +723,20 @@ sub cluster_network { my $routes = PVE::ProcFSTools::read_proc_net_route(); foreach my $entry (@$routes) { - my $mask = $ipv4_mask_hash_clusternet->{$entry->{mask}}; + my $mask = $ipv4_mask_hash_localnet->{$entry->{mask}}; next if !defined($mask); return if $mask eq '0.0.0.0'; my $cidr = "$entry->{dest}/$mask"; my $testnet = Net::IP->new($cidr); if ($testnet->overlaps($testip)) { - $__cluster_network = $cidr; + $__local_network = $cidr; return; } } }; warn $@ if $@; - return $__cluster_network; + return $__local_network; } sub parse_address_list { @@ -915,10 +915,12 @@ my $rule_properties = { sport => { type => 'string', format => 'pve-fw-port-spec', optional => 1, + requires => 'proto', }, dport => { type => 'string', format => 'pve-fw-port-spec', optional => 1, + requires => 'proto', }, comment => { type => 'string', @@ -1318,8 +1320,8 @@ sub ruleset_generate_cmdstr { } } } elsif ($rule->{dport} || $rule->{sport}) { - warn "ignoring destination port '$rule->{dport}' - no protocol specified\n" if $rule->{dport}; - warn "ignoring source port '$rule->{sport}' - no protocol specified\n" if $rule->{sport}; + die "destination port '$rule->{dport}', but no protocol specified\n" if $rule->{dport}; + die "source port '$rule->{sport}', but no protocol specified\n" if $rule->{sport}; } push @cmd, "-m addrtype --dst-type $rule->{dsttype}" if $rule->{dsttype}; @@ -1690,15 +1692,20 @@ sub enable_host_firewall { # we use RETURN because we need to check also tap rules my $accept_action = 'RETURN'; + ruleset_addrule($ruleset, $chain, "-p igmp -j $accept_action"); # important for multicast + # add host rules first, so that cluster wide rules can be overwritten foreach my $rule (@$rules, @$cluster_rules) { $rule->{iface_in} = $rule->{iface} if $rule->{iface}; - 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); - } + eval { + 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); + } + }; + warn $@ if $@; delete $rule->{iface_in}; } @@ -1709,13 +1716,13 @@ sub enable_host_firewall { 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(); + my $localnet = local_network(); # corosync - if ($clusternet) { + if ($localnet) { 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"); + ruleset_addrule($ruleset, $chain, "-s $localnet -d $localnet $corosync_rule"); + ruleset_addrule($ruleset, $chain, "-s $localnet -m addrtype --dst-type MULTICAST $corosync_rule"); } # implement input policy @@ -1735,27 +1742,32 @@ sub enable_host_firewall { # we use RETURN because we may want to check other thigs later $accept_action = 'RETURN'; + ruleset_addrule($ruleset, $chain, "-p igmp -j $accept_action"); # important for multicast + # add host rules first, so that cluster wide rules can be overwritten foreach my $rule (@$rules, @$cluster_rules) { $rule->{iface_out} = $rule->{iface} if $rule->{iface}; - 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); - } + eval { + 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); + } + }; + warn $@ if $@; 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 + if ($localnet) { + ruleset_addrule($ruleset, $chain, "-d $localnet -p tcp --dport 8006 -j $accept_action"); # PVE API + ruleset_addrule($ruleset, $chain, "-d $localnet -p tcp --dport 22 -j $accept_action"); # SSH + ruleset_addrule($ruleset, $chain, "-d $localnet -p tcp --dport 5900:5999 -j $accept_action"); # PVE VNC Console + ruleset_addrule($ruleset, $chain, "-d $localnet -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, "-d $localnet $corosync_rule"); ruleset_addrule($ruleset, $chain, "-m addrtype --dst-type MULTICAST $corosync_rule"); } @@ -2638,8 +2650,15 @@ sub compile { $cluster_conf->{ipset}->{venet0} = []; - my $clusternet = cluster_network() || '127.0.0.0/8'; - push @{$cluster_conf->{ipset}->{management}}, { cidr => $clusternet }; + my $localnet; + if ($cluster_conf->{aliases}->{local_network}) { + $localnet = $cluster_conf->{aliases}->{local_network}->{cidr}; + } else { + $localnet = local_network() || '127.0.0.0/8'; + $cluster_conf->{aliases}->{local_network} = { cidr => $localnet }; + } + + push @{$cluster_conf->{ipset}->{management}}, { cidr => $localnet }; my $ruleset = {}; @@ -2676,69 +2695,78 @@ sub compile { my $hostfw_enable = !(defined($hostfw_options->{enable}) && ($hostfw_options->{enable} == 0)); - enable_host_firewall($ruleset, $hostfw_conf, $cluster_conf) if $hostfw_enable; + if ($hostfw_enable) { + eval { enable_host_firewall($ruleset, $hostfw_conf, $cluster_conf); }; + warn $@ if $@; # just to be sure - should not happen + } 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}}) { - my $conf = $vmdata->{qemu}->{$vmid}; - my $vmfw_conf = $vmfw_configs->{$vmid}; - next if !$vmfw_conf; - next if !$vmfw_conf->{options}->{enable}; - - foreach my $netid (keys %$conf) { - next if $netid !~ m/^net(\d+)$/; - my $net = PVE::QemuServer::parse_net($conf->{$netid}); - next if !$net->{firewall}; - my $iface = "tap${vmid}i$1"; - - my $macaddr = $net->{macaddr}; - generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'IN'); - generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'OUT'); - } + eval { + my $conf = $vmdata->{qemu}->{$vmid}; + my $vmfw_conf = $vmfw_configs->{$vmid}; + return if !$vmfw_conf; + return if !$vmfw_conf->{options}->{enable}; + + foreach my $netid (keys %$conf) { + next if $netid !~ m/^net(\d+)$/; + my $net = PVE::QemuServer::parse_net($conf->{$netid}); + next if !$net->{firewall}; + my $iface = "tap${vmid}i$1"; + + my $macaddr = $net->{macaddr}; + generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, + $vmfw_conf, $vmid, 'IN'); + generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, + $vmfw_conf, $vmid, 'OUT'); + } + }; + warn $@ if $@; # just to be sure - should not happen } # generate firewall rules for OpenVZ containers foreach my $vmid (keys %{$vmdata->{openvz}}) { - my $conf = $vmdata->{openvz}->{$vmid}; + eval { + my $conf = $vmdata->{openvz}->{$vmid}; - my $vmfw_conf = $vmfw_configs->{$vmid}; - next if !$vmfw_conf; - next if !$vmfw_conf->{options}->{enable}; + my $vmfw_conf = $vmfw_configs->{$vmid}; + return if !$vmfw_conf; + return if !$vmfw_conf->{options}->{enable}; - 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 + 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); + 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, $vmfw_conf, $vmid, $ip, 'IN'); - generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, 'OUT'); - } + foreach my $singleip (@ips) { + my $venet0ipset = {}; + $venet0ipset->{cidr} = $singleip; + push @{$cluster_conf->{ipset}->{venet0}}, $venet0ipset; + } - if ($conf->{netif} && $conf->{netif}->{value}) { - my $netif = PVE::OpenVZ::parse_netif($conf->{netif}->{value}); - foreach my $netid (keys %$netif) { - my $d = $netif->{$netid}; + generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, 'IN'); + generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, 'OUT'); + } - my $macaddr = $d->{mac}; - my $iface = $d->{host_ifname}; - generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'IN'); - generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'OUT'); + if ($conf->{netif} && $conf->{netif}->{value}) { + my $netif = PVE::OpenVZ::parse_netif($conf->{netif}->{value}); + foreach my $netid (keys %$netif) { + my $d = $netif->{$netid}; + + my $macaddr = $d->{mac}; + my $iface = $d->{host_ifname}; + generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, + $vmfw_conf, $vmid, 'IN'); + generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, + $vmfw_conf, $vmid, 'OUT'); + } } - } + }; + warn $@ if $@; # just to be sure - should not happen } if(ruleset_chain_exist($ruleset, "PVEFW-IPS")){