Firewall setup
From Smith family
| 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.rulesfile and the/etc/iptablesfile. Adjust/etc/iptables.rulesto 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
