niels.horn |
03-28-2009 05:11 PM |
Request For Comments on Firewall script
Over the last week I set up a spare box to serve as a gateway / router / firewall / proxy (squid) / contentfilter (dansguardian).
Everything works fine, but I'm not sure if my firewall script is safe enough.
I read many things about spoofing, worms, syn-attacks and more, and have implemented nothing of the kind, just the basic things like closing all ports that don't need to stay open.
To clarify things, my setup is like this:
Code:
ADSL-line
|
ADSL-modem
|
gateway/firewall/proxy/content-filter
___|_________________
| | | | | |
PC1 PC2 PC3 PC4 PC5 PC6
Four PCs run Linux (Slackware), like the gataway, and two run Windows.
The script I wrote is like this:
Code:
#!/bin/bash
#
# rc.firewall Setup basic firewall
#
# Version: 0.2.1 (beta) - Saturday, Mar 28, 2009
#
# Author: Niels Horn (niels.horn@gmail.com)
###################
## Configuration ##
###################
### Simulate Only: put =Y to not really do anything, just simulate & test
# put =N to really configure your firewall
SIMULATE_ONLY=N
### Interface names in variables
# - IF_EXT is the one that connects to the internet
# - IF_INT connects to the LAN
IF_EXT=eth0
IF_INT=eth1
### Proxy configuration
# HTTP_PROXY: How to handle http-requests
# use =none to allow port 80 to pass normally
# use =block to block direct outgoing http requests
# (to force users to use proxy)
# use =redirect to redirect all requests to local port
# (=transparent proxy, set HTTP_PROXY_PORT)
HTTP_PROXY=block
#HTTP_PROXY_PORT=8080
### Allowed traffic from LAN to gateway
# use =ALL to allow all traffic, or
# use =<port>,<protocol>,<description> to limit ports where:
# <port> = tcp port to allow
# <protocol> = protocol (tcp | udp)
# <description> = service (only for information)
# ** Separate entries with a space **
# Examples:
# GTW_ALLOWED="ALL"
# GTW_ALLOWED="22,tcp,ssh 53,tcp,dns 8080,tcp,proxy"
#GTW_ALLOWED="ALL"
GTW_ALLOWED="\
8080,tcp,proxy \
8822,tcp,ssh"
### Allowed outgoing traffic
# use =ALL to allow all outgowing traffic, or
# use =<port>,<protocol>,<description> to limit ports where:
# <port> = tcp port to allow
# <protocol> = protocol (tcp | udp)
# <description> = service (only for information)
# ** Separate entries with a space **
# Examples:
# OUT_ALLOWED="ALL"
# OUT_ALLOWED="25,tcp,smtp 53,tcp,dns 80,tcp,http 110,tcp,pop3"
# NOTE: 443 (https) is used for Windows Live Id
#OUT_ALLOWED="ALL"
OUT_ALLOWED="\
21,tcp,ftp \
22,tcp,ssh \
25,tcp,smtp \
53,udp,dns \
110,tcp,pop3 \
123,udp,ntp \
143,tcp,imap \
443,tcp,https \
587,tcp,smtps-gmail \
873,tcp,rsync \
995,tcp,pop3s \
1024:65535,tcp,user-ports \
1024:65535,udp,user-ports"
### Allowed incoming traffic & define NAT
# use =<ext_port>,<protocol>,<ip>,<int_port>,<description> where:
# <ext_port> = tcp port to open on outside
# <protocol> = protocol (tcp | udp)
# <ip> = ip of server on LAN
# <int_port> = port on which server id listening
# <description> = informational only
# ** Separate entries with a space **
# Examples:
# IN_ALLOWED="" (allows nothing at all)
# IN_ALLOWED="22,tcp,192.168.1.100,22,SSH"
# IN_ALLOWED="8000,tcp,192.168.1.101,80,Webserver"
# IN_ALLOWED=
IN_ALLOWED="\
8822,tcp,192.168.2.101,22,SSH"
####################
## Pre-processing ##
####################
echo
echo "Setting up a basic router / firewall:"
echo "====================================="
echo
if [ "$SIMULATE_ONLY" != "N" ]; then
IPT="true "
echo "(** Simulating only... No real changes will be applied! **)"
echo
else
IPT="iptables"
fi
#################################
## Get additional network info ##
#################################
# Get IP-addresses
IP_EXT=`ifconfig $IF_EXT | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`
IP_INT=`ifconfig $IF_INT | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`
# Networks:
NET_EXT="0.0.0.0/0"
NET_INT=`route -n | grep -v '^0.0.0.0' | grep $IF_INT | awk '{print $1"/"$3}'`
# Print collected information:
echo "Connection IF IP Network"
echo "---------- ----- --------------- -------------------------------"
printf "%-10s %-5s %-15s %s\n" LAN $IF_INT $IP_INT $NET_INT
printf "%-10s %-5s %-15s %s\n" Internet $IF_EXT $IP_EXT $NET_EXT
echo
####################
## Clean up first ##
####################
# Flush existing chains
$IPT --flush
$IPT --table nat --flush
$IPT --table mangle --flush
# Delete any existing user chains
$IPT --delete-chain
$IPT --table nat --delete-chain
$IPT --table mangle --delete-chain
###################################################
## Set default policies to drop (we're paranoid) ##
###################################################
$IPT --policy INPUT DROP
$IPT --policy OUTPUT DROP
$IPT --policy FORWARD DROP
#################
## INPUT rules ##
#################
echo "INPUT RULES ***********************************************************"
echo
### From lo (Loopback)
# First trust traffic from our own server - accept input from lo
$IPT -A INPUT -i lo -j ACCEPT
### Basic I/O
#Allow icmp traffic internal->external & external->firewall
$IPT -A INPUT -i $IF_INT -p icmp -s $NET_INT -d $NET_EXT -j ACCEPT
$IPT -A INPUT -i $IF_EXT -p icmp -s $NET_EXT -d $IP_EXT -j ACCEPT
### From IF_INT (LAN)
# Block NETBIOS Broadcasts
echo "Blocking NETBIOS Broadcasts from LAN..."
$IPT -A INPUT -i $IF_INT -p udp --dport 137:139 -j DROP
echo
# What will we allow to arrive from the LAN
if [ "$GTW_ALLOWED" = "ALL" ]; then
echo "All traffic from LAN allowed..."
$IPT -A INPUT -i $IF_INT -s $NET_INT -j ACCEPT
echo
else
echo "Allowing established / related traffic from LAN..."
$IPT -A INPUT -i $IF_INT -s $NET_INT -m state \
--state ESTABLISHED,RELATED -j ACCEPT
echo
echo "Opening allowed ports from LAN..."
echo
echo "Port Prot Description"
echo "----- ---- -----------------------------------"
for filter in $GTW_ALLOWED; do
port=`echo $filter | awk -F , {'printf $1'}`
prot=`echo $filter | awk -F , {'printf $2'}`
desc=`echo $filter | awk -F , {'printf $3'}`
$IPT -A INPUT -i $IF_INT -p $prot -s $NET_INT \
--dport $port -j ACCEPT
printf "%5s %-4s %s\n" $port $prot $desc
done
echo
fi
### From IF_EXT (Internet)
# Block those annoying multicasts from ADSL modems...
echo "Blocking external multicast packets..."
$IPT -A INPUT -i $IF_EXT -d 224.0.0.0/24 -j DROP
echo
# Block annoying Windows Messenger PopUp spamming
echo "Blocking Windows Messenger PopUp packets..."
$IPT -A INPUT -i $IF_EXT -p udp --dport 1026 -j DROP
echo
# Traffic from IF_EXT claiming to be internal = spoofing -> reject
echo "Blocking IP Spoofing..."
$IPT -A INPUT -i $IF_EXT -s $NET_INT -j LOG --log-level 6 --log-prefix "FW: Spoofing: "
$IPT -A INPUT -i $IF_EXT -s $NET_INT -j REJECT
echo
# Allow incoming established / related traffic
echo "Allowing external incoming established / related traffic..."
$IPT -A INPUT -i $IF_EXT -s $NET_EXT -d $IP_EXT -m state \
--state ESTABLISHED,RELATED -j ACCEPT
echo
# Allow incoming traffic as defined in IN_ALLOWED
echo "Opening allowed incoming ports..."
echo
echo "Port Prot Description"
echo "----- ---- -----------------------------------"
for filter in $IN_ALLOWED; do
port=`echo $filter | awk -F , {'printf $1'}`
prot=`echo $filter | awk -F , {'printf $2'}`
desc=`echo $filter | awk -F , {'printf $5'}`
$IPT -A INPUT -i $IF_EXT -p $prot -s $NET_EXT \
-d $IP_EXT --dport $port -j ACCEPT
printf "%5s %-4s %s\n" $port $prot $desc
done
echo
### Anything else is not allowed and will be logged!
echo "Rejecting anything not allowed..."
#$IPT -A INPUT -j LOG --log-level 6 --log-prefix "FW: INPUT Not allowed: "
$IPT -A INPUT -j REJECT
echo
##################
## OUTPUT rules ##
##################
echo "OUTPUT RULES **********************************************************"
echo
### To lo (Loopback)
# Traffic to loopback is ok
$IPT -A OUTPUT -o lo -j ACCEPT
### To IF_INT (LAN)
# Out to IF_INT for local network is ok
$IPT -A OUTPUT -o $IF_INT -d $NET_INT -j ACCEPT
### To IF_EXT (internet)
# Out of IF_EXT for local network is not ok! (routing problem...)
echo "Blocking routing errors..."
$IPT -A OUTPUT -o $IF_EXT -d $NET_INT \
-j LOG --log-level 6 --log-prefix "FW: Routing problem: "
$IPT -A OUTPUT -o $IF_EXT -d $NET_INT -j REJECT
echo
# Rest to IF_EXT if ok
$IPT -A OUTPUT -o $IF_EXT -j ACCEPT
### Anything else is not allowed and will be logged!
echo "Rejecting anything not allowed..."
#$IPT -A OUTPUT -j LOG --log-level 6 --log-prefix "FW: OUTPUT Not allowed: "
$IPT -A OUTPUT -j REJECT
echo
###################
## FORWARD rules ##
###################
echo "FORWARD RULES *********************************************************"
echo
### Redirect port 80 if we use transparent proxy
if [ "$HTTP_PROXY" = "redirect" ]; then
echo "Redirecting http-requests to proxy..."
$IPT -t nat -A PREROUTING -i $IF_INT -p tcp --dport 80 \
-j REDIRECT --to-port $HTTP_PROXY_PORT
echo
fi
### Network Address Translation (NAT)
echo "Building NAT-table"
echo
echo "Port Prot To server Port Description"
echo "----- ---- --------------- ----- -----------------------------------"
for filter in $IN_ALLOWED; do
port_in=`echo $filter | awk -F , {'printf $1'}`
protocol=`echo $filter | awk -F , {'printf $2'}`
server=`echo $filter | awk -F , {'printf $3'}`
port_out=`echo $filter | awk -F , {'printf $4'}`
desc=`echo $filter | awk -F , {'printf $5'}`
# Include in NAT table
$IPT -t nat -A PREROUTING -i $IF_EXT -p $protocol --dport $port_in \
-j DNAT --to-destination $server:$port_out
# Accept in FORWARD chain
#$IPT -A FORWARD -i $IF_EXT -p $protocol --dport $port_in -j ACCEPT
$IPT -A FORWARD -i $IF_EXT -p $protocol --dport $port_out -d $server \
-j ACCEPT
printf "%5s %-4s %-15s %5s %s\n" $port_in $protocol $server $port_out $desc
done
echo
# Allow existing inbound
$IPT -A FORWARD -i $IF_EXT -o $IF_INT -m state \
--state ESTABLISHED,RELATED -j ACCEPT
# If HTTP_PROXY=block, Drop direct http requests from LAN
if [ "$HTTP_PROXY" = "block" ]; then
echo "Blocking outgoing direct http requests..."
$IPT -A FORWARD -i $IF_INT -p tcp --dport 80 -j DROP
echo
fi
# Other outbound traffic
if [ "$OUT_ALLOWED" = "ALL" ]; then
echo "Allowing all other outgoing traffic..."
$IPT -A FORWARD -i $IF_INT -o $IF_EXT -j ACCEPT
echo
else
echo "Opening allowed outgoing ports..."
echo
echo "Port(s) Prot Description"
echo "----------- ---- -----------------------------------"
for filter in $OUT_ALLOWED; do
port=`echo $filter | awk -F , {'printf $1'}`
prot=`echo $filter | awk -F , {'printf $2'}`
desc=`echo $filter | awk -F , {'printf $3'}`
$IPT -A FORWARD -i $IF_INT -p $prot --dport $port -j ACCEPT
printf "%11s %-4s %s\n" $port $prot $desc
done
echo
fi
### Anything else is not allowed and will be logged!
echo "Rejecting anything not allowed..."
#$IPT -A FORWARD -j LOG --log-level 6 --log-prefix "FW: FORWARD Not allowed: "
$IPT -A FORWARD -j REJECT
echo
#################
## POSTROUTING ##
#################
# Anything that passed through FORWARD must be MASQed
$IPT -t nat -A POSTROUTING -o $IF_EXT -j MASQUERADE
#$IPT -t nat -A POSTROUTING -o $IF_INT -j MASQUERADE
##############################
## Enable routing in kernel ##
##############################
echo "Setting kernel options..."
# Enable forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Enable reverse-path filter (prevents spoofing)
# This rejects packets coming in from a source address
# not matching the routing table
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
echo
# All done...
echo "Firewall configuration complete ***************************************"
So my questions are:
- What have I forgotten that I will regret later on?
- What should I include to protect me from worms, viruses, etc. (since there are two Windows machines on the network)
- Anything else that might be stupid that I have done...
Thanks for any suggestions!
I'm no safety-guru, just a guy learning more about iptables...
|