use PVE::JSONSchema qw(register_standard_option get_standard_option);
use PVE::Cluster;
use PVE::ProcFSTools;
-use PVE::Tools qw($IPV4RE);
+use PVE::Tools qw($IPV4RE $IPV6RE);
use File::Basename;
use File::Path;
use IO::File;
my $max_ipset_name_length = 64;
my $max_group_name_length = 20;
-PVE::JSONSchema::register_format('IPv4orCIDR', \&pve_verify_ipv4_or_cidr);
-sub pve_verify_ipv4_or_cidr {
+PVE::JSONSchema::register_format('IPorCIDR', \&pve_verify_ip_or_cidr);
+sub pve_verify_ip_or_cidr {
my ($cidr, $noerr) = @_;
- if ($cidr =~ m!^(?:$IPV4RE)(/(\d+))?$!) {
+ if ($cidr =~ m!^(?:$IPV6RE|$IPV4RE)(/(\d+))?$!) {
return $cidr if Net::IP->new($cidr);
return undef if $noerr;
die Net::IP::Error() . "\n";
die "value does not look like a valid IP address or CIDR network\n";
}
-PVE::JSONSchema::register_format('IPv4orCIDRorAlias', \&pve_verify_ipv4_or_cidr_or_alias);
-sub pve_verify_ipv4_or_cidr_or_alias {
+PVE::JSONSchema::register_format('IPorCIDRorAlias', \&pve_verify_ip_or_cidr_or_alias);
+sub pve_verify_ip_or_cidr_or_alias {
my ($cidr, $noerr) = @_;
return if $cidr =~ m/^(?:$ip_alias_pattern)$/;
- if ($cidr =~ m!^(?:$IPV4RE)(/(\d+))?$!) {
- return $cidr if Net::IP->new($cidr);
- return undef if $noerr;
- die Net::IP::Error() . "\n";
- }
- return undef if $noerr;
- die "value does not look like a valid IP address or CIDR network\n";
+ return pve_verify_ip_or_cidr($cidr, $noerr);
}
PVE::JSONSchema::register_standard_option('ipset-name', {
};
my $check_ipset_or_alias_property = sub {
- my ($name) = @_;
+ my ($name, $expected_ipversion) = @_;
if (my $value = $rule->{$name}) {
if ($value =~ m/^\+/) {
} elsif ($value =~ m/^${ip_alias_pattern}$/){
my $alias = lc($value);
&$add_error($name, "no such alias '$value'")
- if !($cluster_conf->{aliases}->{$alias} || ($fw_conf && $fw_conf->{aliases}->{$alias}))
+ if !($cluster_conf->{aliases}->{$alias} || ($fw_conf && $fw_conf->{aliases}->{$alias}));
+
+ my $e = $fw_conf->{aliases}->{$alias} if $fw_conf;
+ $e = $cluster_conf->{aliases}->{$alias} if !$e && $cluster_conf;
+
+ die "detected mixed ipv4/ipv6 adresses in rule\n"
+ if $expected_ipversion && ($expected_ipversion != $e->{ipversion});
}
}
};
if ($rule->{source}) {
eval { $ipversion = parse_address_list($rule->{source}); };
&$add_error('source', $@) if $@;
- &$check_ipset_or_alias_property('source');
+ &$check_ipset_or_alias_property('source', $ipversion);
}
if ($rule->{dest}) {
eval {
my $dest_ipversion = parse_address_list($rule->{dest});
die "detected mixed ipv4/ipv6 adresses in rule\n"
- if defined($ipversion) && ($dest_ipversion != $ipversion);
- $ipversion = $dest_ipversion;
+ if $ipversion && $dest_ipversion && ($dest_ipversion != $ipversion);
+ $ipversion = $dest_ipversion if $dest_ipversion;
};
&$add_error('dest', $@) if $@;
- &$check_ipset_or_alias_property('dest');
+ &$check_ipset_or_alias_property('dest', $ipversion);
}
if ($rule->{macro} && !$error_count) {
return $cidr;
}
+sub parse_ip_or_cidr {
+ my ($cidr) = @_;
+
+ my $ipversion;
+
+ if ($cidr =~ m!^(?:$IPV6RE)(/(\d+))?$!) {
+ $cidr =~ s|/128$||;
+ $ipversion = 6;
+ } elsif ($cidr =~ m!^(?:$IPV4RE)(/(\d+))?$!) {
+ $cidr =~ s|/32$||;
+ $ipversion = 4;
+ } else {
+ die "value does not look like a valid IP address or CIDR network\n";
+ }
+
+ return wantarray ? ($cidr, $ipversion) : $cidr;
+}
+
sub parse_alias {
my ($line) = @_;
if ($line =~ m/^(\S+)\s(\S+)$/) {
my ($name, $cidr) = ($1, $2);
- $cidr =~ s|/32$||;
- pve_verify_ipv4_or_cidr($cidr);
+ my $ipversion;
+
+ ($cidr, $ipversion) = parse_ip_or_cidr($cidr);
+
my $data = {
name => $name,
cidr => $cidr,
+ ipversion => $ipversion,
};
$data->{comment} = $comment if $comment;
return $data;
if ($cidr =~ m/^${ip_alias_pattern}$/) {
resolve_alias($cluster_conf, $res, $cidr); # make sure alias exists
} else {
- $cidr =~ s|/32$||;
- pve_verify_ipv4_or_cidr_or_alias($cidr);
+ $cidr = parse_ip_or_cidr($cidr);
}
};
if (my $err = $@) {