X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FFirewall.pm;h=3123550fb24805e6ee96c4a8613674dc24bc2e6d;hp=5a6284fa3d2800f84d067c0bf578d8c5d89ccc8a;hb=78a72bc4b25a2b32a470e2d39fd1fcd120dafbdc;hpb=9268573a4675ab12576c956ad055538df616c994 diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 5a6284f..3123550 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -489,7 +489,8 @@ my $pve_fw_parsed_macros; my $pve_fw_macro_descr; my $pve_fw_preferred_macro_names = {}; -my $pve_std_chains = { +my $pve_std_chains = {}; +$pve_std_chains->{4} = { 'PVEFW-SET-ACCEPT-MARK' => [ "-j MARK --set-mark 1", ], @@ -801,16 +802,28 @@ sub parse_address_list { my $count = 0; my $iprange = 0; + my $ipversion; + foreach my $elem (split(/,/, $str)) { $count++; - if (!Net::IP->new($elem)) { + my $ip = Net::IP->new($elem); + if (!$ip) { my $err = Net::IP::Error(); die "invalid IP address: $err\n"; } $iprange = 1 if $elem =~ m/-/; + + my $new_ipversion = Net::IP::ip_is_ipv6($ip->ip()) ? 6 : 4; + + die "detected mixed ipv4/ipv6 addresses in address list '$str'\n" + if $ipversion && ($new_ipversion != $ipversion); + + $ipversion = $new_ipversion; } - die "you can use a range in a list\n" if $iprange && $count > 1; + die "you can't use a range in a list\n" if $iprange && $count > 1; + + return $ipversion; } sub parse_port_name_number_or_range { @@ -852,8 +865,8 @@ sub pve_fw_verify_port_spec { return $portstr; } -PVE::JSONSchema::register_format('pve-fw-v4addr-spec', \&pve_fw_verify_v4addr_spec); -sub pve_fw_verify_v4addr_spec { +PVE::JSONSchema::register_format('pve-fw-addr-spec', \&pve_fw_verify_addr_spec); +sub pve_fw_verify_addr_spec { my ($list) = @_; parse_address_list($list); @@ -952,11 +965,11 @@ my $rule_properties = { }, iface => get_standard_option('pve-iface', { optional => 1 }), source => { - type => 'string', format => 'pve-fw-v4addr-spec', + type => 'string', format => 'pve-fw-addr-spec', optional => 1, }, dest => { - type => 'string', format => 'pve-fw-v4addr-spec', + type => 'string', format => 'pve-fw-addr-spec', optional => 1, }, proto => { @@ -1167,14 +1180,21 @@ sub verify_rule { if !$rule->{proto}; } + my $ipversion; + if ($rule->{source}) { - eval { parse_address_list($rule->{source}); }; + eval { $ipversion = parse_address_list($rule->{source}); }; &$add_error('source', $@) if $@; &$check_ipset_or_alias_property('source'); } if ($rule->{dest}) { - eval { parse_address_list($rule->{dest}); }; + eval { + my $dest_ipversion = parse_address_list($rule->{dest}); + die "detected mixed ipv4/ipv6 adresses in rule\n" + if defined($ipversion) && ($dest_ipversion != $ipversion); + $ipversion = $dest_ipversion; + }; &$add_error('dest', $@) if $@; &$check_ipset_or_alias_property('dest'); } @@ -1194,6 +1214,7 @@ sub verify_rule { } $rule->{errors} = $errors if $error_count; + $rule->{ipversion} = $ipversion if $ipversion; return $rule; } @@ -1720,7 +1741,7 @@ sub ruleset_add_group_rule { } sub ruleset_generate_vm_rules { - my ($ruleset, $rules, $cluster_conf, $vmfw_conf, $chain, $netid, $direction, $options) = @_; + my ($ruleset, $rules, $cluster_conf, $vmfw_conf, $chain, $netid, $direction, $options, $ipversion) = @_; my $lc_direction = lc($direction); @@ -1729,6 +1750,8 @@ sub ruleset_generate_vm_rules { foreach my $rule (@$rules) { next if $rule->{iface} && $rule->{iface} ne $netid; next if !$rule->{enable} || $rule->{errors}; + next if $rule->{ipversion} && ($rule->{ipversion} != $ipversion); + if ($rule->{type} eq 'group') { ruleset_add_group_rule($ruleset, $cluster_conf, $chain, $rule, $direction, $direction eq 'OUT' ? 'RETURN' : $in_accept); @@ -1784,7 +1807,7 @@ sub ruleset_generate_vm_ipsrules { } sub generate_venet_rules_direction { - my ($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, $direction) = @_; + my ($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, $direction, $ipversion) = @_; my $lc_direction = lc($direction); @@ -1797,7 +1820,7 @@ sub generate_venet_rules_direction { ruleset_create_vm_chain($ruleset, $chain, $options, undef, undef, $direction); - ruleset_generate_vm_rules($ruleset, $rules, $cluster_conf, $vmfw_conf, $chain, 'venet', $direction); + ruleset_generate_vm_rules($ruleset, $rules, $cluster_conf, $vmfw_conf, $chain, 'venet', $direction, undef, $ipversion); # implement policy my $policy; @@ -1826,7 +1849,7 @@ sub generate_venet_rules_direction { } sub generate_tap_rules_direction { - my ($ruleset, $cluster_conf, $iface, $netid, $macaddr, $vmfw_conf, $vmid, $direction) = @_; + my ($ruleset, $cluster_conf, $iface, $netid, $macaddr, $vmfw_conf, $vmid, $direction, $ipversion) = @_; my $lc_direction = lc($direction); @@ -1845,7 +1868,7 @@ sub generate_tap_rules_direction { ruleset_create_vm_chain($ruleset, $tapchain, $options, $macaddr, $ipfilter_ipset, $direction); if ($options->{enable}) { - ruleset_generate_vm_rules($ruleset, $rules, $cluster_conf, $vmfw_conf, $tapchain, $netid, $direction, $options); + ruleset_generate_vm_rules($ruleset, $rules, $cluster_conf, $vmfw_conf, $tapchain, $netid, $direction, $options, $ipversion); ruleset_generate_vm_ipsrules($ruleset, $options, $direction, $iface); @@ -2641,29 +2664,35 @@ sub get_option_log_level { } sub generate_std_chains { - my ($ruleset, $options) = @_; + my ($ruleset, $options, $ipversion) = @_; + + my $std_chains = $pve_std_chains->{$ipversion} || die "internal error"; my $loglevel = get_option_log_level($options, 'smurf_log_level'); - # same as shorewall smurflog. - my $chain = 'PVEFW-smurflog'; - $pve_std_chains->{$chain} = []; + my $chain; - push @{$pve_std_chains->{$chain}}, get_log_rule_base($chain, 0, "DROP: ", $loglevel) if $loglevel; - push @{$pve_std_chains->{$chain}}, "-j DROP"; + if ($ipversion == 4) { + # same as shorewall smurflog. + $chain = 'PVEFW-smurflog'; + $std_chains->{$chain} = []; + + push @{$std_chains->{$chain}}, get_log_rule_base($chain, 0, "DROP: ", $loglevel) if $loglevel; + push @{$std_chains->{$chain}}, "-j DROP"; + } # same as shorewall logflags action. $loglevel = get_option_log_level($options, 'tcp_flags_log_level'); $chain = 'PVEFW-logflags'; - $pve_std_chains->{$chain} = []; + $std_chains->{$chain} = []; # fixme: is this correctly logged by pvewf-logger? (ther is no --log-ip-options for NFLOG) - push @{$pve_std_chains->{$chain}}, get_log_rule_base($chain, 0, "DROP: ", $loglevel) if $loglevel; - push @{$pve_std_chains->{$chain}}, "-j DROP"; + push @{$std_chains->{$chain}}, get_log_rule_base($chain, 0, "DROP: ", $loglevel) if $loglevel; + push @{$std_chains->{$chain}}, "-j DROP"; - foreach my $chain (keys %$pve_std_chains) { + foreach my $chain (keys %$std_chains) { ruleset_create_chain($ruleset, $chain); - foreach my $rule (@{$pve_std_chains->{$chain}}) { + foreach my $rule (@{$std_chains->{$chain}}) { if (ref($rule)) { ruleset_generate_rule($ruleset, $chain, $rule); } else { @@ -2890,13 +2919,13 @@ sub compile_iptables_filter { ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o venet0 -m set --match-set ${venet0_ipset_chain} dst -j PVEFW-VENET-IN"); - generate_std_chains($ruleset, $hostfw_options); + generate_std_chains($ruleset, $hostfw_options, $ipversion); my $hostfw_enable = !(defined($hostfw_options->{enable}) && ($hostfw_options->{enable} == 0)); my $ipset_ruleset = {}; - if ($hostfw_enable) { + if ($hostfw_enable && $ipversion eq 4) { eval { enable_host_firewall($ruleset, $hostfw_conf, $cluster_conf); }; warn $@ if $@; # just to be sure - should not happen } @@ -2920,9 +2949,9 @@ sub compile_iptables_filter { my $macaddr = $net->{macaddr}; generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'IN'); + $vmfw_conf, $vmid, 'IN', $ipversion); generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'OUT'); + $vmfw_conf, $vmid, 'OUT', $ipversion); } }; warn $@ if $@; # just to be sure - should not happen @@ -2942,18 +2971,20 @@ sub compile_iptables_filter { 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 = (); - foreach my $singleip (@ips) { - my $venet0ipset = {}; - $venet0ipset->{cidr} = $singleip; - push @{$cluster_conf->{ipset}->{venet0}}, $venet0ipset; + foreach my $singleip (split(',', $ip)) { + my $singleip_ver = parse_address_list($singleip); # make sure we have a valid $ip list + push @{$cluster_conf->{ipset}->{venet0}}, { cidr => $singleip }; + push @ips, $singleip if $singleip_ver == $ipversion; } - generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, 'IN'); - generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip, 'OUT'); + if (scalar(@ips)) { + my $ip_list = join(',', @ips); + generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip_list, 'IN', $ipversion); + generate_venet_rules_direction($ruleset, $cluster_conf, $vmfw_conf, $vmid, $ip_list, 'OUT', $ipversion); + } } } @@ -2966,9 +2997,9 @@ sub compile_iptables_filter { my $macaddr = $d->{mac}; my $iface = $d->{host_ifname}; generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'IN'); + $vmfw_conf, $vmid, 'IN', $ipversion); generate_tap_rules_direction($ruleset, $cluster_conf, $iface, $netid, $macaddr, - $vmfw_conf, $vmid, 'OUT'); + $vmfw_conf, $vmid, 'OUT', $ipversion); } } };