What is a DDoS attack?
Simply put, a DDoS, or Distributed Denial of Service, is when many devices from many separate IP addresses send large amounts of traffic to your server in an attempt to take it down. These are slightly different from DoS attacks, in which only one device is attacking. DoS attacks can be mitigated rather easily because of the fact that they’re only coming from one IP address. But, how do you protect against DDOS?
How to Protect Against DDOS Attacks
The answer? iptables
The majority of tutorials on DDoS protection give you a bunch of iptables rules. You’re probably wondering, why not just use those rules along with UFW. While you _technically _can, UFW rules generally run before iptables rules, so if a port is open with UFW, then no other iptables rule will affect that traffic. I will be using JavaPipe’s rules. They work amazing(I’ve tested them with a small DoS attack, and my system practically didn’t even notice), but don’t work if UFW is installed. Download IPtables list and modify as per your requirement
Enter before.rules
More or less, the only iptables rules that affect UFW are what’s in /etc/ufw/before*.rules. These rules are added before the standard UFW rules(generated with the Ufw command) to protect against DDOS attack. So, add the following to /etc/Ufw/before.rules and /etc/Ufw/before6.rules:
#ANTI DDOS
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -m conntrack --ctstate INVALID -j DROP
-A PREROUTING -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
-A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP
-A PREROUTING -m conntrack --ctstate INVALID -j DROP
-A PREROUTING -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
-A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP
-A PREROUTING -p tcp -m state --state NEW -m recent --set --name DEFAULT --rsource
-A PREROUTING -p tcp -m state --state NEW -m recent --update --seconds 10 --hitcount 25 --name DEFAULT --rsource -j DROP
-A PREROUTING -p icmp -m limit --limit 2/sec -j ACCEPT
-A PREROUTING -p icmp -j DROP
COMMIT
# Completed on Sun Jan 14 21:47:45 2018
# Generated by ip6tables-save v1.6.0 on Sun Jan 14 21:47:45 2018
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p tcp -m connlimit --connlimit-above 25 --connlimit-mask 128 --connlimit-saddr -j REJECT --reject-with tcp-reset
-A INPUT -p tcp -m tcp --tcp-flags RST RST -j DROP
-A INPUT -p tcp -m conntrack --ctstate NEW -j DROP
COMMIT
In case you’re wondering, these are essentially an iptables-save
dump from a server after I added all the relevant rules. If you have limited knowledge on iptables, why don’t you download iptables tutorial?
A bit more…
Now just run
sudo ufw reload
and the settings should take effect. Not everything on JavaPipe is on here because I use a VPN, so the internal IPs must work, so I didn’t use the anti-false IP rules. I also left ICMP unblocked, because I use ping every now and then to see if my server has an SSH problem or a network problem. Also, they recommend you add the following to /etc/sysctl.conf
:
kernel.printk = 4 4 1 7
kernel.panic = 10
kernel.sysrq = 0
kernel.shmmax = 4294967296
kernel.shmall = 4194304
kernel.core_uses_pid = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
vm.dirty_ratio = 80
vm.dirty_background_ratio = 5
fs.file-max = 2097152
net.core.netdev_max_backlog = 262144
net.core.rmem_default = 31457280
net.core.rmem_max = 67108864
net.core.wmem_default = 31457280
net.core.wmem_max = 67108864
net.core.somaxconn = 65535
net.core.optmem_max = 25165824
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384
net.ipv4.neigh.default.gc_interval = 5
net.ipv4.neigh.default.gc_stale_time = 120
net.netfilter.nf_conntrack_max = 10000000
net.netfilter.nf_conntrack_tcp_loose = 0
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.ip_no_pmtu_disc = 1
net.ipv4.route.flush = 1
net.ipv4.route.max_size = 8048576
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_congestion_control = htcp
net.ipv4.tcp_mem = 65536 131072 262144
net.ipv4.udp_mem = 65536 131072 262144
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.udp_rmem_min = 16384
net.ipv4.tcp_wmem = 4096 87380 33554432
net.ipv4.udp_wmem_min = 16384
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 400000
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rfc1337 = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_fack = 1
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 10
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1
I just put what I use to protect against DDOS attack, which is like three lines less than the original. To be honest, I have no idea what most of them do(I understand many of the networking ones), but from my testing with ab on a more powerful server, these rules are effective. Now reboot, or because you’re on Linux 🙂 , just run
sudo sysctl -a
Additional tips
If you’re using UFW, there are a few more steps you can take to prevent your server from going down. You’re probably familiar with
ufw allow 22/tcp
This allows connections to TCP port 22, which is most commonly used for SSH. For extra protection, however, use “limit” like so:
ufw limit 22/tcp
This will overwrite “allow” rules if they exist for the same port. What this does is rate limit that port to 6 new connections per IP per 30 seconds. This works on many other services as well. However, remember that sometimes receiving more than 6 connections in 30 seconds is normal. For example, refreshing the page, or clicking on a link more than once within 30 seconds isn’t exactly rare. Rate limiting on TCP 80 and/or 443 could result in browsers not being able to access your website. To resolve this, simply don’t use rate-limiting on those ports, or allow certain IP addresses(i.e. Cloudflare’s) unmetered access(i.e. ufw insert 1 allow from IP_ADDR to any port 443
), and limit everyone else.