X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FFirewall.pm;h=dd6ec61a38e5d02a9dd7e695a4c023f97a8782eb;hp=362dfbc5ace4666be8aa308a0bf193f13aafb8e0;hb=35f0c37e4dfcc017ca3446971efcb5f78155a7e7;hpb=0365eb68439db796282603ef5d27cab82a07f3cd diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 362dfbc..dd6ec61 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -56,6 +56,13 @@ PVE::JSONSchema::register_standard_option('ipset-name', { maxLength => 20, }); +PVE::JSONSchema::register_standard_option('pve-fw-loglevel' => { + description => "Log level.", + type => 'string', + enum => ['emerg', 'alert', 'crit', 'err', 'warning', 'notice', 'info', 'debug', 'nolog'], + optional => 1, +}); + my $security_group_pattern = '[A-Za-z][A-Za-z0-9\-\_]+'; PVE::JSONSchema::register_standard_option('pve-security-group-name', { @@ -1218,7 +1225,7 @@ sub ruleset_generate_cmdstr { push @cmd, "-m iprange --dst-range $dest"; } else { - push @cmd, "-s $dest"; + push @cmd, "-d $dest"; } } @@ -1503,7 +1510,7 @@ sub generate_nfqueue { $action .= " --queue-num $1"; } } - $action .= " --queue-bypass"; + $action .= " --queue-bypass" if $feature_ipset_nomatch; #need kernel 3.10 }else{ $action = "ACCEPT"; } @@ -1632,7 +1639,9 @@ sub enable_host_firewall { # fixme: allow security groups my $options = $hostfw_conf->{options}; + my $cluster_options = $cluster_conf->{options}; my $rules = $hostfw_conf->{rules}; + my $cluster_rules = $cluster_conf->{rules}; # host inbound firewall my $chain = "PVEFW-HOST-IN"; @@ -1658,13 +1667,14 @@ sub enable_host_firewall { # we use RETURN because we need to check also tap rules my $accept_action = 'RETURN'; - foreach my $rule (@$rules) { + # add host rules first, so that cluster wide rules can be overwritten + foreach my $rule (@$rules, @$cluster_rules) { next if $rule->{type} ne 'in'; ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, undef, $cluster_conf); } # implement input policy - my $policy = $options->{policy_in} || 'DROP'; # allow nothing by default + my $policy = $cluster_options->{policy_in} || 'DROP'; # allow nothing by default ruleset_add_chain_policy($ruleset, $chain, 0, $policy, $loglevel, $accept_action); # host outbound firewall @@ -1683,13 +1693,14 @@ sub enable_host_firewall { # we use RETURN because we may want to check other thigs later $accept_action = 'RETURN'; - foreach my $rule (@$rules) { + # add host rules first, so that cluster wide rules can be overwritten + foreach my $rule (@$rules, @$cluster_rules) { next if $rule->{type} ne 'out'; ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $accept_action, REJECT => "PVEFW-reject" }, undef, $cluster_conf); } # implement output policy - $policy = $options->{policy_out} || 'ACCEPT'; # allow everything by default + $policy = $cluster_options->{policy_out} || 'ACCEPT'; # allow everything by default ruleset_add_chain_policy($ruleset, $chain, 0, $policy, $loglevel, $accept_action); ruleset_addrule($ruleset, "PVEFW-OUTPUT", "-j PVEFW-HOST-OUT"); @@ -1850,16 +1861,13 @@ sub parse_hostfw_option { my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog"; - if ($line =~ m/^(enable|dhcp|nosmurfs|tcpflags|allow_bridge_route|optimize):\s*(0|1)\s*$/i) { + if ($line =~ m/^(enable|nosmurfs|tcpflags|allow_bridge_route|optimize):\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) { $opt = lc($1); $value = $2 ? lc($3) : ''; - } elsif ($line =~ m/^(policy_(in|out)):\s*(ACCEPT|DROP|REJECT)\s*$/i) { - $opt = lc($1); - $value = uc($3); - } elsif ($line =~ m/^(nf_conntrack_max):\s*(\d+)\s*$/i) { + } elsif ($line =~ m/^(nf_conntrack_max|nf_conntrack_tcp_timeout_established):\s*(\d+)\s*$/i) { $opt = lc($1); $value = int($2); } else { @@ -1878,6 +1886,9 @@ sub parse_clusterfw_option { if ($line =~ m/^(enable):\s*(0|1)\s*$/i) { $opt = lc($1); $value = int($2); + } elsif ($line =~ m/^(policy_(in|out)):\s*(ACCEPT|DROP|REJECT)\s*$/i) { + $opt = lc($1); + $value = uc($3); } else { chomp $line; die "can't parse option '$line'\n" @@ -2276,6 +2287,7 @@ sub generate_std_chains { # same as shorewall smurflog. my $chain = 'PVEFW-smurflog'; + $pve_std_chains->{$chain} = []; push @{$pve_std_chains->{$chain}}, get_log_rule_base($chain, 0, "DROP: ", $loglevel) if $loglevel; push @{$pve_std_chains->{$chain}}, "-j DROP"; @@ -2283,6 +2295,8 @@ sub generate_std_chains { # same as shorewall logflags action. $loglevel = get_option_log_level($options, 'tcp_flags_log_level'); $chain = 'PVEFW-logflags'; + $pve_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"; @@ -2482,13 +2496,16 @@ sub save_hostfw_conf { } sub compile { + my ($cluster_conf, $hostfw_conf) = @_; + + $cluster_conf = load_clusterfw_conf() if !$cluster_conf; + $hostfw_conf = load_hostfw_conf() if !$hostfw_conf; + my $vmdata = read_local_vm_config(); my $vmfw_configs = read_vm_firewall_configs($vmdata); my $routing_table = read_proc_net_route(); - my $cluster_conf = load_clusterfw_conf(); - my $ipset_ruleset = {}; generate_ipset_chains($ipset_ruleset, $cluster_conf); @@ -2499,7 +2516,6 @@ sub compile { ruleset_create_chain($ruleset, "PVEFW-FORWARD"); - my $hostfw_conf = load_hostfw_conf(); my $hostfw_options = $hostfw_conf->{options} || {}; generate_std_chains($ruleset, $hostfw_options); @@ -2595,7 +2611,7 @@ sub compile { ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o vmbr+ -j DROP"); ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i vmbr+ -j DROP"); - return wantarray ? ($ruleset, $hostfw_conf, $ipset_ruleset) : $ruleset; + return ($ruleset, $ipset_ruleset); } sub get_ruleset_status { @@ -2764,6 +2780,8 @@ sub apply_ruleset { update_nf_conntrack_max($hostfw_conf); + update_nf_conntrack_tcp_timeout_established($hostfw_conf); + my ($ipset_create_cmdlist, $ipset_delete_cmdlist, $ipset_changes) = get_ipset_cmdlist($ipset_ruleset, undef, $verbose); @@ -2828,6 +2846,16 @@ sub update_nf_conntrack_max { } } +sub update_nf_conntrack_tcp_timeout_established { + my ($hostfw_conf) = @_; + + my $options = $hostfw_conf->{options} || {}; + + my $value = defined($options->{nf_conntrack_tcp_timeout_established}) ? $options->{nf_conntrack_tcp_timeout_established} : 432000; + + PVE::ProcFSTools::write_proc_entry("/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established", $value); +} + sub remove_pvefw_chains { my ($chash, $hooks) = iptables_get_chains(); @@ -2855,9 +2883,25 @@ sub update { my ($start, $verbose) = @_; my $code = sub { + + my $cluster_conf = load_clusterfw_conf(); + my $cluster_options = $cluster_conf->{options}; + + my $enable = $cluster_options->{enable}; + my $status = read_pvefw_status(); - my ($ruleset, $hostfw_conf, $ipset_ruleset) = compile(); + die "Firewall is disabled - cannot start\n" if !$enable && $start; + + if (!$enable) { + PVE::Firewall::remove_pvefw_chains(); + print "Firewall disabled\n" if $verbose; + return; + } + + my $hostfw_conf = load_hostfw_conf(); + + my ($ruleset, $ipset_ruleset) = compile($cluster_conf, $hostfw_conf); if ($start || $status eq 'active') {