iptables
WIP
Basic operations
List the rules
Remove a rule
iptables -D INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -D INPUT 12
Insert a rule
Network range
IP Address
MAC Address
Limit connections
iptables -A FORWARD -m state --state NEW -p tcp -m multiport --dport http,https -o eth0 -i eth1 -m limit --limit 50/hour --limit-burst 5 -j ACCEPT
Limit concurrent connections
Limit concurrent connections per IP
Time based connections
iptables -A INPUT -p tcp -m tcp --dport 443 -i enp3s0 -m time --timestart 12:30 --timestop 13:30 --days Mon,Tue,Wed,Thu,Fri -j ACCEPT
Multiple ports
iptables -A INPUT -i eth0 -p tcp -m state --state NEW -m multiport --dports ssh,smtp,http,https -j ACCEPT
Replace a rule
Default chain policy
Log rules
/var/log/messages or journalctl.
Aug 15 05:30:58 server kernel: iptables-ssh: IN=eth0 OUT= MAC=52:54:00:16:56:7f:52:54:00:0f:b2:e4:08:00 SRC=192.168.1.229 DST=192.168.1.129 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57381 DF PROTO=TCP SPT=45910 DPT=22 WINDOW=29200 RES=0x00 SYN URGP=0
Filter by owner
iptables -A OUTPUT -d 192.168.1.100 -m owner --uid-owner bob -j DROP
iptables -A OUTPUT -d 192.168.1.100 -m owner --gid-owner bob -j DROP
Saving the rules
conntrack or state for connection tracking (new, invalid, established, ...)
conntrack is much more complete than state; state only matches INVALID, NEW, ESTABLISHED, RELATED or UNTRACKED; conntrack can match ip orig/src, port orig/src, direction, status, expire time, and some others (see man iptables-extensions).
Example:
The same rule with conntrack:
iptables -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.1.15 --ctorigdstport 22 -i enp3s0 -j ACCEPT
Maybe state is obsolete and you should use conntrack but they both do the same.
Example script
#!/usr/bin/env sh
## Flush all chains
iptables -F
iptables -t nat -F
iptables -t mangle -F
## Delete all chains
iptables -X
## Default chain policy
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
## Rest of the rules
[...]
## Save
iptables-save > /etc/iptables/iptables.rules
ip6tables-save > /etc/iptables/ip6tables.rules
Example rules
## Drop all invalid connections
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
## Refuse connections without SYN flag
iptables -A INPUT -p tcp ! --syn -m conntrack --ctstate NEW -j DROP
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -j DROP
## Drop Christmas tree packets
iptables -A INPUT -p tcp -m tcp --tcp-flags ALL FIN,PSH,URG -j DROP
## Drop other invalid packets
iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
## Allows all loopback (lo0) traffic and reject all traffic to 127/8 that doesn't use lo0
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
## Allow established connections
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
## Enable routing.
echo 1 > /proc/sys/net/ipv4/ip_forward
## Enable routing permanently
sysctl -w net.ipv4.ip_forward=1
## Ping with rate limit
iptables -A INPUT -p icmp -m limit --limit 1/sec --limit-burst 1 -j ACCEPT
## SSH
ssh="192.168.1.15,192.168.1.20"
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -i enp3s0 -s "$ssh" -j ACCEPT
Quick logging of connections
Create rules
# TCP
sudo iptables -I INPUT 1 -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_IN: " --log-level 4
sudo iptables -I FORWARD 1 -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_FWD: " --log-level 4
sudo iptables -I OUTPUT 1 -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_OUT: " --log-level 4
# UDP
sudo iptables -I INPUT 1 -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_IN: " --log-level 4
sudo iptables -I FORWARD 1 -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_FWD: " --log-level 4
sudo iptables -I OUTPUT 1 -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_OUT: " --log-level 4
Get data
journalctl --since yesterday -k -o short-iso \
| grep 'IPT_NEW_' \
| awk '
{
# ISO timestamp is the first token with -o short-iso
ts = $1
# extract fields
src = (match($0,/SRC=([^ ]+)/,a) ? a[1] : "-")
proto = (match($0,/PROTO=([^ ]+)/,b) ? b[1] : "-")
if (match($0,/DPT=([^ ]+)/,c)) port=c[1]
else if (match($0,/SPT=([^ ]+)/,c)) port=c[1]
else port="-"
key = src "|" proto "|" port
cnt[key]++
if (last[key]=="" || ts > last[key]) last[key]=ts
}
END {
# print CSV-like lines: count,src,proto,port,last_ts
for (k in cnt) {
split(k,parts,"|")
printf "%d,%s,%s,%s,%s\n", cnt[k], parts[1], parts[2], parts[3], last[k]
}
}
' \
| sort -t, -k1,1nr \
| awk -F, 'BEGIN { printf "%-20s %-6s %-6s %-25s %6s\n","SOURCE","PROTO","PORT","LAST_TIMESTAMP","HITS" }
{ printf "%-20s %-6s %-6s %-25s %6d\n", $2,$3,$4,$5,$1 }'
Remove rules
# TCP
sudo iptables -D INPUT -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_IN: " --log-level 4
sudo iptables -D FORWARD -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_FWD: " --log-level 4
sudo iptables -D OUTPUT -p tcp -m conntrack --ctstate NEW -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_TCP_OUT: " --log-level 4
# UDP
sudo iptables -D INPUT -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_IN: " --log-level 4
sudo iptables -D FORWARD -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_FWD: " --log-level 4
sudo iptables -D OUTPUT -p udp -m conntrack --ctstate NEW -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "IPT_NEW_UDP_OUT: " --log-level 4
Links
https://www.booleanworld.com/depth-guide-iptables-linux-firewall/