-t >>> set a table to operate opon (for firewalls often ‘filter’, for NAT config is ‘nat’)
-L >>> show config for a chain or all chains without name specification
-S >>> show rulses for a chain or all chains
-F >>> flush rules for a chain or all chains
-P [chain] [target] >>> set the default policy for a chain
-A [cahin]>>> specify a chain
-D [cahin] [rule] >>> delete a rule form a chain (by number or rule specification)
-I [chain] [num] [rule] >>> add new rule to a chain
-R [chain] [num] [rule] >>> replace an existing rule in a chain
-m [name] >>> adds extended matching rules provided by module name
-p [protocol] >>> tcp, udp, udplite, icmp, esp, shtp, all
--sport >>> specify source port or 1:65535 for a port range
--dport >>> specify destination port or 1:65535 for a port range
-s >>> source address or 192.168.1.0/24 for a net block
-d >>> destiation address or 192.168.1.0/24 for a net block
-i >>> input interface only
-o >>> output interface only
--state >>> connection state: INVALID, NEW, ESTABLISHED, RELATED
-j [target] >>> action: ACCEPT, DROP, REJECT
-g [chain] >>> continue the process in another chain
-nL >>> show numeric IPs and ports
-nvL >>> more verbose output
Tables
By default there are three tables in the kernel that contain sets of rules.
The filter table is used for packet filtering
The nat table is used for address translation
The mangle table can be used for special-purpose processing of packets
Filter Table
Packet filtering is a bit more than packet forwarding. While packet forwarding uses only a routing table to make decisions, packet filtering also uses a list of rules. The kernel will inspect packets and decide based on these rules what to do with each packet.
The filter table in iptables has three chains (sets of rules). The INPUT chain is used for any packet coming into the system. The OUTPUT chain is for any packet leaving the system. And the FORWARD chain is for packets that are forwarded (routed) through the system.
Setting Default Policy
The most secure firewall policy would be to DROP everything and then specifically accept some traffic. A package that is dropped will not continue in any chain, and no warning or error will be sent anywhere.
The below commands lock down a computer. Do not execute these commands inside a remote SSH shell.
Resetting Default Policies and Stopping the Firewall:
ipbles -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
Allow Loopback Access
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# see the results
iptables -n -L -v --line-number
Allow ICMP echo (ping)
ICMP types:
use --icmp-type 8 for echo request only
type 0 → echo reply
type 3 → destination unreachable messages
type 5 → redirect messages
type 8 → echo request
type 11 → time exceeded messages
type 12 → parameter problem messages
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type any -j ACCEPT
Route Pings
The previous two lines do not allow other computers to route ping messages through your router, because it only handles INPUT and OUTPUT.
For routing of ping, you will need to enable it on the FORWARD chain. The following command enables routing of icmp messages between networks.
iptables -A FORWARD -p icmp --icmp-type any -j ACCEPT
Allow Established & Outbound Connections
The following commands will implement a policy to allow all outbound connections and all established TCP, UDP and ICMP connections:
# iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
Using the state module alone, INVALID will break protocols that use bi-directional connections or multiple connections or exchanges, unless an ALG is provided for the protocol.
Refuse spoofed Packets
Refuse spoofed packets pretending to be from the external interface's IP address.
iptables -A INPUT -i $INTERNET -s $IPADDR -j DROP
Refuse packets claiming to be from a Class A private network.
iptables -A INPUT -i $INTERNET -s $CLASS_A -j DROP
Refuse packets claiming to be from the loopback interface.
iptables -A INPUT -i $INTERNET -s $LOOPBACK -j DROP
Refuse malformed broadcast packets
iptables -A INPUT -i $INTERNET -s $BROADCAST_DEST -j LOG
iptables -A INPUT -i $INTERNET -s $BROADCAST_DEST -j DROP
iptables -A INPUT -i $INTERNET -d $BROADCAST_SRC -j LOG
iptables -A INPUT -i $INTERNET -d $BROADCAST_SRC -j DROP
Refuse directed broadcasts (Used to map networks and in Denial of Service attacks)
iptables -A INPUT -i $INTERNET -d $SUBNET_BASE -j DROP
iptables -A INPUT -i $INTERNET -d $SUBNET_BROADCAST -j DROP
Refuse limited broadcasts
iptables -A INPUT -i $INTERNET -d $BROADCAST_DEST -j DROP
Don't put logging rules at the top of your table as the first rule, otherwise iptables will log EVERYTHING and will lead to a DoS condition if you dont have enough resource to store that data.
A best practice is to add logging rules at the end of the table as the last rule so anything that is not filtered by other rules will be logged.
Remember that anything you drop before the log rules will not be logged.
add these at the end:
iptables -A INPUT -j LOG
iptables -A OUTPUT -j LOG
iptables -A FORWARD -j LOG
These sysctl.conf settings help to maximize the performance of your server under DDoS as well as the effectiveness of the iptables rules.
IPtables Anti-DDoS Rules
Block New Packets That Are Not SYN:
iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP
This blocks all packets that are new (don’t belong to an established connection) and don’t use the SYN flag. This rule is similar to the “Block Invalid Packets” one, but we found that it catches some packets that the other one doesn’t.
Block Uncommon MSS Values:
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
The above iptables rule blocks new packets (only SYN packets can be new packets as per the two previous rules) that use a TCP MSS value that is not common. This helps to block dumb SYN floods.
Block Packets With Bogus TCP Flags:
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP
The above ruleset blocks packets that use bogus TCP flags, ie. TCP flags that legitimate packets wouldn’t use.
Block Packets From Private Subnets (Spoofing):
iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP
iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP
iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP
iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP
iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP
iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP
iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP
iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP
iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP
These rules block spoofed packets originating from private (local) subnets. On your public network interface you usually don’t want to receive packets from private source IPs.
These rules assume that your loopback interface uses the 127.0.0.0/8 IP space.
These five sets of rules alone already block many TCP-based DDoS attacks at very high packet rates.
With the kernel settings and rules mentioned above, you’ll be able to filter ACK and SYN-ACK attacks at line rate.
It rejects connections from hosts that have more than 80 established connections. If you face any issues you should raise the limit as this could cause troubles with legitimate clients that establish a large number of TCP connections.
Limit the new TCP connections that a client can establish per second:
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP
This can be useful against connection attacks, but not so much against SYN floods because the usually use an endless amount of different spoofed source IPs.
block fragmented packets:
iptables -t mangle -A PREROUTING -f -j DROP
Normally you don’t need those and blocking fragments will mitigate UDP fragmentation flood. But most of the time UDP fragmentation floods use a high amount of bandwidth that is likely to exhaust the capacity of your network card, which makes this rule optional and probably not the most useful one.
limits incoming TCP RST packets to mitigate TCP RST floods:
iptables -A INPUT -p tcp --tcp-flags RST RST -m limit --limit 2/s --limit-burst 2 -j ACCEPT
iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP
Mitigating SYN Floods With SYNPROXY
SYNPROXY is a new target of iptables that has been added in Linux kernel version 3.12 and iptables 1.4.21. CentOS 7 backported the feature and it’s available in its 3.10 default kernel.
The purpose of SYNPROXY is to check whether the host that sent the SYN packet actually establishes a full TCP connection or just does nothing after it sent the SYN packet.
If it does nothing, it discards the packet with minimal performance impact.
Here are iptables SYNPROXY rules that help mitigate SYN floods that bypass our other rules:
iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Per-IP packet limits
iptables -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSHLIMIT --rsource
iptables -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSHLIMIT --update --seconds 180 --hitcount 5 --name SSH --rsource -j DROP
Custom Chains
/iptables -N ssh-rules
iptables -A ssh-rules -s 18.130.0.0/16 -j ACCEPT
iptables -A ssh-rules -s 18.11.0.0/16 -j ACCEPT
iptables -A ssh-rules -j DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -j ssh-rules
iptables -X ssh-rules
save/restore/persistent
Use iptables save to automatically implement these rules when the firewall is (re)started.