# helper function for API
+sub copy_opject_with_digest {
+ my ($object) = @_;
+
+ my $sha = Digest::SHA->new('sha1');
+
+ my $res = {};
+ foreach my $k (sort keys %$object) {
+ my $v = $object->{$k};
+ next if !defined($v);
+ $res->{$k} = $v;
+ $sha->add($k, ':', $v, "\n");
+ }
+
+ my $digest = $sha->b64digest;
+
+ $res->{digest} = $digest;
+
+ return wantarray ? ($res, $digest) : $res;
+}
+
+sub copy_list_with_digest {
+ my ($list) = @_;
+
+ my $sha = Digest::SHA->new('sha1');
+
+ my $res = [];
+ foreach my $entry (@$list) {
+ my $data = {};
+ foreach my $k (sort keys %$entry) {
+ my $v = $entry->{$k};
+ next if !defined($v);
+ $data->{$k} = $v;
+ $sha->add($k, ':', $v, "\n");
+ }
+ push @$res, $data;
+ }
+
+ my $digest = $sha->b64digest;
+
+ foreach my $entry (@$res) {
+ $entry->{digest} = $digest;
+ }
+
+ return wantarray ? ($res, $digest) : $res;
+}
+
my $rule_properties = {
pos => {
description => "Update rule at position <pos>.",
minimum => 0,
optional => 1,
},
- digest => {
- type => 'string',
- optional => 1,
- maxLength => 27,
- minLength => 27,
- },
+ digest => get_standard_option('pve-config-digest'),
type => {
type => 'string',
optional => 1,
},
};
-sub cleanup_fw_rule {
- my ($rule, $digest, $pos) = @_;
-
- my $r = {};
-
- foreach my $k (keys %$rule) {
- next if !$rule_properties->{$k};
- my $v = $rule->{$k};
- next if !defined($v);
- $r->{$k} = $v;
- $r->{digest} = $digest;
- $r->{pos} = $pos;
- }
-
- return $r;
-}
-
sub add_rule_properties {
my ($properties) = @_;
$action .= " --queue-num $1";
}
}
- $action .= " --queue-bypass";
+ $action .= " --queue-bypass" if $feature_ipset_nomatch; #need kernel 3.10
}else{
$action = "ACCEPT";
}
# fixme: allow security groups
my $options = $hostfw_conf->{options};
+ my $cluster_options = $cluster_conf->{options};
my $rules = $hostfw_conf->{rules};
# host inbound firewall
}
# 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
}
# 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");
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 {
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"
my $section;
- my $digest = Digest::SHA->new('sha1');
-
while (defined(my $line = <$fh>)) {
- $digest->add($line);
-
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
push @{$res->{$section}}, $rule;
}
- $res->{digest} = $digest->b64digest;
-
return $res;
}
my $section;
- my $digest = Digest::SHA->new('sha1');
-
while (defined(my $line = <$fh>)) {
- $digest->add($line);
-
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
push @{$res->{$section}}, $rule;
}
-$res->{digest} = $digest->b64digest;
-
return $res;
}
options => {},
groups => {},
group_comments => {},
- ipset => {}
+ ipset => {} ,
+ ipset_comments => {},
};
- my $digest = Digest::SHA->new('sha1');
-
while (defined(my $line = <$fh>)) {
- $digest->add($line);
-
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
$group = lc($1);
my $comment = $2;
$res->{$section}->{$group} = [];
- $res->{group_comments}->{$group} = $comment if $comment;
+ $res->{group_comments}->{$group} = decode('utf8', $comment)
+ if $comment;
next;
}
next;
}
- if ($line =~ m/^\[ipset\s+(\S+)\]\s*$/i) {
+ if ($line =~ m/^\[ipset\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i) {
$section = 'ipset';
$group = lc($1);
+ my $comment = $2;
$res->{$section}->{$group} = [];
+ $res->{ipset_comments}->{$group} = decode('utf8', $comment)
+ if $comment;
next;
}
}
}
- $res->{digest} = $digest->b64digest;
return $res;
}
$raw .= &$format_options($options) if scalar(keys %$options);
foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) {
- $raw .= "[IPSET $ipset]\n\n";
+ if (my $comment = $cluster_conf->{ipset_comments}->{$ipset}) {
+ my $utf8comment = encode('utf8', $comment);
+ $raw .= "[IPSET $ipset] # $utf8comment\n\n";
+ } else {
+ $raw .= "[IPSET $ipset]\n\n";
+ }
my $options = $cluster_conf->{ipset}->{$ipset};
$raw .= &$format_ipset($options);
$raw .= "\n";
foreach my $group (sort keys %{$cluster_conf->{groups}}) {
my $rules = $cluster_conf->{groups}->{$group};
if (my $comment = $cluster_conf->{group_comments}->{$group}) {
- $raw .= "[group $group] # $comment\n\n";
+ my $utf8comment = encode('utf8', $comment);
+ $raw .= "[group $group] # $utf8comment\n\n";
} else {
$raw .= "[group $group]\n\n";
}
}
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);
ruleset_create_chain($ruleset, "PVEFW-FORWARD");
- my $hostfw_conf = load_hostfw_conf();
my $hostfw_options = $hostfw_conf->{options} || {};
generate_std_chains($ruleset, $hostfw_options);
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 {
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);
}
}
+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();
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') {