type => 'boolean',
optional => 1,
},
+ nf_conntrack_allow_invalid => {
+ description => "Allow invalid packets on connection tracking.",
+ type => 'boolean',
+ default => 0,
+ optional => 1,
+ },
};
our $vm_option_properties = {
} elsif ($policy eq 'REJECT') {
ruleset_addrule($ruleset, $chain, "", "-j PVEFW-Reject");
- ruleset_addrule($ruleset, $chain, "", "-g PVEFW-reject", $loglevel, "policy $policy:", $vmid);
+ ruleset_addrule($ruleset, $chain, "", "-g PVEFW-reject", $loglevel, "policy $policy: ", $vmid);
} else {
# should not happen
die "internal error: unknown policy '$policy'";
}
sub ruleset_chain_add_conn_filters {
- my ($ruleset, $chain, $accept) = @_;
+ my ($ruleset, $chain, $allow_invalid, $accept) = @_;
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID", "-j DROP");
+ if (!$allow_invalid) {
+ ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID", "-j DROP");
+ }
ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED", "-j $accept");
}
ruleset_addrule($ruleset, $chain, "-i lo", "-j ACCEPT");
- ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
+ ruleset_chain_add_conn_filters($ruleset, $chain, 0, 'ACCEPT');
ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options, 'IN', '-j RETURN');
ruleset_chain_add_input_filters($ruleset, $chain, $ipversion, $options, $cluster_conf, $loglevel);
ruleset_addrule($ruleset, $chain, "-o lo", "-j ACCEPT");
- ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
+ ruleset_chain_add_conn_filters($ruleset, $chain, 0, 'ACCEPT');
# we use RETURN because we may want to check other thigs later
$accept_action = 'RETURN';
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack|nf_conntrack_allow_invalid):\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) {
# fixme: what log level should we use here?
my $loglevel = get_option_log_level($hostfw_options, "log_level_out");
- ruleset_chain_add_conn_filters($ruleset, "PVEFW-FORWARD", "ACCEPT");
+ my $conn_allow_invalid = $hostfw_options->{nf_conntrack_allow_invalid} // 0;
+ ruleset_chain_add_conn_filters($ruleset, "PVEFW-FORWARD", $conn_allow_invalid, "ACCEPT");
ruleset_create_chain($ruleset, "PVEFW-FWBR-IN");
ruleset_chain_add_input_filters($ruleset, "PVEFW-FWBR-IN", $ipversion, $hostfw_options, $cluster_conf, $loglevel);
my $conf = $vmdata->{qemu}->{$vmid};
my $vmfw_conf = $vmfw_configs->{$vmid};
return if !$vmfw_conf;
+ my $ipsets = $vmfw_conf->{ipset};
foreach my $netid (sort keys %$conf) {
next if $netid !~ m/^net(\d+)$/;
next if !$net->{firewall};
my $iface = "tap${vmid}i$1";
my $macaddr = $net->{macaddr};
-
- generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid);
-
+ my $arpfilter = [];
+ if (defined(my $ipset = $ipsets->{"ipfilter-$netid"})) {
+ foreach my $ipaddr (@$ipset) {
+ my($ip, $version) = parse_ip_or_cidr($ipaddr->{cidr});
+ next if !$ip || ($version && $version != 4);
+ push(@$arpfilter, $ip);
+ }
+ }
+ generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter);
}
};
warn $@ if $@; # just to be sure - should not happen
my $vmfw_conf = $vmfw_configs->{$vmid};
return if !$vmfw_conf || !$vmfw_conf->{options}->{enable};
+ my $ipsets = $vmfw_conf->{ipset};
foreach my $netid (sort keys %$conf) {
next if $netid !~ m/^net(\d+)$/;
next if !$net->{firewall};
my $iface = "veth${vmid}i$1";
my $macaddr = $net->{hwaddr};
- generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid);
+ my $arpfilter = [];
+ if (defined(my $ipset = $ipsets->{"ipfilter-$netid"})) {
+ foreach my $ipaddr (@$ipset) {
+ my($ip, $version) = parse_ip_or_cidr($ipaddr->{cidr});
+ next if !$ip || ($version && $version != 4);
+ push(@$arpfilter, $ip);
+ }
+ }
+ push(@$arpfilter, $net->{ip}) if $net->{ip} && $vmfw_conf->{options}->{ipfilter};
+ generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter);
}
};
warn $@ if $@; # just to be sure - should not happen
}
sub generate_tap_layer2filter {
- my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid) = @_;
+ my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter) = @_;
my $options = $vmfw_conf->{options};
my $tapchain = $iface."-OUT";
ruleset_addrule($ruleset, $tapchain, "-s ! $macaddr", '-j DROP');
}
+ if (@$arpfilter){
+ my $arpchain = $tapchain."-ARP";
+ ruleset_addrule($ruleset, $tapchain, "-p ARP", "-j $arpchain");
+ ruleset_create_chain($ruleset, $arpchain);
+
+ foreach my $ip (@{$arpfilter}) {
+ ruleset_addrule($ruleset, $arpchain, "-p ARP --arp-ip-src $ip", '-j RETURN');
+ }
+ ruleset_addrule($ruleset, $arpchain, '', '-j DROP');
+ }
+
if (defined($options->{layer2_protocols})){
+ my $protochain = $tapchain."-PROTO";
+ ruleset_addrule($ruleset, $tapchain, '', "-j $protochain");
+ ruleset_create_chain($ruleset, $protochain);
+
foreach my $proto (split(/,/, $options->{layer2_protocols})) {
- ruleset_addrule($ruleset, $tapchain, "-p $proto", '-j ACCEPT');
+ ruleset_addrule($ruleset, $protochain, "-p $proto", '-j RETURN');
}
- ruleset_addrule($ruleset, $tapchain, '', "-j DROP");
- } else {
- ruleset_addrule($ruleset, $tapchain, '', '-j ACCEPT');
+ ruleset_addrule($ruleset, $protochain, '', '-j DROP');
}
+ ruleset_addrule($ruleset, $tapchain, '', '-j ACCEPT');
+
ruleset_addrule($ruleset, 'PVEFW-FWBR-OUT', "-i $iface", "-j $tapchain");
}