[pve-devel] [PATCH pve-firewall 2/2] add synflood protection
Alexandre Derumier
aderumier at odiso.com
Tue Nov 12 13:59:04 CET 2019
Currently, a virtio-net + vhost-net can handle between 200-300 kpps for each vm (with 1core/queue=1).
That mean than a vm can easily overloaded with a simple synflood (hping3 --flood -p 80 -S targetip).
Also the conntrack of the host can be saturated easily.
This patch introduce a new option, enable rate limiting of syn/s by src ip (protection_synflood:1).
rate limit can be set with : protection_synflood_rate (default 200 syn/s)
with an extra burst: protection_synflood_rate (default 1000).
It's also possible to reduce conntrack syn timeout: nf_conntrack_tcp_timeout_syn_recv (default 60).
with default values, a src ip can take around (60 * 200 = 12000 conntrack entries).
The iptables rules are done in raw table, before reaching the conntrack.
This protection works fine for non-spoofed src ip.
For spoofed src ip, the only way could be to implement SYNPROXY,
but this only works for routed/nat setup. (The host need to be able to reply
with the src ip the vm)
Some good information about synflood protections
https://2014.rmll.info/slides/356/day_1-1400-Jesper_Brouer-DDoS_protection_using_Netfilter_iptables.pdf
---
src/PVE/Firewall.pm | 58 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm
index 8f4ff1a..db16e0f 100644
--- a/src/PVE/Firewall.pm
+++ b/src/PVE/Firewall.pm
@@ -1273,6 +1273,14 @@ our $host_option_properties = {
default => 432000,
minimum => 7875,
},
+ nf_conntrack_tcp_timeout_syn_recv => {
+ description => "Conntrack syn recv timeout.",
+ type => 'integer',
+ optional => 1,
+ default => 60,
+ minimum => 30,
+ maximum => 60,
+ },
ndp => {
description => "Enable NDP (Neighbor Discovery Protocol).",
type => 'boolean',
@@ -1285,6 +1293,24 @@ our $host_option_properties = {
default => 0,
optional => 1,
},
+ protection_synflood => {
+ description => "Enable synflood protection",
+ type => 'boolean',
+ default => 0,
+ optional => 1,
+ },
+ protection_synflood_rate => {
+ description => "Synflood protection rate syn/sec by ip src.",
+ type => 'integer',
+ optional => 1,
+ default => 200,
+ },
+ protection_synflood_burst => {
+ description => "Synflood protection rate burst by ip src.",
+ type => 'integer',
+ optional => 1,
+ default => 1000,
+ },
log_nf_conntrack => {
description => "Enable logging of conntrack information.",
type => 'boolean',
@@ -2752,13 +2778,13 @@ sub parse_hostfw_option {
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack|nf_conntrack_allow_invalid):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack|nf_conntrack_allow_invalid|protection_synflood):\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) {
$opt = lc($1);
$value = $2 ? lc($3) : '';
- } elsif ($line =~ m/^(nf_conntrack_max|nf_conntrack_tcp_timeout_established):\s*(\d+)\s*$/i) {
+ } elsif ($line =~ m/^(nf_conntrack_max|nf_conntrack_tcp_timeout_established|nf_conntrack_tcp_timeout_syn_recv|protection_synflood_rate|protection_synflood_burst|protection_limit):\s*(\d+)\s*$/i) {
$opt = lc($1);
$value = int($2);
} else {
@@ -3572,6 +3598,22 @@ sub compile_iptables_raw {
my $ruleset = {};
+ my $hostfw_options = $hostfw_conf->{options} || {};
+ my $protection_synflood = $hostfw_options->{protection_synflood} || 0;
+
+ if($protection_synflood) {
+
+ my $protection_synflood_rate = $hostfw_options->{protection_synflood_rate} ? $hostfw_options->{protection_synflood_rate} : 200;
+ my $protection_synflood_burst = $hostfw_options->{protection_synflood_burst} ? $hostfw_options->{protection_synflood_burst} : 1000;
+ my $protection_synflood_limit = $hostfw_options->{protection_synflood_limit} ? $hostfw_options->{protection_synflood_limit} : 3000;
+ my $protection_synflood_expire = $hostfw_options->{nf_conntrack_tcp_timeout_syn_recv} ? $hostfw_options->{nf_conntrack_tcp_timeout_syn_recv} : 60;
+ $protection_synflood_expire = $protection_synflood_expire * 1000;
+ my $protection_synflood_mask = $ipversion == 4 ? 32 : 64;
+
+ ruleset_create_chain($ruleset, "PVEFW-PREROUTING");
+ ruleset_addrule($ruleset, "PVEFW-PREROUTING", "-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m hashlimit --hashlimit-above $protection_synflood_rate/sec --hashlimit-burst $protection_synflood_burst --hashlimit-mode srcip --hashlimit-name syn --hashlimit-htable-size 2097152 --hashlimit-srcmask $protection_synflood_mask --hashlimit-htable-expire $protection_synflood_expire", "-j DROP");
+ }
+
return $ruleset;
}
@@ -4286,6 +4328,8 @@ sub apply_ruleset {
update_nf_conntrack_tcp_timeout_established($hostfw_conf);
+ update_nf_conntrack_tcp_timeout_syn_recv($hostfw_conf);
+
update_nf_conntrack_logging($hostfw_conf);
}
@@ -4323,6 +4367,16 @@ sub update_nf_conntrack_tcp_timeout_established {
PVE::ProcFSTools::write_proc_entry("/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established", $value);
}
+sub update_nf_conntrack_tcp_timeout_syn_recv {
+ my ($hostfw_conf) = @_;
+
+ my $options = $hostfw_conf->{options} || {};
+
+ my $value = defined($options->{nf_conntrack_tcp_timeout_syn_recv}) ? $options->{nf_conntrack_tcp_timeout_syn_recev} : 60;
+
+ PVE::ProcFSTools::write_proc_entry("/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv", $value);
+}
+
my $log_nf_conntrack_enabled = undef;
sub update_nf_conntrack_logging {
my ($hostfw_conf) = @_;
--
2.20.1
More information about the pve-devel
mailing list