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 1 > /proc/sys/net/ipv6/conf/all/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 rely 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
############
### 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
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 "------------------------"
echo -e " ... Layer 2: ICMP"
# ICMP packets should not be fragmented
$IPTABLES -A INPUT --fragment -p icmp -m comment --comment "no ICMP fragments" -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 -m limit --limit 1/s --limit-burst 1 -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
# Avoid common attacks ... but blocks ping
#$IPTABLES -A OUTPUT -p icmp --icmp-type 3 -j DROP
# Feedback for problems
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 1 -m comment --comment "destination unreachable" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 2 -m comment --comment "packet too big" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 3 -m comment --comment "time exceeded" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 4 -m comment --comment "parameter problem" -j ACCEPT
# Router and neighbor discovery
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 133 -m comment --comment "router sollicitation" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 134 -m comment --comment "router advertisement" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 135 -m comment --comment "neighbor sollicitation" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 136 -m comment --comment "neighbor advertisement" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 133 -m comment --comment "router sollicitation" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 134 -m comment --comment "router advertisement" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 135 -m comment --comment "neighbor sollicitation" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 136 -m comment --comment "neighbor advertisement" -j ACCEPT
# Ping requests
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 128 -m comment --comment "echo request" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 128 -m comment --comment "echo request" -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type 129 -m comment --comment "echo reply" -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type 129 -m comment --comment "echo reply" -j ACCEPT
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 -j DROP
$IPTABLES -A INPUT -p tcp --tcp-option 128 -j DROP
echo " ... Layer 4: TCP # avoid common scans and TCP flags attacks"
# 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 ALL ACK -j DROP
$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`
# 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
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 state --state ESTABLISHED -m comment --comment "DNS UDP" -j ACCEPT
$IPTABLES -A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m comment --comment "DNS TCP" -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "DNS UDP" -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "DNS TCP" -j ACCEPT
$IP6TABLES -A INPUT -p udp --sport 53 -m state --state ESTABLISHED -m comment --comment "DNS UDP" -j ACCEPT
$IP6TABLES -A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -m comment --comment "DNS TCP" -j ACCEPT
$IP6TABLES -A OUTPUT -p udp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "DNS UDP" -j ACCEPT
$IP6TABLES -A OUTPUT -p tcp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "DNS TCP" -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 client - base rules
$IPTABLES -A INPUT -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
# Active FTP
$IPTABLES -A INPUT -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT
# Passive FTP
$IPTABLES -A INPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT