Firewall setup

From Smith family

Jump to: navigation, search
Server setup
← Previous Next →
Hostname and IP Protect SSH

The base of this script came from James Stevens's example firewall rulesets. Adjustments to the /proc entries are described by Brian Hatch at SecurityFocus.

Contents

Remove ufw

The first thing to do is to disable the default ufw package:

root@server:~# ufw disable

With that done, you can move on to installing a more flexible firewall.

Add a bespoke iptables firewall

  • Add the /etc/iptables.rules file and the /etc/iptables file. Adjust /etc/iptables.rules to suit, depending on what services you want to offer with each machine.
  • Make both files executable
root@server:~# chown root:root /etc/iptables.rules
root@server:~# chmod +x /etc/iptables.rules
root@server:~# chown root:root /etc/iptables
root@server:~# chmod +x /etc/iptables
  • Install it in the startup sequence with
root@server:~# update-rc.d iptables start 13 2 3 4 5 . stop 13 S 0 1 6 .
(note the full stops)

Information on iptables from the iptables tutorial. Names of the services used are listed in /etc/services

Iptables.rules

This is the rule set for the server machine

#!/bin/bash
## Iptables ruleset

# Based on an original by James Stephens (jns@ias.edu)
# http://www.sns.ias.edu/~jns/

## ============================================================
#
# Load appropriate modules.
modprobe ip_tables
modprobe ip_conntrack
modprobe ip_conntrack_ftp 

# These lines are here in case rules are already in place and the script is ever rerun on the fly.
# We want to remove all rules and pre-exisiting user defined chains and zero the counters
# before we implement new rules.
iptables -F
iptables -X
iptables -Z 

# Set up a default policy for the built-in chains.
# If we modify and re-run the script mid-session then (because we have a default DROP
# policy), what happens is that there is a small time period when packets are denied until
# the new rules are back in place. There is no period, however small, when packets we
# don't want are allowed.
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

## ===========================================================
## Some definitions:

IFACE="eth0"
IPADDR="192.168.1.251"       # this machine's address
NAMESERVER_1="192.168.1.251" # desktop.domain.tld
NAMESERVER_2="1.2.3.4"       # ISP's primary nameserver
NAMESERVER_3="1.2.3.5"       # ISP's secondary nameserver
ROUTER="192.168.1.1"
LAN="192.168.1.0/24"
BROADCAST="192.168.1.255"
LOOPBACK="127.0.0.0/8"
CLASS_A="10.0.0.0/8"
CLASS_B="172.16.0.0/12"
CLASS_C="192.168.0.0/16"
CLASS_D_MULTICAST="224.0.0.0/4"
CLASS_E_RESERVED_NET="240.0.0.0/5"
P_PORTS="0:1023"
UP_PORTS="1024:65535"
TR_SRC_PORTS="32769:65535"
TR_DEST_PORTS="33434:33523"

## ============================================================
## Kernel flags
# To dynamically change kernel parameters and variables on the fly you need
# CONFIG_SYSCTL defined in your kernel. I would advise the following: 

# Disable response to ping.
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
# echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all

# Disable response to broadcasts.
# You don't want yourself becoming a Smurf amplifier.
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

# Don't accept source routed packets. Attackers can use source routing to generate
# traffic pretending to be from inside your network, but which is routed back along
# the path from which it came, namely outside, so attackers can compromise your
# network. Source routing is rarely used for legitimate purposes.
echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route

# Disable ICMP redirect acceptance. ICMP redirects can be used to alter your routing
# tables, possibly to a bad end.
echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects
echo "0" > /proc/sys/net/ipv4/conf/all/send_redirects

# Enable bad error message protection.
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

# Turn on reverse path filtering. This helps make sure that packets use
# legitimate source addresses, by automatically rejecting incoming packets
# if the routing table entry for their source address doesn't match the network
# interface they're arriving on. This has security advantages because it prevents
# so-called IP spoofing, however it can pose problems if you use asymmetric routing
# (packets from you to a host take a different path than packets from that host to you)
# or if you operate a non-routing host which has several IP addresses on different
# interfaces. (Note - If you turn on IP forwarding, you will also get this).
for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do
   echo "1" > ${interface}
done

# Log spoofed packets, source routed packets, redirect packets.
echo "1" > /proc/sys/net/ipv4/conf/all/log_martians

# Make sure that IP forwarding is turned off. We only want this for a multi-homed host.
echo "0" > /proc/sys/net/ipv4/ip_forward

echo "1" > /proc/sys/net/ipv4/tcp_syncookies  # protect against DoS attacks


## ============================================================
# RULES

## LOOPBACK
# Allow unlimited traffic on the loopback interface.
iptables -A INPUT  -i lo -j ACCEPT

# Standard actions for logging and dropping packets 

## LOGGING
# You don't have to split up your logging like I do below, but I prefer to do it this way
# because I can then grep for things in the logs more easily. One thing you probably want
# to do is rate-limit the logging. I didn't do that here because it is probably best not too
# when you first set things up ................. you actually really want to see everything going to
# the logs to work out what isn't working and why. You cam implement logging with
# "-m limit --limit 6/h --limit-burst 5" (or similar) before the -j LOG in each case.

# Create a new table to allow easy access
iptables -N log-and-drop

# Any fragment not already allowed is logged and then dropped.
iptables -A log-and-drop -i $IFACE -f -j LOG --log-ip-options --log-level debug --log-prefix "IPTABLES FRAGMENTS: "
iptables -A log-and-drop -i $IFACE -f -j DROP
# Any udp not already allowed is logged and then dropped.
iptables -A log-and-drop -i $IFACE -p udp -j LOG --log-ip-options --log-level debug --log-prefix "IPTABLES UDP-IN: "
iptables -A log-and-drop -i $IFACE -p udp -j DROP
# Any icmp not already allowed is logged and then dropped.
iptables -A log-and-drop -i $IFACE -p icmp -j LOG --log-ip-options --log-level debug --log-prefix "IPTABLES ICMP-IN: "
iptables -A log-and-drop -i $IFACE -p icmp -j DROP
# Any tcp not already allowed is logged and then dropped.
iptables -A log-and-drop -i $IFACE -p tcp -j LOG --log-ip-options --log-tcp-options --log-level debug --log-prefix "IPTABLES TCP-IN: "
iptables -A log-and-drop -i $IFACE -p tcp -j DROP
# Anything else not already allowed is logged and then dropped.
# It will be dropped by the default policy anyway ........ but let's be paranoid.
iptables -A log-and-drop -i $IFACE -j LOG --log-ip-options --log-level debug --log-prefix "IPTABLES PROTOCOL-X-IN: "
iptables -A log-and-drop -i $IFACE -j DROP

## SYN-FLOODING PROTECTION
# This rule maximises the rate of incoming connections. In order to do this we divert tcp
# packets with the SYN bit set off to a user-defined chain. Up to limit-burst connections
# can arrive in 1/limit seconds ..... in this case 10 connections in one second. After this, one
# of the burst is regained every second and connections are allowed again. The default limit
# is 3/hour. The default limit burst is 5.
# (was --limit-burst 4 )
iptables -N syn-flood
iptables -A INPUT -i $IFACE -p tcp --syn -j syn-flood
iptables -A syn-flood -m limit --limit 5/s --limit-burst 100 -j RETURN
iptables -A syn-flood -j log-and-drop

### Allow any packets related to connections we've started
iptables -A INPUT -i $IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

# FRAGMENTS
# I have to say that fragments scare me more than anything.
# Sending lots of non-first fragments was what allowed Jolt2  to effectively "drown"
# Firewall-1. Fragments can be overlapped, and the subsequent interpretation of such
# fragments is very OS-dependent (see this paper for details).
# I am not going to trust any fragments.
# Log fragments just to see if we get any, and deny them too.
iptables -A INPUT -i $IFACE -f -j log-and-drop

## Make sure NEW tcp connections are SYN packets
iptables -A INPUT -i $IFACE -p tcp ! --syn -m state --state NEW -j log-and-drop

## SPOOFING
# Most of this anti-spoofing stuff is theoretically not really necessary with the flags we
# have set in the kernel above ........... but you never know there isn't a bug somewhere in
# your IP stack.
#
# Special case: silently drop packets broadcast by our own instance of CUPS
iptables -A INPUT -i $IFACE -s $IPADDR -d $BROADCAST -p udp --dport ipp --sport ipp -j DROP
# Special case: silently drop DHCP request and renewal packets
iptables -A INPUT -i $IFACE -s "0.0.0.0" -d "255.255.255.255" -p udp --sport bootpc --dport bootps -j DROP
iptables -A INPUT -i $IFACE -s $ROUTER   -d "255.255.255.255" -p udp --sport bootps --dport bootpc -j DROP

# Refuse spoofed packets pretending to be from your IP address.
iptables -A INPUT -i $IFACE -s $IPADDR -j log-and-drop
# Refuse packets claiming to be from a Class A private network.
iptables -A INPUT -i $IFACE -s $CLASS_A -j log-and-drop
# Refuse packets claiming to be from a Class B private network.
iptables -A INPUT -i $IFACE -s $CLASS_B -j log-and-drop
# Refuse packets claiming to be from a Class C private network.
# Note that we want to allow some, because we're ON a Class C network (hence the sub-table).
# Packets from our LAN are passed back to the main INPUT table.
# Other packets from Class C networks get dropped.
iptables -N class-c-filter
iptables -A INPUT -i $IFACE -s $CLASS_C -j class-c-filter
iptables -A class-c-filter -i $IFACE -s $LAN -j RETURN
iptables -A class-c-filter -i $IFACE -j log-and-drop
# Refuse Class D multicast addresses. Multicast is illegal as a source address.
iptables -A INPUT -i $IFACE -s $CLASS_D_MULTICAST -j log-and-drop
# Refuse Class E reserved IP addresses.
iptables -A INPUT -i $IFACE -s $CLASS_E_RESERVED_NET -j log-and-drop
# Refuse packets claiming to be to the loopback interface.
# Refusing packets claiming to be to the loopback interface protects against
# source quench, whereby a machine can be told to slow itself down by an icmp source
# quench to the loopback.
iptables -A INPUT  -i $IFACE -d $LOOPBACK -j log-and-drop
# Refuse broadcast address packets, except for broadcasts across our LAN
# iptables -A INPUT -i $IFACE -d $BROADCAST -j log-and-drop
iptables -N broadcast-filter
iptables -A INPUT -i $IFACE -d $BROADCAST -j broadcast-filter
iptables -A broadcast-filter -i $IFACE -s $LAN -j RETURN
iptables -A broadcast-filter -i $IFACE -j log-and-drop


## ============================================================
## SERVICES
# Note that this is mainly for the services provided by this server: services
# used are generally allowed through the OUTPUT chain and the return packets
# are either ESTABLISHED or RELATED.

## DNS (port 53)
# Allow UDP and TCP packets in for DNS server.
iptables -A INPUT -i $IFACE -p udp -s $LAN --dport domain -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport domain -j ACCEPT
# Allow UDP packets in if they are a response from a nameserver.
iptables -A INPUT -i $IFACE -p udp -s $NAMESERVER_1 --sport domain -j ACCEPT
iptables -A INPUT -i $IFACE -p udp -s $NAMESERVER_2 --sport domain -j ACCEPT
iptables -A INPUT -i $IFACE -p udp -s $NAMESERVER_3 --sport domain -j ACCEPT
# Allow TCP packets in if they are a response from a nameserver.
iptables -A INPUT -i $IFACE -p tcp -s $NAMESERVER_1 --sport domain -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp -s $NAMESERVER_2 --sport domain -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp -s $NAMESERVER_3 --sport domain -j ACCEPT

## Allow SSH (port 22)
iptables -A INPUT -i $IFACE -p tcp --dport ssh -j ACCEPT

## Allow WWW (ports 80 and 443)
iptables -A INPUT -i $IFACE -p tcp --dport http  -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp --dport https -j ACCEPT

## Allow TELNET (port 23)
# iptables -A INPUT -i $IFACE -p tcp --dport telnet -j ACCEPT

## Allow FTP (port 21 for control, port 20 for data)
# Allow ftp outbound.
## iptables -A INPUT -i $IFACE -p tcp --dport ftp -j ACCEPT
# Now for the connection tracking part of ftp. This is discussed more completely in my section
# on connection tracking to be found here.
# 1) Active ftp.
# This involves a connection INbound from port 20 on the remote machine, to a local port
# passed over the ftp channel via a PORT command. The ip_conntrack_ftp module recognizes
# the connection as RELATED to the original outgoing connection to port 21 so we don't
# need NEW as a state match.
## iptables -A INPUT -i $IFACE -p tcp --dport ftp-data -j ACCEPT
# 2) Passive ftp.
# This involves a connection outbound from a port >1023 on the local machine, to a port >1023
# on the remote machine previously passed over the ftp channel via a PORT command. The
# ip_conntrack_ftp module recognizes the connection as RELATED to the original outgoing
# connection to port 21 so we don't need NEW as a state match.
# iptables -A INPUT -i $IFACE -p tcp --sport $UP_PORTS --dport $UP_PORTS -m state --state ESTABLISHED -j ACCEPT
# (not needed due to the default acceptance of ESTABLISHED packets above

## MAIL
# SMTP (port 25)
iptables -A INPUT  -i $IFACE -p tcp --dport smtp  -j ACCEPT
# IMAP (ports 143, 220, 993).  Only accept connections from machines on this LAN
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport imap  -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport imap3 -j ACCEPT
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport imaps -j ACCEPT
# POP3 (ports 110, 995)
# iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport pop3  -j ACCEPT
# iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport pop3s -j ACCEPT

## SAMBA (UDP ports 137, 138; TCP ports 139, 445)
# Only accept packets from the LAN
# iptables -A INPUT -i $IFACE -p udp -s $LAN --dport netbios-ns   -j ACCEPT
# iptables -A INPUT -i $IFACE -p udp -s $LAN --dport netbios-dgm  -j ACCEPT
# iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport netbios-ssn  -j ACCEPT
# iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport microsoft-ds -j ACCEPT

## CUPS printing (port 631)
# Only accept packets from the LAN
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport ipp -j ACCEPT
iptables -A INPUT -i $IFACE -p udp -s $LAN --dport ipp -j ACCEPT

## MySQL (port 3306)
# Only accept packets from the LAN
iptables -A INPUT -i $IFACE -p tcp -s $LAN --dport mysql -j ACCEPT
iptables -A INPUT -i $IFACE -p udp -s $LAN --dport mysql -j ACCEPT

## Git (port 9418)
iptables -A INPUT -i $IFACE -p tcp --dport git -j ACCEPT

## AUTH server (port 113)
# Reject ident probes with a tcp reset.
# I need to do this for a broken mailhost that won't accept my mail if I just drop its ident probe.
# iptables -A INPUT -i $IFACE -p tcp --dport auth -j REJECT --reject-with tcp-reset

# ICMP
# We accept icmp in if it is "related" to other connections (e.g a time exceeded (11)
# from a traceroute) or it is part of an "established" connection (e.g. an echo reply (0)
# from an echo-request (8)).
# iptables -A INPUT -i $IFACE -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
# (not needed due to the default acceptance of ESTABLISHED packets above

### Log and drop
# Log and drop all remaining input packets
iptables -A INPUT -j log-and-drop

# THE END

Iptables script

#!/bin/sh
# Start/stop iptables firewall
#
### BEGIN INIT INFO
# Provides:          firewall
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      S 0 1 6
# Short-Description: Firewall
# Description:       Sets up a firewall with iptables.
#                    Firewall rules are at /etc/iptables.rules
### END INIT INFO

test -f /sbin/iptables || exit 0

. /lib/lsb/init-functions

IPTABLES_CONFIG=/etc/iptables.rules

# check we have the right kernel version
KERNELMAJ=`uname -r | sed                   -e 's,\..*,,'`
KERNELMIN=`uname -r | sed -e 's,[^\.]*\.,,' -e 's,\..*,,'`
if [ "$KERNELMAJ" -lt 2 ] ; then
 exit 0
fi
if [ "$KERNELMAJ" -eq 2 -a "$KERNELMIN" -lt 3 ] ; then
 exit 0
fi 

if  /sbin/lsmod 2>/dev/null |grep -q ipchains ; then
 # Don't do both
 exit 0
fi

start() {
 # don't do squat if we don't have the script
 if [ -f $IPTABLES_CONFIG ]; then
     log_begin_msg "Applying iptables firewall rules:"
     $IPTABLES_CONFIG
     log_end_msg $?
 fi
}

stop() {
    log_begin_msg "Flushing all iptable chains"
    iptables -F
    log_end_msg $?

    log_begin_msg "Removing user defined iptable chains"
    iptables -X
    log_end_msg $?

    log_begin_msg "Resetting built-in chains to the default ACCEPT policy:"
    iptables -P INPUT ACCEPT && \
        iptables -P FORWARD ACCEPT && \
        iptables -P OUTPUT ACCEPT && \
    log_end_msg $?
}

panic() {
    log_begin_msg "Changing target policies to DROP: "
    iptables -P INPUT DROP && \
        iptables -P FORWARD DROP && \
        iptables -P OUTPUT DROP && \
    log_end_msg $?

    log_begin_msg "Flushing all iptable chains"
    iptables -F
    log_end_msg $?

    log_begin_msg "Removing user defined iptable chains"
    iptables -X
    log_end_msg $?
}

case "$1" in
  start)
 start
 ;;

  stop)
 stop
 ;;

  restart)
 # "restart" is really just "start" as this isn't a daemon,
 #  and "start" clears any pre-defined rules anyway.
 #  This is really only here to make those who expect it happy
 panic
 start
 ;;

  status)
 iptables --list
 ;;

  panic)
 panic
 ;;

  *)
 echo "Usage: $0 {start|stop|restart|status|panic}"
 exit 1
esac

exit 0
Personal tools