Firewall basics
Contents
Set IP preference
If you enable IPv6 then that will be the default.
Recommended solution : IPv6 is now available in a lot of places. It's time to use it!
If you don't want to use IPv6 you can force IPv4 mode. This is not recommended any-more! IPv6 is becoming bigger and bigger, you need to switch.
You can override that and set IPv4 as the default protocol:
vim /etc/gai.conf
About line 54, un-comment the following line:
#
# For sites which prefer IPv4 connections change the last line to
#
precedence ::ffff:0:0/96 100
Global networking configuration
Enable modules
First things first! Before writing any rule you have to enable the required modules in your current O.S.
- Note -
If your server is hosted over Internet then you're probably using a custom Kernel (such as OVH, Tripnet, ...). In that case most modules are already enabled.
MODPROBE=`which modprobe`
echo -e " "
echo -e "-----------------------------"
echo -e " Enable networking modules"
echo -e "-----------------------------"
##### IPv4
$MODPROBE ip_tables
$MODPROBE iptable_filter
$MODPROBE iptable_mangle
# Allow to use state match
$MODPROBE ip_conntrack
# Allow NAT
$MODPROBE iptable_nat
##### IPv6
$MODPROBE ip6_tables
$MODPROBE ip6table_filter
$MODPROBE ip6table_mangle
##### Allow active / passive FTP
$MODPROBE ip_conntrack_ftp
$MODPROBE ip_nat_ftp
##### Allow log limits
echo " ... burst limit"
$MODPROBE ipt_limit
Set network features
Now that you've enable some modules, you need to choose which network features you're gonna use or not.
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
echo -e " "
echo -e "------------------------"
echo -e " Set network features"
echo -e "------------------------"
echo " ... Enable common Linux protections"
# Avoid broadcast echo
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# avoid TCP SYN Cookie
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# protection against bogus responses
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
# Avoid IP Spoofing (discard non routable IP@)
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f; done
# Avoid ICMP redirect
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
echo 0 > /proc/sys/net/ipv6/conf/all/accept_redirects
# Avoid Source Routed
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 0 > /proc/sys/net/ipv6/conf/all/accept_source_route
## Check TCP window
echo 1 > /proc/sys/net/ipv4/tcp_window_scaling
## Avoid DoS
echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time
## Adjust TTL value
echo 64 > /proc/sys/net/ipv4/ip_default_ttl
# Enable port forwarding in general
# (i) Some might argue that it should only be done by routers...
# Since I'm using a VPN, I like to access both networks and exchange data between them.
# That's why port forwarding is enable.
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 2 > /proc/sys/net/ipv6/conf/all/use_tempaddr
echo 2 > /proc/sys/net/ipv6/conf/default/use_tempaddr
echo 2 > /proc/sys/net/ipv6/conf/eth0/use_tempaddr
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
echo 0 > /proc/sys/net/ipv6/conf/default/forwarding
echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding
Default policy
Attacks types
As a reminder, there are 3 different kind of attacks:
- INPUT = intrusion. Someone want something from your computer, NOW.
- OUTPUT = disclosure. Someone want something from your computer or network - and you might give it LATER.
- FORWARD = get access. someone want something from your network. ... Or even worse: they will use your computer to perform attacks on your behalf!
You can read more about each attack over Internet.
Set default policies
This is how you defined a default policy.
- You should set all policies in ACCEPT ; and DROP the packets at the end of your firewall. By doing so you'll probably not be locked away from your server in case of firewall change.
- You should keep the RELATED and ESTABLISHED connections
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
echo -e " "
echo -e "------------------------"
echo -e " Flush existing rules "
echo -e "------------------------"
# Delete GENERIC rules
$IP6TABLES -F
$IP6TABLES -X
$IPTABLES -F
$IPTABLES -X
# delete FILTER rule (in/out)
$IPTABLES -t filter -F
$IPTABLES -t filter -X
$IP6TABLES -t filter -F
$IP6TABLES -t filter -X
# delete MANGLE rules (packets modifications)
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
$IP6TABLES -t mangle -F
$IP6TABLES -t mangle -X
# delete NAT rules [IPv4 only]
$IPTABLES -t nat -F
$IPTABLES -t nat -X
echo -e " "
echo -e "------------------------"
echo -e " Default policy"
echo -e "------------------------"
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IP6TABLES -P INPUT ACCEPT
$IP6TABLES -P FORWARD ACCEPT
$IP6TABLES -P OUTPUT ACCEPT
echo -e " "
echo -e "------------------------"
echo -e " Keep connections"
echo -e "------------------------"
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IP6TABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IP6TABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IP6TABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
[...]
# End of script (optional)
$IPTABLES -A INPUT -j DROP
$IP6TABLES -A INPUT -j DROP
$IPTABLES -A OUTPUT -j DROP
$IP6TABLES -A OUTPUT -j DROP
Basic protection and protocol(s) enforcement
Basic (minimal) protection
You should put some minimal protection. This layer relies on your O.S and its internal checks. Most of the time that's enough to block malformed and suspicious packets.
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
#####################
### All protocols ###
#####################
# Reject invalid packets
$IPTABLES -A INPUT -m state --state INVALID -m comment --comment "Invalid input" -j DROP
$IPTABLES -A OUTPUT -m state --state INVALID -m comment --comment "Invalid input" -j DROP
$IPTABLES -A FORWARD -m state --state INVALID -m comment --comment "Invalid forward" -j DROP
$IP6TABLES -A INPUT -m state --state INVALID -m comment --comment "Invalid input" -j DROP
$IP6TABLES -A OUTPUT -m state --state INVALID -m comment --comment "Invalid input" -j DROP
$IP6TABLES -A FORWARD -m state --state INVALID -m comment --comment "Invalid forward" -j DROP
# Ensure TCP connection requests start with SYN flag
$IPTABLES -A INPUT -p tcp -m state --state NEW ! --syn -m comment --comment "Invalid conn request" -j DROP
$IPTABLES -A OUTPUT -p tcp -m state --state NEW ! --syn -m comment --comment "Invalid conn request" -j DROP
$IP6TABLES -A INPUT -p tcp -m state --state NEW ! --syn -m comment --comment "Invalid conn request" -j DROP
$IP6TABLES -A OUTPUT -p tcp -m state --state NEW ! --syn -m comment --comment "Invalid conn request" -j DROP
############
### IPv4 ###
############
## Localhost
$IPTABLES -A INPUT ! -i lo -s 127.0.0.0/24 -m comment --comment "Reject none loopback on 'lo'" -j DROP
$IPTABLES -A OUTPUT ! -o lo -d 127.0.0.0/24 -m comment --comment "Reject none loopback on 'lo'" -j DROP
# Accept all local packets
$IPTABLES -A INPUT -i lo -m comment --comment "Accept localhost packets" -j ACCEPT
$IPTABLES -A OUTPUT -o lo -m comment --comment "Accept localhost packets" -j ACCEPT
############
### IPv6 ###
############
# Allow localhost traffic. These rules are for all protocols.
$IP6TABLES -A INPUT -s ::1 -d ::1 -j ACCEPT
$IP6TABLES -A INPUT ! -i lo -s ::1 -m comment --comment "Reject none loopback on 'lo'" -j DROP
$IP6TABLES -A OUTPUT ! -o lo -d ::1 -m comment --comment "Reject none loopback on 'lo'" -j DROP
# Allow Link-Local addresses
$IP6TABLES -A INPUT -s fe80::/10 -j ACCEPT
$IP6TABLES -A OUTPUT -s fe80::/10 -j ACCEPT
# Normally, link-local packets should NOT be forwarded and don't need an entry in the FORWARD rule.
# However, when bridging in Linux (e.g. in Xen or OpenWRT), the FORWARD rule is needed:
$IP6TABLES -A FORWARD -s fe80::/10 -j ACCEPT
#################
### Multicast ###
#################
$IPTABLES -A INPUT -m comment --comment "Multicast auto-configuration" -d 224.0.0.0/24 -j ACCEPT
$IPTABLES -A OUTPUT -m comment --comment "Multicast request" -d 224.0.0.0/24 -j ACCEPT
$IP6TABLES -A INPUT -d ff00::/8 -j ACCEPT
$IP6TABLES -A INPUT -s ff00::/8 -j ACCEPT
$IP6TABLES -A OUTPUT -d ff00::/8 -j ACCEPT
$IP6TABLES -A OUTPUT -s ff00::/8 -j ACCEPT
Block IPv4 in IPv6 tunnels
If your ISP delivers you a native IPv6 connection then you don't need to use IPv4 tunneling! Just use either IPv4 or IPv6 native mode.
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
## IPv6 security
# No IPv4 -> IPv6 tunneling
$IP6TABLES -A INPUT -s 2002::/16 -m comment --comment "Reject 6to4 tunnels" -j DROP
$IP6TABLES -A FORWARD -s 2002::/16 -m comment --comment "Reject 6to4 tunnels" -j DROP
$IP6TABLES -A INPUT -s 2001:0::/32 -m comment --comment "Reject Teredo tunnels" -j DROP
$IP6TABLES -A FORWARD -s 2001:0::/32 -m comment --comment "Reject Teredo tunnels" -j DROP
# Block IPv6 protocol in IPv4 frames
$IPTABLES -A INPUT -p 41 -m comment --comment "Block IPv6 protocol in IPv4 frames" -j DROP
$IPTABLES -A OUTPUT -p 41 -m comment --comment "Block IPv6 protocol in IPv4 frames" -j DROP
$IPTABLES -A FORWARD -p 41 -m comment --comment "Block IPv6 protocol in IPv4 frames" -j DROP
Block IPv6 routing headers
# Filter all packets that have RH0 headers:
$IP6TABLES -A INPUT -m rt --rt-type 0 -j DROP
$IP6TABLES -A FORWARD -m rt --rt-type 0 -j DROP
$IP6TABLES -A OUTPUT -m rt --rt-type 0 -j DROP
Protocol(s) enforcement
You can even push the standard protection a bit higher by checking some protocols flags.
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
echo -e " "
echo -e "------------------------"
echo -e " Protocols enforcement"
echo -e "------------------------"
####### IPv4 #######
echo " ... Layer 2: ICMP v4"
# ICMP packets should not be fragmented
$IPTABLES -A INPUT --fragment -p icmp -m comment --comment "no ICMP fragments" -j DROP
# SMURF attack protection
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type address-mask-request -m comment --comment "address-mask-request" -j DROP
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type timestamp-request -m comment --comment "timestamp-request" -j DROP
# Limit ICMP Flood
$IPTABLES -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -m comment --comment "ICMP flood protection" -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type 0 -m comment --comment "echo reply" -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type 3 -m comment --comment "destination unreachable" -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type 8 -m comment --comment "echo request" -j ACCEPT
####### IPv6 #######
echo " ... Layer 2: ICMP v6 "
# Don't DROP ICMP6 a lot of things are happening over there! It might completly block the connection if you DROP icmp6
$IP6TABLES -A INPUT -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 -j ACCEPT
$IP6TABLES -A FORWARD -p icmpv6 -j ACCEPT
####### TCP IPv4 #######
echo " ... Layer 4: TCP # check packets conformity"
# INCOMING packets check
# All new incoming TCP should be SYN first
$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -m comment --comment "new TCP connection check" -j DROP
# Avoid SYN Flood (max 3 SYN packets / second. Then Drop all requests !!)
$IPTABLES -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -m comment --comment "avoid TCP SYN flood" -j ACCEPT
# Avoid fragment packets
$IPTABLES -A INPUT -f -m comment --comment "no fragments" -j DROP
# Check TCP flags -- flag 64, 128 = bogues
$IPTABLES -A INPUT -p tcp --tcp-option 64 -m comment --comment "ECE flag" -j DROP
$IPTABLES -A INPUT -p tcp --tcp-option 128 -m comment --comment "CWR flag" -j DROP
echo " ... Layer 4: TCP # Avoid NMAP Scans"
# XMAS-NULL
$IPTABLES -A INPUT -p tcp --tcp-flags ALL NONE -m comment --comment "attack XMAS-NULL" -j DROP
# XMAS-TREE
$IPTABLES -A INPUT -p tcp --tcp-flags ALL ALL -m comment --comment "attack XMAS-tree" -j DROP
# Stealth XMAS Scan
$IPTABLES -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -m comment --comment "attack XMAS stealth" -j DROP
# SYN/RST Scan
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -m comment --comment "scan SYN/RST" -j DROP
# SYN/FIN Scan
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -m comment --comment "scan SYN/FIN" -j DROP
# SYN/ACK Scan
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,ACK SYN,ACK -m comment --comment "scan SYN/ACK" -j DROP
# FIN/RST Scan
$IPTABLES -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -m comment --comment "scan FIN/RST" -j DROP
# FIN/ACK Scan
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags FIN,ACK FIN -m comment --comment "scan FIN/ACK" -j DROP
# ACK/URG Scan
$IPTABLES -A INPUT -p tcp --tcp-flags ACK,URG URG -m comment --comment "scan ACK/URG" -j DROP
# FIN/URG/PSH Scan
$IPTABLES -A INPUT -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -m comment --comment "scan FIN/URG/PSH" -j DROP
# XMAS-PSH Scan
$IPTABLES -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -m comment --comment "scan XMAS/PSH" -j DROP
# End TCP connection
$IPTABLES -A INPUT -p tcp --tcp-flags ALL FIN -m comment --comment "end TCP connection flag" -j DROP
# Ports scans
$IPTABLES -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "common scan FIN/SYN/RST/ACK SYN" -j DROP
$IPTABLES -A INPUT -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -m comment --comment "common scan FIN/SYN/RST/ACK/PSH/URG NONE" -j DROP
Allow services and network protocols
DHCP
DHCP client:
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
# DHCP client >> Broadcast IP request
$IPTABLES -A INPUT -p udp --sport 67:68 --dport 67:68 -m comment --comment "DHCP" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --sport 67:68 --dport 67:68 -m comment --comment "DHCP" -j ACCEPT
$IP6TABLES -A INPUT -p udp --sport 67:68 --dport 67:68 -m comment --comment "DHCP" -j ACCEPT
$IP6TABLES -A OUTPUT -p udp --sport 67:68 --dport 67:68 -m comment --comment "DHCP" -j ACCEPT
DNS
This will allow your computer to perform DNS requests:
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
# DNS
$IPTABLES -A INPUT -p udp --sport 53 -m comment --comment "DNS UDP sPort" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --sport 53 -m comment --comment "DNS UDP sPort" -j ACCEPT
$IPTABLES -A INPUT -p udp --dport 53 -m comment --comment "DNS UDP dPort" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 53 -m comment --comment "DNS UDP dPort" -j ACCEPT
$IP6TABLES -A INPUT -p udp --sport 53 -m comment --comment "DNS UDP sPort" -j ACCEPT
$IP6TABLES -A OUTPUT -p udp --sport 53 -m comment --comment "DNS UDP sPort" -j ACCEPT
$IP6TABLES -A INPUT -p udp --dport 53 -m comment --comment "DNS UDP dPort" -j ACCEPT
$IP6TABLES -A OUTPUT -p udp --dport 53 -m comment --comment "DNS UDP dPort" -j ACCEPT
# DNS SEC
# Established, related input are already accepted earlier
$IPTABLES -A OUTPUT -p tcp --sport 53 -m comment --comment "DNS Sec TCP sPort" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Sec TCP dPort" -j ACCEPT
$IP6TABLES -A OUTPUT -p tcp --sport 53 -m comment --comment "DNS Sec TCP sPort" -j ACCEPT
$IP6TABLES -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Sec TCP dPort" -j ACCEPT
!! IMPORTANT !!!
If you ever loose Internet access after that you need to check your /etc/resolv.conf
configuration and make sure you're using a valid DNS server.
LAN communication
To allow communication in the local network, without any restrictions:
IPTABLES=`which iptables`
IP_LAN_V4="172.16.50.0/24"
IP_LAN_V6="2001:DB8:1::1"
# Allow LAN communication
if [ ! -z "$IP_LAN_V4" ]
then
echo -e " ... Allow LAN communication - IP v4"
$IPTABLES -A INPUT -s $IP_LAN_V4 -d $IP_LAN_V4 -j ACCEPT
$IPTABLES -A OUTPUT -s $IP_LAN_V4 -d $IP_LAN_V4 -j ACCEPT
# Allow forwarding within the LAN
$IPTABLES -A FORWARD -s $IP_LAN_V4 -j ACCEPT
fi
if [ ! -z "$IP_LAN_V6" ]
then
echo -e " ... Allow LAN communication - IP v6"
$IP6TABLES -A INPUT -s $IP_LAN_V6 -d $IP_LAN_V6 -j ACCEPT
$IP6TABLES -A OUTPUT -s $IP_LAN_V6 -d $IP_LAN_V6 -j ACCEPT
# Allow forwarding within the LAN
$IP6TABLES -A FORWARD -s $IP_LAN_V6 -j ACCEPT
fi
Note: thanks to the ! -z operator if the variable is not set or "" then the rule will be skipped.
NTP (time syncronization) client
IPTABLES=`which iptables`
# NTP client
echo -e " ... Allow NTP time sync"
$IPTABLES -A INPUT -p udp --sport 123 -m state --state ESTABLISHED -m comment --comment "NTP (UDP)" -j ACCEPT
$IPTABLES -A INPUT -p tcp --sport 123 -m state --state ESTABLISHED -m comment --comment "NTP (TCP)" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 123 -m state --state NEW,ESTABLISHED -m comment --comment "NTP (UDP)" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 123 -m state --state NEW,ESTABLISHED -m comment --comment "NTP (TCP)" -j ACCEPT
IPTABLES=`which iptables`
# SAMBA share
# Access filtering is done in /etc/samba/smb.conf
$IPTABLES -A INPUT -p tcp --dport 135 -m comment --comment "DCE endpoint resolution" -j ACCEPT
$IPTABLES -A INPUT -p udp --dport 137 -m comment --comment "NetBIOS Name Service" -j ACCEPT
$IPTABLES -A INPUT -p udp --dport 138 -m comment --comment "NetBIOS Datagram" -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 139 -m comment --comment "NetBIOS Session" -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 445 -m comment --comment "SMB over TCP" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --sport 135 -m state --state ESTABLISHED -m comment --comment "DCE endpoint resolution" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 137 -m comment --comment "NetBios Name Service" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 138 -m comment --comment "NetBios Data Exchange" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 139 -m comment --comment "NetBios Session + Samba" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 445 -m comment --comment "CIFS - Partage Win2K and more" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 548 -m comment --comment "Apple file sharing" -j ACCEPT
FTP client
IPTABLES=`which iptables`
# FTP
# FTP INPUT (Client <--from-- Server)
$IPTABLES -A INPUT -p tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -m comment --comment "FTP command: allow FTP connections" -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 20 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -m comment --comment "FTP data (active)" -j ACCEPT
$IPTABLES -A INPUT -p tcp --sport 1024:65535 --dport 1024:65535 -m conntrack --ctstate NEW,ESTABLISHED -m comment --comment "FTP data (passive)" -j ACCEPT
$IPTABLES -A INPUT -p tcp -m state --state ESTABLISHED -m comment --comment "FTP established connections" -j ACCEPT
# FTP OUTPUT (Client --to--> Server)
$IPTABLES -A OUTPUT -p tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -m comment --comment "FTP command: allow FTP connections" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 20 -m conntrack --ctstate NEW,ESTABLISHED -m comment --comment "FTP data (active)" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --sport 1024:65535 --dport 1024:65535 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -m comment --comment "FTP data (passive)" -j ACCEPT