Nasser Heidari

2009-04-14

Firewall Script

Filed under: Linux — Nasser Heidari @ 19:42

I recommend to take a look at this pages before you start :
Linux Firewall-related /proc Entries
http://iptables-tutorial.frozentux.net/other/ip-sysctl.txt

#!/bin/bash
#http://github.com/jwiegley/jw.firewall/blob/57b08f6d01671336dca7474ca4f38e84fab583cd/firewall.iptables
IPTABLES=$1
MYNAME=$2
 
######################################################################
#
# rc.firewall
#
# version 1.13 (2007/11/03) by John Wiegley 
#
# This script is based on a similar firewalling script I wrote for ipfw,
# but has been changed to utilize iptables. Also, it is customized
# solely for running on johnwiegley.com, and does not contain any
# configuration options.
#
# Revision history:
# 1.01: Added port knocking for ssh access.
# 1.02: Lock out ssh port scanners for 5 minutes.
# 1.03: Remove port scanners from lockout after 5 mins good behavior.
# 1.04: Flush the nat table as well as the filter (default) table.
# 1.05: Use hashlimit for connection rate limiting instead of recent.
# 1.06: Extended portscan lockout to an entire day.
# 1.07: Removed an excessive rule.
# 1.08: Commented out rate limiting of Apache.
# 1.09: Increased SSH availability to one day.
# 1.10: Drop ICMP redirect packets.
# 1.11: Decrease SYN flood rate limit to 60 conns per second.
# 1.12: Don't filter based on the connection source port.
# 1.13: Opened up the IMAP/S port 993.
#
######################################################################
 
$IPTABLES -F
$IPTABLES -t nat -F
$IPTABLES -X
 
$IPTABLES -t nat -P PREROUTING ACCEPT
$IPTABLES -t nat -P POSTROUTING ACCEPT
$IPTABLES -t nat -P OUTPUT ACCEPT
 
$IPTABLES -t nat -A POSTROUTING -o eth0 -j MASQUERADE
 
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -P OUTPUT ACCEPT
 
if [[ $2 == flush ]]; then
exit 0
fi
 
######################################################################
 
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT ACCEPT
 
# Drop invalid packets immediately
$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A FORWARD -m state --state INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
 
# Allow trusted interfaces
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A INPUT -i tun+ -j ACCEPT
$IPTABLES -A FORWARD -i tun+ -j ACCEPT
$IPTABLES -A FORWARD -o tun+ -j ACCEPT
 
# Drop suspicious IP packets
#$IPTABLES -A INPUT -m ipv4options --rr -j DROP
#$IPTABLES -A INPUT -m ipv4options --ts -j DROP
#$IPTABLES -A INPUT -m ipv4options --lsrr -j DROP
#$IPTABLES -A INPUT -m ipv4options --ssrr -j DROP
 
# Drop bogus TCP packets
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
 
# Allow multicast DNS packets. jww (2007-09-09): This may be needed at
# Server Axis for determining server presence. I have to ask them.
$IPTABLES -A INPUT -d 224.0.0.251 -p udp -m udp --dport mdns -j ACCEPT
 
# Reject packets from RFC1918 class networks (i.e., spoofed)
$IPTABLES -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP
$IPTABLES -A INPUT -s 192.168.0.0/16 -j DROP
$IPTABLES -A INPUT -s 169.254.0.0/16 -j DROP
if [[ $MYNAME == "johnwiegley.com" ]]; then
    $IPTABLES -A INPUT -s 172.16.0.0/12 -j DROP
fi
$IPTABLES -A INPUT -s 127.0.0.0/8 -j DROP
 
$IPTABLES -A INPUT -s 224.0.0.0/4 -j DROP
$IPTABLES -A INPUT -d 224.0.0.0/4 -j DROP
$IPTABLES -A INPUT -s 240.0.0.0/5 -j DROP
$IPTABLES -A INPUT -d 240.0.0.0/5 -j DROP
$IPTABLES -A INPUT -s 0.0.0.0/8 -j DROP
$IPTABLES -A INPUT -d 0.0.0.0/8 -j DROP
$IPTABLES -A INPUT -d 239.255.255.0/24 -j DROP
$IPTABLES -A INPUT -d 255.255.255.255 -j DROP
 
# Reject packets spoofed to appear as if from us
if [[ $MYNAME == "johnwiegley.com" ]]; then
    $IPTABLES -A INPUT -s 208.70.150.153 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.154 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.155 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.156 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.157 -j DROP
fi
 
# Allow most ICMP packets to be received (so people can check our
# presence), but restrict the flow to avoid ping flood attacks
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type redirect -j DROP
$IPTABLES -A INPUT -p icmp -m icmp -m limit --limit 1/second -j ACCEPT
 
# Anyone trying to portscan us at port 139 is locked out for 1 day.
$IPTABLES -A INPUT -m recent --name portscan --rcheck --seconds 86400 -j DROP
$IPTABLES -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP
$IPTABLES -A INPUT -m recent --name portscan --remove
 
$IPTABLES -A INPUT -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j LOG --log-level 4 --log-prefix "Portscan:"
$IPTABLES -A INPUT -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j DROP
$IPTABLES -A FORWARD -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j LOG --log-level 4 --log-prefix "Portscan:"
$IPTABLES -A FORWARD -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j DROP
 
# jww (2007-09-09): I don't think this can be done with iptables alone,
# so I satisfy myself with limiting RST packets instead. Intention:
# Delay RST packets by 0.5 seconds to avoid SMURF attacks, by given the
# next real data packet in the sequence a better chance to arrive first.
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags RST RST \
    -m limit --limit 2/second --limit-burst 2 -j ACCEPT
 
# If we are using IPsec, these rules allow such packets through
#$IPTABLES -A INPUT -p ah -j ACCEPT
#$IPTABLES -A INPUT -p esp -j ACCEPT
 
# Allow established and related packets
$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
 
# Discard any left over fragments
$IPTABLES -A INPUT -f -j DROP
 
# Protect against SYN floods by rate limiting the number of new
# connections from any host to 60 per second. This does *not* do rate
# limiting overall, because then someone could easily shut us down by
# saturating the limit.
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp --syn \
    -m recent --name synflood --update --seconds 1 --hitcount 60 -j DROP
 
# Reply to unknown "NEW" SYN/ACK packets with a RESET, so we can't be
# used as a middle-man for Sequence Number Prediction based spoof
# attacks.
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp \
    --tcp-flags SYN,ACK SYN,ACK -j REJECT --reject-with tcp-reset
 
# Log and drop NEW packets which don't have the SYN bit set
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp ! --syn \
    -j LOG --log-level 4 --log-prefix "New !SYN:"
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp ! --syn -j DROP
 
# If any packets reach this point that have the ACK bit sent (but not
# SYN), respond with a TCP reset
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags ACK ACK \
    -j REJECT --reject-with tcp-reset
 
# DNS
$IPTABLES -A INPUT -m state --state NEW -p udp -m udp --dport domain -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp --dport domain -j ACCEPT
 
# OpenVPN
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport 1194 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 1195 -j ACCEPT
 
# FTP, but allow only 5 open connections per host, and 5 new connections
# per minute from any given host (to block brute force scans)
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# --dport ftp -m connlimit --connlimit-above 5 -j DROP
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport ftp -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport rsync -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport rsync -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport git -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name gitusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport git -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name gitusers -j ACCEPT
 
# SSH, but allow only 2 new connections per minute from any given host
# (to block brute force scans), and only after knocking first at port
# 1908.
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# --dport ssh -m recent --rcheck --seconds 86400 --name sshusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport ssh -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1907 -m recent --name sshusers --remove \
    -j REJECT --reject-with icmp-admin-prohibited
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1908 -m recent --name sshusers --set \
    -j REJECT --reject-with icmp-admin-prohibited
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1909 -m recent --name sshusers --remove \
    -j REJECT --reject-with icmp-admin-prohibited
 
# Web, but allow only 10 open connections per host, and 40 new
# connections per minute from any given host
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# -m multiport --dports http,https -m connlimit --connlimit-above 10 -j DROP
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    -m multiport --dports http,https -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 8080 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 8007 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 9090 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 5050 -j ACCEPT
# -m hashlimit --hashlimit 40/min --hashlimit-mode srcip --hashlimit-name webusers -j ACCEPT
 
# if a connection comes in to .157:80, redirect it to local port 8080
$IPTABLES -t nat -A PREROUTING -s 208.70.150.157 -p tcp -m tcp --dport 80 \
    -j REDIRECT --to-ports 8080
 
# SMTP, but allow only 5 open connections per host, and 10 new connections per
# minute from any given host. And only listen at mail.johnwiegley.com.
DEST=""
if [[ $MYNAME == "johnwiegley.com" ]]; then
DEST="-d 208.70.150.154"
fi
#$IPTABLES -A INPUT -m state --state NEW $DEST -p tcp -m tcp \
# -m multiport --dports smtp,submission -m connlimit --connlimit-above 5 -j DROP
$IPTABLES -A INPUT -m state --state NEW $DEST -p tcp -m tcp \
    -m multiport --dports smtp,submission,imaps -m hashlimit \
    --hashlimit 10/min --hashlimit-mode srcip --hashlimit-name mailusers -j ACCEPT
 
# Reject all others by letting them know that such communication with the host
# is forbidden
$IPTABLES -A INPUT -j REJECT --reject-with icmp-admin-prohibited
 
echo If you can exit me now, things are OK...
sleep 120
 
exec $0 $IPTABLES flush
Advertisements

1 Comment »

  1. Hi, nice post. I have been wondering about this topic,so thanks for blogging. I’ll probably be coming back to your blog. Keep up great writing

    Comment by With This Diet I Shed T h i r t y P o u n d s in Thirty Days — 2009-05-06 @ 13:05


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: