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
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
echo " ... IPv4"
$MODPROBE ip_tables
$MODPROBE iptable_filter
$MODPROBE iptable_mangle
# Allow to use state match
$MODPROBE ip_conntrack
# IPv6
echo " ... IPv6"
$MODPROBE ip6_tables
$MODPROBE ip6table_filter
$MODPROBE ip6table_mangle
# Allow NAT
echo " ... NAT"
$MODPROBE iptable_nat
# Allow active / passive FTP
echo " ... FTP"
$MODPROBE ip_conntrack_ftp
$MODPROBE ip_nat_ftp
# Allow log limits
echo " ... burst limit"
$MODPROBE ipt_limit
Network features
Now that you've enable some modules, you need to choose which Network's 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
# Port forwarding in general
echo " ... Enable forwarding"
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.
Linux script
This is how you defined a default policy.
Note:
- You have to adjust the policy to your own settings
- You should NOT set the INPUT in ACCEPT mode. That's risky!
IPTABLES=`which iptables`
IP6TABLES=`which ip6tables`
echo -e " "
echo -e "------------------------"
echo -e " Flush existing rules "
echo -e "------------------------"
$IP6TABLES -F
$IP6TABLES -X
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t filter -F
$IPTABLES -t filter -X
# delete NAT rules
$IPTABLES -t nat -F
$IPTABLES -t nat -X
# delete MANGLE rules (packets modifications)
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
$IP6TABLES -t mangle -F
$IP6TABLES -t mangle -X
echo -e " "
echo -e "------------------------"
echo -e " Default policy"
echo -e "------------------------"
echo -e " || --> OUTGOING reject all "
echo -e " --> || INCOMING reject all "
echo -e " --> || --> FORWARDING reject all (each redirection manual needs configuration)"
# INCOMING = avoid intrusions
# OUTGOING = avoid disclosure of sensitive / private data
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT DROP
$IP6TABLES -P INPUT DROP
$IP6TABLES -P FORWARD DROP
$IP6TABLES -P OUTPUT DROP
echo -e " ... Reject invalid packets"
# Reject invalid packets
$IPTABLES -A INPUT -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IPTABLES -A INPUT -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
$IPTABLES -A INPUT -p icmp -m state --state INVALID -m comment --comment "Reject invalid ICMP" -j DROP
$IPTABLES -A OUTPUT -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IPTABLES -A OUTPUT -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
$IPTABLES -A OUTPUT -p icmp -m state --state INVALID -m comment --comment "Reject invalid ICMP" -j DROP
$IPTABLES -A FORWARD -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IPTABLES -A FORWARD -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
$IP6TABLES -A INPUT -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IP6TABLES -A INPUT -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
$IP6TABLES -A INPUT -p icmpv6 -m state --state INVALID -m comment --comment "Reject invalid ICMP6" -j DROP
$IP6TABLES -A OUTPUT -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IP6TABLES -A OUTPUT -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
$IP6TABLES -A OUTPUT -p icmpv6 -m state --state INVALID -m comment --comment "Reject invalid ICMP6" -j DROP
$IP6TABLES -A FORWARD -p tcp -m state --state INVALID -m comment --comment "Reject invalid TCP" -j DROP
$IP6TABLES -A FORWARD -p udp -m state --state INVALID -m comment --comment "Reject invalid UDP" -j DROP
echo " ... Avoid spoofing and local subnets"
# Reserved addresses. We shouldn't received any packets from them!
### TODO #### Adjust these values
$IPTABLES -A INPUT -s 10.0.0.0/8 -j DROP
#$IPTABLES -A INPUT -s 172.16.0.0/12 -j DROP
#$IPTABLES -A INPUT -s 192.168.0.0/16 -j DROP
$IPTABLES -A INPUT -s 169.254.0.0/16 -j DROP
## 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
$IPTABLES -A FORWARD -s 127.0.0.0/24 -m comment --comment "Reject none loopback on 'lo'" -j DROP
$IP6TABLES -A INPUT ! -i lo -s ::1/128 -m comment --comment "Reject none loopback on 'lo'" -j DROP
$IP6TABLES -A OUTPUT ! -o lo -d ::1/128 -m comment --comment "Reject none loopback on 'lo'" -j DROP
$IP6TABLES -A FORWARD -s ::1/128 -m comment --comment "Reject none loopback on 'lo'" -j DROP
## 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
## Stateful connections
echo -e " ... Keep ESTABLISHED connections "
$IPTABLES -A INPUT -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A FORWARD -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A OUTPUT -m state --state ESTABLISHED -j ACCEPT
$IP6TABLES -A INPUT -m state --state ESTABLISHED -j ACCEPT
$IP6TABLES -A FORWARD -m state --state ESTABLISHED -j ACCEPT
$IP6TABLES -A OUTPUT -m state --state ESTABLISHED -j ACCEPT
echo -e " ... Keep RELATED connections (required for FTP by example)"
$IPTABLES -A INPUT -m state --state RELATED -j ACCEPT
$IPTABLES -A FORWARD -m state --state RELATED -j ACCEPT
$IPTABLES -A OUTPUT -m state --state RELATED -j ACCEPT
$IP6TABLES -A INPUT -m state --state RELATED -j ACCEPT
$IP6TABLES -A FORWARD -m state --state RELATED -j ACCEPT
$IP6TABLES -A OUTPUT -m state --state RELATED -j ACCEPT
Protocol(s) enforcement
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