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";
}
type => 'string',
pattern => '[A-Za-z][A-Za-z0-9\-\_]+',
minLength => 2,
- maxLength => 20,
+ maxLength => 20,
});
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,
});
type => 'string',
pattern => $security_group_name_pattern,
minLength => 2,
- maxLength => 20,
+ maxLength => 20,
});
my $feature_ipset_nomatch = 0;
}
$iprange = 1 if $elem =~ m/-/;
}
-
+
die "you can use a range in a list\n" if $iprange && $count > 1;
}
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};
}
}
}
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});
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;
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 {
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}) {
}
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");
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);
}
};
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");
# 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);
}
# 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);
}
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}$/;
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) {
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>)) {
$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;
}
if($cidr !~ m/^${ip_alias_pattern}$/) {
$cidr =~ s|/32$||;
-
+
eval { pve_verify_ipv4_or_cidr($cidr); };
if (my $err = $@) {
warn "$prefix: $cidr - $err";
}
}
- my $entry = { cidr => $cidr };
+ my $entry = { cidr => $cidr };
$entry->{nomatch} = 1 if $nomatch;
$entry->{comment} = $comment if $comment;
-
+
push @{$res->{$section}->{$group}}, $entry;
}
}
if $entry->{comment} && $entry->{comment} !~ m/^\s*$/;
$raw .= "$line\n";
}
-
+
return $raw;
};
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);
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?
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");
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");
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};
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');
}
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";