}
};
+my $proto_is_icmp = sub {
+ my $proto = shift;
+ return $proto eq 'icmp' || $proto eq 'icmpv6' || $proto eq 'ipv6-icmp';
+};
+
sub init_firewall_macros {
$pve_fw_parsed_macros = {};
return $ipversion;
}
+# $dport must only be set to 1 if the parsed parameter is dport and the
+# protocol is one of the ICMP variants - ICMP type values used to be stored in
+# the dport parameter.
sub parse_port_name_number_or_range {
my ($str, $dport) = @_;
optional => 1,
},
'icmp-type' => {
- description => "Specify icmp-type. Only valid if proto equals 'icmp'.",
+ description => "Specify icmp-type. Only valid if proto equals 'icmp' or 'icmpv6'/'ipv6-icmp'.",
type => 'string', format => 'pve-fw-icmp-type-spec',
optional => 1,
},
if (my $value = $rule->{$name}) {
if ($value =~ m/^\+/) {
- if ($value =~ m/^\+(${ipset_name_pattern})$/) {
- &$add_error($name, "no such ipset '$1'")
- if !($cluster_conf->{ipset}->{$1} || ($fw_conf && $fw_conf->{ipset}->{$1}));
+ if ($value =~ m@^\+(vm/|dc/)?(${ipset_name_pattern})$@) {
+ &$add_error($name, "no such ipset '$2'")
+ if !($cluster_conf->{ipset}->{$2} || ($fw_conf && $fw_conf->{ipset}->{$2}));
} else {
&$add_error($name, "invalid ipset name '$value'");
}
}
+ my $is_icmp = 0;
if ($rule->{proto}) {
eval { pve_fw_verify_protocol_spec($rule->{proto}); };
&$add_error('proto', $@) if $@;
&$set_ip_version(4) if $rule->{proto} eq 'icmp';
&$set_ip_version(6) if $rule->{proto} eq 'icmpv6';
&$set_ip_version(6) if $rule->{proto} eq 'ipv6-icmp';
+ $is_icmp = $proto_is_icmp->($rule->{proto});
}
if ($rule->{dport}) {
- eval { parse_port_name_number_or_range($rule->{dport}, 1); };
+ eval { parse_port_name_number_or_range($rule->{dport}, $is_icmp); };
&$add_error('dport', $@) if $@;
my $proto = $rule->{proto};
&$add_error('proto', "missing property - 'dport' requires this property")
if !$proto;
&$add_error('dport', "protocol '$proto' does not support ports")
- if !$PROTOCOLS_WITH_PORTS->{$proto} &&
- $proto ne 'icmp' && $proto ne 'icmpv6'; # special cases
+ if !$PROTOCOLS_WITH_PORTS->{$proto} && !$is_icmp; #special cases
}
if (my $icmp_type = $rule ->{'icmp-type'}) {
my $proto = $rule->{proto};
&$add_error('proto', "missing property - 'icmp-type' requires this property")
- if $proto ne 'icmp' && $proto ne 'icmpv6' && $proto ne 'ipv6-icmp';
+ if !$is_icmp;
&$add_error('icmp-type', "'icmp-type' cannot be specified together with 'dport'")
if $rule->{dport};
if ($proto eq 'icmp' && !$icmp_type_names->{$icmp_type}) {
my $match;
if ($adr =~ m/^\+/) {
- if ($adr =~ m/^\+(${ipset_name_pattern})$/) {
- my $name = $1;
+ if ($adr =~ m@^\+(vm/|dc/)?(${ipset_name_pattern})$@) {
+ my $scope = $1;
+ my $name = $2;
my $ipset_chain;
- if ($fw_conf && $fw_conf->{ipset}->{$name}) {
+ if ($scope ne 'dc/' && $fw_conf && $fw_conf->{ipset}->{$name}) {
$ipset_chain = compute_ipset_chain_name($fw_conf->{vmid}, $name, $ipversion);
- } elsif ($cluster_conf && $cluster_conf->{ipset}->{$name}) {
+ } elsif ($scope ne 'vm/' && $cluster_conf && $cluster_conf->{ipset}->{$name}) {
$ipset_chain = compute_ipset_chain_name(0, $name, $ipversion);
} else {
die "no such ipset '$name'\n";
if (my $proto = $rule->{proto}) {
push @match, "-p $proto";
+ my $is_icmp = $proto_is_icmp->($proto);
- my $multidport = defined($rule->{dport}) && parse_port_name_number_or_range($rule->{dport}, 1);
+ my $multidport = defined($rule->{dport}) && parse_port_name_number_or_range($rule->{dport}, $is_icmp);
my $multisport = defined($rule->{sport}) && parse_port_name_number_or_range($rule->{sport}, 0);
my $add_dport = sub {
return if !defined($rule->{'icmp-type'}) || $rule->{'icmp-type'} eq '';
die "'icmp-type' can only be set if 'icmp', 'icmpv6' or 'ipv6-icmp' is specified\n"
- if ($proto ne 'icmp') && ($proto ne 'icmpv6') && ($proto ne 'ipv6-icmp');
+ if !$is_icmp;
my $type = $proto eq 'icmp' ? 'icmp-type' : 'icmpv6-type';
push @match, "-m $proto --$type $rule->{'icmp-type'}";