X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2FPVE%2FFirewall.pm;h=ef54621a5d3a9455bb0bc60a3001b36dc46a9837;hb=0362a1adeee64bc70719b4f3d99805b09e8cd63d;hp=95bc130b0b3e32e41026455931f36884d395b7e0;hpb=3ba6fd17986d8f719b98fca3a18d8af8aa35f923;p=pve-firewall.git diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 95bc130..ef54621 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -40,7 +40,7 @@ sub pve_verify_ipv4_or_cidr { my ($cidr, $noerr) = @_; if ($cidr =~ m!^(?:$IPV4RE)(/(\d+))?$!) { - return $cidr if Net::IP->new($cidr); + return $cidr if Net::IP->new($cidr); return undef if $noerr; die Net::IP::Error() . "\n"; } @@ -53,7 +53,7 @@ PVE::JSONSchema::register_standard_option('ipset-name', { type => 'string', pattern => '[A-Za-z][A-Za-z0-9\-\_]+', minLength => 2, - maxLength => 20, + maxLength => 20, }); PVE::JSONSchema::register_standard_option('pve-fw-alias', { @@ -61,12 +61,12 @@ PVE::JSONSchema::register_standard_option('pve-fw-alias', { type => 'string', pattern => '[A-Za-z][A-Za-z0-9\-\_]+', minLength => 2, - maxLength => 20, + maxLength => 20, }); PVE::JSONSchema::register_standard_option('pve-fw-loglevel' => { description => "Log level.", - type => 'string', + type => 'string', enum => ['emerg', 'alert', 'crit', 'err', 'warning', 'notice', 'info', 'debug', 'nolog'], optional => 1, }); @@ -79,7 +79,7 @@ PVE::JSONSchema::register_standard_option('pve-security-group-name', { type => 'string', pattern => $security_group_name_pattern, minLength => 2, - maxLength => 20, + maxLength => 20, }); my $feature_ipset_nomatch = 0; @@ -733,7 +733,7 @@ sub parse_address_list { } $iprange = 1 if $elem =~ m/-/; } - + die "you can use a range in a list\n" if $iprange && $count > 1; } @@ -757,7 +757,7 @@ sub parse_port_name_number_or_range { if ($icmp_type_names->{$item}) { $icmp_port = 1; } else { - die "invalid port '$item'\n" if !$services->{byname}->{$item}; + die "invalid port '$item'\n" if !$services->{byname}->{$item}; } } } @@ -918,7 +918,7 @@ sub add_rule_properties { sub delete_rule_properties { my ($rule, $delete_str) = @_; - + foreach my $opt (PVE::Tools::split_list($delete_str)) { raise_param_exc({ 'delete' => "no such property ('$opt')"}) if !defined($rule_properties->{$opt}); @@ -956,7 +956,7 @@ my $apply_macro = sub { if (!defined($v)) { my $msg = "missing parameter '$k' in macro '$macro_name'"; - raise_param_exc({ macro => $msg }) if $verify; + raise_param_exc({ macro => $msg }) if $verify; die "$msg\n"; } $rule->{$k} = $v; @@ -968,7 +968,7 @@ my $apply_macro = sub { if (defined($rule->{$k})) { if ($rule->{$k} ne $param->{$k}) { my $msg = "parameter '$k' already define in macro (value = '$rule->{$k}')"; - raise_param_exc({ $k => $msg }) if $verify; + raise_param_exc({ $k => $msg }) if $verify; die "$msg\n"; } } else { @@ -988,19 +988,19 @@ sub verify_rule { raise_param_exc({ type => "missing property"}) if !$type; raise_param_exc({ action => "missing property"}) if !$rule->{action}; - + if ($type eq 'in' || $type eq 'out') { raise_param_exc({ action => "unknown action '$rule->{action}'"}) if $rule->{action} !~ m/^(ACCEPT|DROP|REJECT)$/; } elsif ($type eq 'group') { - raise_param_exc({ type => "security groups not allowed"}) + raise_param_exc({ type => "security groups not allowed"}) if !$allow_groups; - raise_param_exc({ action => "invalid characters in security group name"}) + raise_param_exc({ action => "invalid characters in security group name"}) if $rule->{action} !~ m/^${security_group_name_pattern}$/; } else { raise_param_exc({ type => "unknown rule type '$type'"}); } - + # fixme: verify $rule->{iface}? if ($rule->{macro}) { @@ -1436,7 +1436,12 @@ sub ruleset_chain_add_conn_filters { } sub ruleset_chain_add_input_filters { - my ($ruleset, $chain, $options) = @_; + my ($ruleset, $chain, $options, $cluster_conf, $loglevel) = @_; + + if ($cluster_conf->{ipset}->{blacklist}){ + ruleset_addlog($ruleset, $chain, 0, "DROP: ", $loglevel, "-m set --match-set PVEFW-blacklist src"); + ruleset_addrule($ruleset, $chain, "-m set --match-set PVEFW-blacklist src -j DROP"); + } if (!(defined($options->{nosmurfs}) && $options->{nosmurfs} == 0)) { ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID,NEW -j PVEFW-smurfs"); @@ -1499,11 +1504,11 @@ sub ruleset_generate_vm_rules { eval { if ($direction eq 'OUT') { ruleset_generate_rule($ruleset, $chain, $rule, - { ACCEPT => "PVEFW-SET-ACCEPT-MARK", REJECT => "PVEFW-reject" }, + { ACCEPT => "PVEFW-SET-ACCEPT-MARK", REJECT => "PVEFW-reject" }, undef, $cluster_conf); } else { - ruleset_generate_rule($ruleset, $chain, $rule, - { ACCEPT => $in_accept , REJECT => "PVEFW-reject" }, + ruleset_generate_rule($ruleset, $chain, $rule, + { ACCEPT => $in_accept , REJECT => "PVEFW-reject" }, undef, $cluster_conf); } }; @@ -1649,7 +1654,7 @@ sub enable_host_firewall { ruleset_addrule($ruleset, $chain, "-i lo -j ACCEPT"); ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT'); - ruleset_chain_add_input_filters($ruleset, $chain, $options); + ruleset_chain_add_input_filters($ruleset, $chain, $options, $cluster_conf, $loglevel); ruleset_addrule($ruleset, $chain, "-m addrtype --dst-type MULTICAST -j ACCEPT"); ruleset_addrule($ruleset, $chain, "-p udp -m conntrack --ctstate NEW --dport 5404:5405 -j ACCEPT"); @@ -1661,6 +1666,7 @@ 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); } @@ -1688,6 +1694,7 @@ 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); } @@ -1777,7 +1784,7 @@ sub parse_fw_rule { die "unknown action '$action'\n"; } } elsif ($type eq 'group') { - die "wrong number of rule elements\n" if scalar(@data) != 3; + die "wrong number of rule elements\n" if scalar(@data) > 3; die "groups disabled\n" if !$allow_groups; die "invalid characters in group name\n" if $action !~ m/^${security_group_name_pattern}$/; @@ -1853,7 +1860,7 @@ sub parse_hostfw_option { my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog"; - if ($line =~ m/^(enable|nosmurfs|tcpflags|optimize):\s*(0|1)\s*$/i) { + if ($line =~ m/^(enable|nosmurfs|tcpflags):\s*(0|1)\s*$/i) { $opt = lc($1); $value = int($2); } elsif ($line =~ m/^(log_level_in|log_level_out|tcp_flags_log_level|smurf_log_level):\s*(($loglevels)\s*)?$/i) { @@ -2012,14 +2019,14 @@ sub parse_cluster_fw_rules { my $section; my $group; - my $res = { - rules => [], - options => {}, - aliases => {}, - groups => {}, - group_comments => {}, + my $res = { + rules => [], + options => {}, + aliases => {}, + groups => {}, + group_comments => {}, ipset => {} , - ipset_comments => {}, + ipset_comments => {}, }; while (defined(my $line = <$fh>)) { @@ -2059,7 +2066,7 @@ sub parse_cluster_fw_rules { $group = lc($1); my $comment = $2; $res->{$section}->{$group} = []; - $res->{ipset_comments}->{$group} = decode('utf8', $comment) + $res->{ipset_comments}->{$group} = decode('utf8', $comment) if $comment; next; } @@ -2107,7 +2114,7 @@ sub parse_cluster_fw_rules { if($cidr !~ m/^${ip_alias_pattern}$/) { $cidr =~ s|/32$||; - + eval { pve_verify_ipv4_or_cidr($cidr); }; if (my $err = $@) { warn "$prefix: $cidr - $err"; @@ -2115,10 +2122,10 @@ sub parse_cluster_fw_rules { } } - my $entry = { cidr => $cidr }; + my $entry = { cidr => $cidr }; $entry->{nomatch} = 1 if $nomatch; $entry->{comment} = $comment if $comment; - + push @{$res->{$section}->{$group}}, $entry; } } @@ -2274,7 +2281,7 @@ my $format_ipset = sub { if $entry->{comment} && $entry->{comment} !~ m/^\s*$/; $raw .= "$line\n"; } - + return $raw; }; @@ -2469,7 +2476,7 @@ sub save_clusterfw_conf { my $aliases = $cluster_conf->{aliases}; $raw .= &$format_aliases($aliases) if scalar(keys %$aliases); - + foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) { if (my $comment = $cluster_conf->{ipset_comments}->{$ipset}) { my $utf8comment = encode('utf8', $comment); @@ -2570,7 +2577,7 @@ sub compile { ruleset_create_chain($ruleset, "PVEFW-OUTPUT"); ruleset_create_chain($ruleset, "PVEFW-FORWARD"); - + my $hostfw_options = $hostfw_conf->{options} || {}; # fixme: what log level should we use here? @@ -2578,17 +2585,12 @@ sub compile { ruleset_chain_add_conn_filters($ruleset, "PVEFW-FORWARD", "ACCEPT"); - if ($cluster_conf->{ipset}->{blacklist}){ - ruleset_addlog($ruleset, "PVEFW-FORWARD", 0, "DROP: ", $loglevel, "-m set --match-set PVEFW-blacklist src"); - ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m set --match-set PVEFW-blacklist src -j DROP"); - } - 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_create_chain($ruleset, "PVEFW-FWBR-IN"); - ruleset_chain_add_input_filters($ruleset, "PVEFW-FWBR-IN", $hostfw_options); + ruleset_chain_add_input_filters($ruleset, "PVEFW-FWBR-IN", $hostfw_options, $cluster_conf, $loglevel); ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-in fwln+ -j PVEFW-FWBR-IN"); @@ -2596,7 +2598,7 @@ sub compile { ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-out fwln+ -j PVEFW-FWBR-OUT"); ruleset_create_chain($ruleset, "PVEFW-VENET-IN"); - ruleset_chain_add_input_filters($ruleset, "PVEFW-VENET-IN", $hostfw_options); + 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"); @@ -2618,7 +2620,7 @@ sub compile { foreach my $netid (keys %$conf) { next if $netid !~ m/^net(\d+)$/; my $net = PVE::QemuServer::parse_net($conf->{$netid}); - next if !$net; + next if !$net->{firewall}; my $iface = "tap${vmid}i$1"; my $macaddr = $net->{macaddr}; @@ -2639,7 +2641,7 @@ sub compile { if ($conf->{ip_address} && $conf->{ip_address}->{value}) { my $ip = $conf->{ip_address}->{value}; - $ip =~ s/\s+/,/g; + $ip =~ s/\s+/,/g; 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'); } @@ -2782,7 +2784,7 @@ sub get_ipset_cmdlist { my $active_chains = ipset_get_chains(); my $statushash = get_ruleset_status($ruleset, $active_chains, \&ipset_chain_digest, $verbose); - # remove stale _swap chains + # remove stale _swap chains foreach my $chain (keys %$active_chains) { if ($chain =~ m/^PVEFW-\S+_swap$/) { $cmdlist .= "destroy $chain\n";