],
'NeighborDiscovery' => [
"IPv6 neighbor solicitation, neighbor and router advertisement",
+ { action => 'PARAM', proto => 'icmpv6', dport => 'router-solicitation' },
{ action => 'PARAM', proto => 'icmpv6', dport => 'router-advertisement' },
{ action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-solicitation' },
{ action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-advertisement' },
],
+ 'DHCPv6' => [
+ { action => 'PARAM', proto => 'udp', dport => '546:547', sport => '546:547' },
+ ],
'Trcrt' => [
{ action => 'PARAM', proto => 'udp', dport => '33434:33524' },
{ action => 'PARAM', proto => 'icmpv6', dport => 'echo-request' },
my $pve_fw_parsed_macros;
my $pve_fw_macro_descr;
+my $pve_fw_macro_ipversion = {};
my $pve_fw_preferred_macro_names = {};
my $pve_std_chains = {};
'echo-reply' => 1,
'router-solicitation' => 1,
'router-advertisement' => 1,
+ 'neighbor-solicitation' => 1,
'neighbour-solicitation' => 1,
+ 'neighbor-advertisement' => 1,
'neighbour-advertisement' => 1,
'redirect' => 1,
};
$pve_fw_parsed_macros = {};
- foreach my $k (keys %$pve_fw_macros) {
+ my $parse = sub {
+ my ($k, $macro) = @_;
my $lc_name = lc($k);
- my $macro = $pve_fw_macros->{$k};
- if (!ref($macro->[0])) {
- $pve_fw_macro_descr->{$k} = shift @$macro;
+ $pve_fw_macro_ipversion->{$k} = 0;
+ while (!ref($macro->[0])) {
+ my $desc = shift @$macro;
+ if ($desc eq 'ipv4only') {
+ $pve_fw_macro_ipversion->{$k} = 4;
+ } elsif ($desc eq 'ipv6only') {
+ $pve_fw_macro_ipversion->{$k} = 6;
+ } else {
+ $pve_fw_macro_descr->{$k} = $desc;
+ }
}
$pve_fw_preferred_macro_names->{$lc_name} = $k;
$pve_fw_parsed_macros->{$k} = $macro;
+ };
+
+ foreach my $k (keys %$pve_fw_macros) {
+ &$parse($k, $pve_fw_macros->{$k});
+ }
+
+ foreach my $k (keys %$pve_ipv6fw_macros) {
+ next if $pve_fw_parsed_macros->{$k};
+ &$parse($k, $pve_ipv6fw_macros->{$k});
+ $pve_fw_macro_ipversion->{$k} = 6;
}
}
next if !defined($v);
$data->{$k} = $v;
# Note: digest ignores refs ($rule->{errors})
- $sha->add($k, ':', $v, "\n") if !ref($v); ;
+ # since Digest::SHA expects a series of bytes,
+ # we have to encode the value here to prevent errors when
+ # using utf8 characters (eg. in comments)
+ $sha->add($k, ':', encode_utf8($v), "\n") if !ref($v); ;
}
push @$res, $data;
}
$macro_rules = $pve_ipv6fw_macros->{$macro_name};
}
+ # skip macros which are specific to another ipversion
+ if ($ipversion && (my $required = $pve_fw_macro_ipversion->{$macro_name})) {
+ return if $ipversion != $required;
+ }
+
my $rules = [];
foreach my $templ (@$macro_rules) {
if ($rule->{dport}) {
if ($rule->{proto} && $rule->{proto} eq 'icmp') {
# Note: we use dport to store --icmp-type
- die "unknown icmp-type '$rule->{dport}'\n" if !defined($icmp_type_names->{$rule->{dport}});
+ die "unknown icmp-type '$rule->{dport}'\n"
+ if $rule->{dport} !~ /^\d+$/ && !defined($icmp_type_names->{$rule->{dport}});
push @cmd, "-m icmp --icmp-type $rule->{dport}";
} elsif ($rule->{proto} && $rule->{proto} eq 'icmpv6') {
# Note: we use dport to store --icmpv6-type
- die "unknown icmpv6-type '$rule->{dport}'\n" if !defined($icmpv6_type_names->{$rule->{dport}});
+ die "unknown icmpv6-type '$rule->{dport}'\n"
+ if $rule->{dport} !~ /^\d+$/ && !defined($icmpv6_type_names->{$rule->{dport}});
push @cmd, "-m icmpv6 --icmpv6-type $rule->{dport}";
} else {
if ($nbdport > 1) {
}
}
+sub ruleset_chain_add_ndp {
+ my ($ruleset, $chain, $ipversion, $options) = @_;
+ return if $ipversion != 6 || (defined($options->{ndp}) && !$options->{ndp});
+
+ ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type router-solicitation -j ACCEPT");
+ ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type router-advertisement -j ACCEPT");
+ ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT");
+ ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT");
+}
+
sub ruleset_chain_add_conn_filters {
my ($ruleset, $chain, $accept) = @_;
}
}
+ ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options);
+
if ($direction eq 'OUT') {
if (defined($macaddr) && !(defined($options->{macfilter}) && $options->{macfilter} == 0)) {
ruleset_addrule($ruleset, $chain, "-m mac ! --mac-source $macaddr -j DROP");
ruleset_addrule($ruleset, $chain, "-i lo -j ACCEPT");
+ ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options);
ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
ruleset_chain_add_input_filters($ruleset, $chain, $ipversion, $options, $cluster_conf, $loglevel);
ruleset_addrule($ruleset, $chain, "-o lo -j ACCEPT");
+ ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options);
ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
# we use RETURN because we may want to check other thigs later
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|dhcp|macfilter|ips):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|dhcp|ndp|macfilter|ips):\s*(0|1)\s*$/i) {
$opt = lc($1);
$value = int($2);
} elsif ($line =~ m/^(log_level_in|log_level_out):\s*(($loglevels)\s*)?$/i) {
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|nosmurfs|tcpflags):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp):\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) {