I have been working on creating a customised firewall for my linux box. I would like a few opinions on how secure it is and if there are any obvious weaknesses. The system it protects runs Gentoo and connects to a LAN through a router with NAT. It acts as a general desktop but also holds a local rsync mirror. Ssh access is currently disabled but rules are defined should it be needed.
The script is still being developed so a few comments for my own reference are hidden within.
The script is still being developed so a few comments for my own reference are hidden within.
Code:
#!/bin/bash
# Firewall Script - 0.6 - Development Version
# Note: Script assumes a single interface "$INT0" with a fixed ipaddress "$LANIP"
###############################################################
# Enviroment Variables
###############################################################
IPT="/sbin/iptables" # Shortcut
LOOPBACK="lo"
INT0="eth0" # Modify As Required
LANIP="192.168.0.7" # Modify As Required
###############################################################
# Set Policies for Chains
#-------------------------
# Set all to DROP as default as this is the most secure.
# Rules can then be used to allow the traffic that is desired.
###############################################################
###SETUP
#Flush old rules
$IPT -F
#Delete User Created Chains
$IPT -X
#Create New Chains
$IPT -N ICMP_IN
$IPT -N ICMP_OUT
$IPT -N BAD_FLAGS
#Set Policies
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP
###############################################################
# Module Loading
###############################################################
# Note: Hardcode these into "/etc/modules.autoload.d/kernel-2.6" if script not executed at startup
# Load additional modules
modprobe x_tables
modprobe ip_tables
modprobe iptable_filter
modprobe ipt_REJECT
modprobe xt_tcpudp
modprobe nf_conntrack
modprobe nf_conntrack_ipv4
modprobe nf_conntrack_ftp
modprobe nf_conntrack_irc
modprobe xt_state
modprobe ipt_LOG
modprobe nfnetlink
modprobe xt_limit
###############################################################
# Kernel Parameters
###############################################################
# Note: Hardcode these into "/etc/sysctl.conf" if script not executed at startup
# Enable broadcast echo protection
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Disable packet forwarding
echo 0 > /proc/sys/net/ipv4/ip_forward
# Disable source routed packets
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
# Enable TCP SYN Cookie Protection
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Disable ICMP Redirect Acceptance
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
# Don't send redirect messages
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
# Drop Spoofed Packets coming in on an interface, which, if replied to,
# would result in the reply going out a different interface.
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
# Log packets with impossible addresses.
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
###############################################################
# Rules
###############################################################
#
#---------------------------------------------------------------
# Enable loopback traffic - Means the machine can talk to itself (127.0.0.1)
echo "Loopback"
$IPT -A INPUT -i $LOOPBACK -j ACCEPT
$IPT -A OUTPUT -o $LOOPBACK -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
### Spoofing/Hijacking/DoS Protection
echo "Spoof/Hijack/Dos Protection"
# Drop inbound traffic with a source address the same as this machine
$IPT -A INPUT -i $INT0 -s $LANIP -j DROP
# Drop outbound traffic with a source address NOT the same as this machine
$IPT -A OUTPUT -o $INT0 -s ! $LANIP -j DROP
# Drop internet traffic from RFC 1918 private address space ranges
$IPT -A INPUT -s 10.0.0.0/8 -j DROP
$IPT -A INPUT -s 172.16.0.0/12 -j DROP
# Cannot drop 192.168.0.0/16 range as used for local LAN. Can only be dropped on an internet-facing connecting directly to the internet.
#$IPT -A INPUT -s 192.168.0.0/16 -j DROP
# Drop Traffic on Zeroconf address range
$IPT -A INPUT -s 168.254.0.0/16 -j DROP
# Drop TEST-NET address range
$IPT -A INPUT -s 192.0.2.0/24 -j DROP
# Drop reserved/unallocated address ranges
$IPT -A INPUT -s 224.0.0.0/4 -j DROP
$IPT -A INPUT -s 240.0.0.0/5 -j DROP
$IPT -A INPUT -s 248.0.0.0/5 -j DROP
# Drop loopback and zero addresses - Enable for internet-facing interfaces only.
#$IPT -A INPUT -s 127.0.0.0/8 -j DROP
#$IPT -A INPUT -s 255.255.255.255/32 -j DROP
#$IPT -A INPUT -s 0.0.0.0/8 -j DROP
#---------------------------------------------------------------------------------------------------------------------------------------------
# Send inbound traffic through the BAD_FLAGS Chain before being processed furthur
$IPT -A INPUT -p tcp -j BAD_FLAGS
#---------------------------------------------------------------------------------------------------------------------------------------------
# Prevent SYN Flooding - Might need tuning to traffic load
$IPT -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT
# LOG/DROP Traffic in INVALID State
$IPT -A INPUT -m state --state INVALID -j LOG --log-prefix "IPT: INV_STATE: "
$IPT -A INPUT -m state --state INVALID -j DROP
# LOG/DROP Fragmented Traffic
$IPT -A INPUT -f -j LOG --log-prefix "IPT: Frag: "
$IPT -A INPUT -f -j DROP
#---------------------------------------------------------------------------------------------------------------------------------------------
# Redirect ICMP Traffic to User Created Chains
echo "ICMP Processing Redirect"
$IPT -A INPUT -p icmp -j ICMP_IN
$IPT -A OUTPUT -p icmp -j ICMP_OUT
#---------------------------------------------------------------------------------------------------------------------------------------------
# DNS Rules - Allow this machine to contact the DNS server
echo "DNS"
$IPT -A INPUT -p udp --sport domain -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p udp --dport domain -m state --state NEW,ESTABLISHED -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Web Browsing - Allow for browsing to take place from this machine.
# - Do not allow new inbound HTTP requests
echo "Web Browsing"
#HTTP
$IPT -A INPUT -p tcp --sport 80 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
#HTTPS
$IPT -A INPUT -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# FTP - Allow outgoing FTP connections for update purposes
# Note: Uses nf_conntrack_ftp module
echo "FTP - Outgoing Connections"
$IPT -A INPUT -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
echo "------> Active FTP"
$IPT -A INPUT -p tcp --sport 20 --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 20 --sport 1024: -m state --state ESTABLISHED -j ACCEPT
echo "------> Passive FTP"
$IPT -A INPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# SSH Rule Set A - Allows for new connections to be made to the machine from the local lan.
# - Outbound SSH connections cannot be made from the machine.
#echo "SSH Rule Set A"
#$IPT -A INPUT -p tcp -s 192.168.0.0/24 --dport ssh -m state --state NEW,ESTABLISHED -j ACCEPT
#$IPT -A OUTPUT -p tcp -d 192.168.0.0/24 --sport ssh -m state --state ESTABLISHED -j ACCEPT
# SSH Rule Set B - Allows for new connections to be made from this machine.
# - Does not allow for inbound SSH connections
#echo "SSH Rule Set B"
#$IPT -A INPUT -p tcp --sport ssh -m state --state ESTABLISHED -j ACCEPT
#$IPT -A OUTPUT -p tcp --dport ssh -m state --state NEW,ESTABLISHED -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Following Rules still being researched and tested
#---------------------------------------------------------------------------------------------------------------------------------------------
# Bittorrent - Uptp 5 connections
# Tidy this up a bit
#echo "Bittorrent"
#Does it need to accept new connections or are they established first?
#$IPT -A INPUT -p tcp -m state --state NEW --dport 6881:6886 -j ACCEPT
#$IPT -A INPUT -p udp --dport 6881:6886 -m state --state NEW -j ACCEPT
# Need to add outbound connection restriction
#$IPT -A OUTPUT -p tcp --dport 6881:6886 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Azureues - WEBUI for home server
echo "Azureus Web UI"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 62836 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 62836 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# NTP - Network Time Protocol - To allow system clock sync with time servers
# Might be able to secure this more by limiting connection to a handful of time servers
echo "NTP"
$IPT -A INPUT -p udp -m state --state ESTABLISHED --sport ntp -j ACCEPT
$IPT -A OUTPUT -p udp -m state --state NEW,ESTABLISHED --dport ntp -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# RSYNC
echo "RSYNC"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport rsync -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport rsync -j ACCEPT
# Local RSYNC Mirror (This machine being the mirror)
echo "RSYNC Mirror" # Configure source variable to only allow access from known clients
$IPT -A INPUT -p tcp -m state --state NEW,ESTABLISHED -s 192.168.0.10 --dport rsync -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state ESTABLISHED --sport rsync -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Live-F1 Script
echo "Live-F1"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 4321 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 4321 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Synergy
echo "Synergy"
# Need to harden to only allow packets to/from synergy server on 192.168.0.2
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 24800 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 24800 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# No-IP (Dynamic DNS)
echo "No-IP"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 8245 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 8245 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# Netselect - Enable if required
#echo "Netselect"
#$IPT -A INPUT -p ICMP -m state --state RELATED -j ACCEPT
#$IPT -A OUTPUT -p udp -m state --state NEW,ESTABLISHED --dport 33000:34000 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# PIDGIN/IM
echo "PIDGIN/IM"
echo "- - - - - > Jabber/XMPP (Google Talk)"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 5222 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 5222 -j ACCEPT
echo "- - - - - > MSN Messenger Protocol"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 1863 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 1863 -j ACCEPT
# Need to allow for instant messaging protocols
#Other Protocol Ports
#5050 -- Yahoo
#5190 -- AIM/ICQ
#---------------------------------------------------------------------------------------------------------------------------------------------
# IRC
# Note: Look into using nf_conntrack_irc module
echo "IRC"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 6660:7003 -j ACCEPT #Are these port ranges correct?
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 6660:7003 -j ACCEPT
#$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 9999 -j ACCEPT
#$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 9999 -j ACCEPT
# DROP IDENT
$IPT -A INPUT -p tcp --dport 113 -j DROP #IDENT Port - Drop requests here to prevent them clogging up the log file
$IPT -A OUTPUT -p tcp --sport 113 -j DROP #IDENT Port - Drop requests here to prevent them clogging up the log file
#Will need rules for DCC Chat (Ports 2056:2066)
#---------------------------------------------------------------------------------------------------------------------------------------------
# DHCP Traffic - Reference [url]http://www.linklogger.com/UDP67_68.htm[/url]
echo "DHCP Traffic"
# UDP Ports 67/68 are used to allocate an IPAddress.
# Typically a machine will broadcast a request to the DHCP server UDP 0.0.0.0:68 > 255.255.255.255:67
# These ip addresses are used as the machine does not know the IP Address of the server and hasnt got an ipaddress allocated to itself
# It is typical for the server to respond with something like 192.168.1.1:67 > 255.255.255.255:68. The response will contain
# the ipaddress that the server is offering for the machine to use.
# Might want to tighten these rules by resticting to 0.0.0.0 and 255.255.255.255 but this wouldnt allow for renewal requests.
$IPT -A INPUT -p udp --dport 68 --sport 67 -m state --state ESTABLISHED -j ACCEPT #Accept requested info from DHCP server
$IPT -A INPUT -p udp --dport 67 --sport 68 -j DROP # Drop traffic from other machines meant for the DHCP server (prevents it being logged)
$IPT -A OUTPUT -p udp --sport 68 --dport 67 -m state --state NEW,ESTABLISHED -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
#SMB/CIFS
# Need to work more on the samba side to setup the shares before enabling
$IPT -A INPUT -p tcp -m state --state NEW,ESTABLISHED --dport 137:139 -j ACCEPT
$IPT -A INPUT -p udp -m state --state NEW,ESTABLISHED --dport 137:139 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --sport 137:139 -j ACCEPT
$IPT -A OUTPUT -p udp -m state --state NEW,ESTABLISHED --sport 137:139 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
# CUPS Support
echo "CUPS Support"
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --dport 631 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --sport 631 -j ACCEPT
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --dport 515 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --sport 515 -j ACCEPT
$IPT -A INPUT -p tcp -m state --state ESTABLISHED --sport 445 -j ACCEPT
$IPT -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 445 -j ACCEPT
#---------------------------------------------------------------------------------------------------------------------------------------------
##########
## ICMP ##
##########
#
# ICMP Message Types
# ==================
#
# Type Description
# ---- -----------
# 0 Echo Reply
# 3 Destination Unreachable
# 4 Source Quench
# 5 Redirect
# 8 Echo Request
# 11 Time Exceeded
# 12 Parameter Problem
# 13 Timestamp
# 14 Timestamp Reply
# 15 Information Request
# 16 Information Reply
#
# ==================
# ICMP Inbound Rules
$IPT -A ICMP_IN -p icmp --icmp-type 8 -j DROP
$IPT -A ICMP_IN -p icmp --icmp-type 0 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A ICMP_IN -p icmp --icmp-type 3 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A ICMP_IN -p icmp --icmp-type 11 -m state --state ESTABLISHED,RELATED -j ACCEPT
# Log and Drop inbound ICMP Traffic
$IPT -A ICMP_IN -p icmp -j LOG --log-prefix "IPT: ICMP_IN: "
$IPT -A ICMP_IN -p icmp -j DROP
# ICMP Outbound Rules
$IPT -A ICMP_OUT -p icmp --icmp-type 8 -m state --state NEW -j ACCEPT
# Log and Drop outbound ICMP Traffic
$IPT -A ICMP_OUT -p icmp -j LOG --log-prefix "IPT: ICMP_OUT: "
$IPT -A ICMP_OUT -p icmp -j DROP
#---------------------------------------------------------------------------------------------------------------------------------------------
#####################
## BAD FLAGS CHAIN ##
#####################
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "IPT: Bad SF Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "IPT: Bad SR Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,PSH SYN,FIN,PSH -j LOG --log-prefix "IPT: Bad SFP Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,PSH SYN,FIN,PSH -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,RST SYN,FIN,RST -j LOG --log-prefix "IPT: Bad SFR Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,RST SYN,FIN,RST -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,RST,PSH SYN,FIN,RST,PSH -j LOG --log-prefix "IPT: Bad SFRP Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags SYN,FIN,RST,PSH SYN,FIN,RST,PSH -j DROP
# Disable as dropping valid traffic
#$IPT -A BAD_FLAGS -p tcp --tcp-flags FIN FIN -j LOG --log-prefix "IPT: Bad F Flag: "
#$IPT -A BAD_FLAGS -p tcp --tcp-flags FIN FIN -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags FIN,RST FIN,RST -j LOG --log-prefix "IPT: Bad FR Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,FIN FIN -j LOG --log-prefix "IPT: Bad F Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,FIN FIN -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,PSH PSH -j LOG --log-prefix "IPT: Bad P Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,PSH PSH -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,URG URG -j LOG --log-prefix "IPT: Bad U Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ACK,URG URG -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j LOG --log-prefix "IPT: Bad SFPU Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "IPT: Null Flag: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL NONE -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL ALL -j LOG --log-prefix "IPT: All Flags: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL ALL -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL FIN,URG,PSH -j LOG --log-prefix "IPT: Nmap:Xmas Flags: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOG --log-prefix "IPT: Merry Xmas Flags: "
$IPT -A BAD_FLAGS -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
#---------------------------------------------------------------------------------------------------------------------------------------------
#############
## LOGGING ##
#############
# LOG & DROP traffic thats not dealt with by the other rules (DROP by default after logging due to policy) - Working
# Note: Investigate port 137/138 traffic. Its creating a lot of log data.
# Note: Wireless traffic is generating a lot of log entries, see what can be done about this.
# Temporarily disable logging whilst above issue is being resolved.
echo "Enable LOG of DROP packets"
#Logging disabled as log locations need creating & rotations setup
$IPT -A INPUT -m limit --limit 1/sec -j LOG --log-prefix "IPT INPUT: DROP "
$IPT -A FORWARD -m limit --limit 1/sec -j LOG --log-prefix "IPT FORWARD: DROP "
$IPT -A OUTPUT -m limit --limit 1/sec -j LOG --log-prefix "IPT OUTPUT: DROP "
#---------------------------------------------------------------------------------------------------------------------------------------------
echo "End of script"
exit 0