|
#!/bin/bash
#
# Jan K Labanowski, jkl@ccl.net, Nov, 2001 Thu Aug 30 23:17:39 EDT 2001
# Last modified: Wed Dec 19 02:50:04 EST 2001
#
# Please help me to maintain the script. If you see something wrong, bad
# or stupid, just tell me to fix it. Firewalls are not my specialty, what
# the true gurus can see. Reward me for my humility... .
#
# This "yet another firewal script" (YAFS) makes the assumption which I have
# at home. It uses kernel 2.4.7 which came with RH7.2. The
# iptables --version
# reports iptables v1.2.3
#
# This assumes that you have a few static addresses (e.g., provided by
# your ISP with your DSL service) and you want to setup your own servers
# etc. This approach is suitable if you have A FEW addresses. It can be
# reworked to do ranges quite easily, but as it is now, it does not
# use ranges, subnetting, etc. It also assimes that you run RedHat 7.2
# with latest kernel and iptables updates (it will not run without updates,
# since there is a bug in uptables 1.2.3 with log levels). The original
# 7.1 RH may run, but I did not try it. Next, you need to disable the
# iptables and ipchains startup scripts which came with the system (or
# when you installed firewall on your system. You do that:
# cd /etc/rc.d
# find . -name '[KS]*iptables' -print
# find . -name '[KS]*ipchains' -print
# You get read of them as:
# cd /etc/rc.d
# find . -name '[KS]*iptables' -exec rm {} \;
# find . -name '[KS]*ichains' -exec rm {} \;
#
# (of course, you can try:
# chkconfig --del iptables
# chkconfig --del ichains
# assuming that links were placed by chkconfig --add and scripts were not
# modified).
#
#
# This setip assumes that you have 3 ethernet cards.
# There are tons of confusing and often outdated notes on the Web about
# "Multiple Ethernet Cards". They often assume that you have the drivers
# compiled into the kernel. Read them, but remember that modern Linuces come
# with drivers as kernel modules, so all this stuff about lilo.conf and
# append is no longer valid. The way I do it is to have 3 cards which use
# different drivers (go to Hardware Compatibility List on RedHat site
# and see which cards use which drivers). In this case I was using
# the 3Com ISA 3c509 (module: 3c509), the 3Com PCI 3c900 Boomerang (module
# 3c59x), and Linksys NC100 (module tulip). After you install cards and
# reboot the machine, Linux kudzu will usually find them and ask you to
# configure the cards. Do it, but you will most likely have to correct the
# default settings. Also, you may need to add the parameters if the cards
# do not want to initialize with right interrupts numbers and IO addresses.
# You may also easily run out of iterrupts when you have other things
# installed on your system (like sound cards), or you have other things
# build into your motherboard. In this case, you may need to run BIOS Setup
# and disble serial ports or parallel port on your mother board, and play
# with PCI/PnP setting on your slots, until you get it right. Try also to
# change order in which modules are listed/loaded in /etc/modules.conf file.
# The relevant piece /etc/modules.conf file is:
#
# alias eth2 3c59x
# alias eth1 tulip
# alias eth0 3c509 irq=5
#
# I had to put them in reverse order, and "suggest" interrupt 5 for the
# Etherlink III card, since they were getting conflict initially. Before
# you give parameters, print the interrupts by:
#
# cat /proc/interrupts
#
# You can also list the IO port number which are taken by:
#
# cat /proc/ioports
#
# and if your card allows setting the ports, choose something which is not
# already taken and specify it with io=xxxx parameter in /etc/modules.conf.
# Note that the slowest card in my case (ISA 3c509) is used to talk to
# external Internet (eth0), since the DSL is far from saturating the bandwidth
# of the 10BT card. On the inside, I am using fast cards on my LAN and DMZ
# side, since here I can use their speed for backup or copying files
# back and forth, printer support, etc.
#
#
# My physical arrangement is similar to the following:
#
# [Internet/DSL]--eth0(3c509-ISA-10BT)::[Firewall/NAT]::eth1[Linksys/NC100]
# [5 static IPs] .. [PCI-10/100BT]
# eth2[3com900] | 192.168.0.1
# / 192.168.1.1 |
# / |
# / |
# / |
# / |
# / |
# / LAN |
# / uplink
# / ------------
# / | EtherHub |
# DMZ uplink | |--HOST1
# ------------ | |
# | EtherHub | | |--HOST2
# DNS1-HOST(eth0)-----| | . .
# 192.168.1.2 | | . .
# | | | |--HOSTn
# DNS2-HOST(eth0)-----| | ------------
# 192.168.1.3 | |
# /----------\
# / | \
# eth0 | eth0
# WEB-SERVER-1 | WEB-SERVER-2
# 192.168.1.4 | 192.168.1.5
# |
# eth0
# WEB-SERVER-3
# 192.168.1.6
# I have 5 static IP addresses and I want to do the following with them:
# a) do IP masquerading to provide access to Internet for the local subnet
# 192.168.0.0 (LAN). Connection to the computers on the LAN cannot be
# initiated from the outside, but can be initiated from the inside,
# i.e., when the computer on the LAN subnet wants to connect to some
# Web Server. The source address of the LAN computer in the packet
# will be changed to the address of the Firewall and Firewall (based
# on packet serial number) will direct the responses rom the outside
# net back to the appropriate computer on the LAN. While you can
# ssh from the LAN computer to some computer on the Internet, no computer
# will be able to ssh directly to LAN computers. To do this, one needs to
# first log into the Firewall or one of the DMZ computers if they allow
# logging in.
# NOTE: by experiment I found that you cannot access the
# DMZ computers from within DMZ using their "external" addresses.
# In other words, you cannot use the same URL for the web page
# as you would use outside. It may be a bug, or a feature, but the DNAT
# and SNAT do not work for me together on the same interface (in my case
# the eth2). Somehow, the netfilter gets confused. But you are perfectly
# OK to access the DMZ computers from your LAN subnet with their
# "external" IPs and ports. Do not ask me why... DNAT and SNAT should
# work in principle on the same interface, but they do not work for me.
#
#
# b) keep Web servers, DNSses, FTP servers, etc. in another local subnet
# 192.168.1.0 (DMZ). Here I can keep servers for up to 5 domains
# which represent 5 static IP addresses which I got assigned to my
# DSL service. The services to be redirected to them will be
# Port 20: ftp-data, Port 21: ftp, Port 25: smpt (e-mail),
# Port 53: domain (DNS server), Port 80: http (Web Server),
# Port 443: https (Secure Web Server). Nobody will be able to
# log into them directly, only via Firewall, or from inside (LAN),
#
# Now, back to configuration. I did initially the default configuration
# for the default /etc/rc.d/init.d/network script of Red Hat Linux.
# I actually sugest you do it to, so you can test your network conncetivity.
# My speakeasy.net Gateway was:
# 215.236.123.1
# My DNS addresses were: 216.254.95.2 and 216.231.41.2
# I named my DMZ domain as it would be named for the Web or mail, or whatever
# access on external Internet. Say, it was mymymy.com. You can name your
# LAN domain whatever you want. If you can make the host names different
# among ALL MACHINES (I mean, firewall, DMZ, and LAN), I would use the same
# domain as I use for external hosts.
#
# On the firewall I assigned IP addresses to all interfaces (i.e., NIC cards)
# as follows. For the eth0 interface, I used the the out-of-order address
# which I was given by ISP (they usually give you a range of consecutive
# addresses and one odd address, but it varies, and is probably random).
# Say, I chose my address as: 215.236.123.210 for the eth0 facing the WORLD.
#
# On each of my computers in DMZ and LAN (and firewall), I have an /etc/hosts
# file ( C:\WINNT\SYSTEM32\DRIVERS\ETC\HOSTS on Windoz2000 and C:\WINDOWS\HOSTS
# on Windoz9x ) which lists all computer names and domains with their real,
# actual, internal, IP addresses. I want them to talk to each other with their
# real IP addresses on internal wires. Note, these computers (especially the
# firewall and the computers in DMZ), will have different addresses in the
# DNS server -- there they have their external, "official", Internet addresses.
# Since the /etc/hosts file is by default searched first (you can make sure
# by having a file /etc/hosts.conf with lines
cat > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null </dev/null <ToPort". All REALATED and
# ESTABLISHED packets initiated by the connection to these ports will be
# directed to the corresponding DMZ machines.
# I am considering adding ranges syntax here, but I need to get it out fast.
# So no 20:25,30:50->2020-46 yet, maybe later.
#
# The popular ports are:
# FTP -- 20, 21
# SSH -- 22,
# TELNET -- 23
# E-MAIL -- 25
# WHOIS -- 43
# DNS -- 53
# GOPHER -- 70
# FINGER -- 79
# HTTP -- 80
# KERBEROS -- 88
# POP3 -- 110
# IDENT/AUTH -- 113
# NNTP -- 119
# NTP -- 123
# IMAP -- 143
# WAIS -- 210
# HTTPS -- 443
# X-WINDOW -- 6000:6063
# Also note that the above are "official" port numbers, but you can run stuff
# on other ports. I often saw people running SSHD on port 2222 (they had
# to change the sshd_config file). This actually allows you to do the trick.
# You can have the sshd running on DMZ machines on the different port than
# on the firewall, and when you use ssh without port number, you log in to
# firewall, and when you use it with a port number of sshd of the DMZ host
# (e.g., like: ssh -p 2222 ...) you can login directly to DMZ host from
# outside (you better have a password which cracker will not crack, though).
#faminor.edu (215.236.123.103)
INET_TO_DMZ[0]="215.236.123.103->192.168.1.129" # Hx
DNAT_TCP_PORTS[0]="20->20 21->21 22->22 25->25 80->9083 9083->9083"
DNAT_UDP_PORTS[0]=""
#basement.edu (215.236.123.104)
INET_TO_DMZ[1]="215.236.123.104->192.168.1.129" # Hx
DNAT_TCP_PORTS[1]="20->20 21->21 22->22 25->25 80->9084 9084->9084"
DNAT_UDP_PORTS[1]=""
#server1.cclun.edu (215.236.123.129)
INET_TO_DMZ[2]="215.236.123.129->192.168.1.129" # D3
DNAT_TCP_PORTS[2]="20->20 21->21 22->22 25->25 53->53 80->9081 9081->9081 443->9443 9443->9443"
DNAT_UDP_PORTS[2]="53->53"
#mail1.usdne.edu (215.236.123.130)
INET_TO_DMZ[3]="215.236.123.130->192.168.1.129" # 03
DNAT_TCP_PORTS[3]="20->20 21->21 22->22 25->25 80->9080 9080->9080 8080->7080 7080->7080"
DNAT_UDP_PORTS[3]=""
#chumisty.edu (215.236.123.131)
INET_TO_DMZ[4]="215.236.123.131->192.168.1.129" # 01
DNAT_TCP_PORTS[4]="20->20 21->21 22->22 25->25 53->53 80->9082 9082->9082"
DNAT_UDP_PORTS[4]="53->53"
#search1.cclun.edu (215.236.123.132)
INET_TO_DMZ[5]="215.236.123.132->192.168.1.132" # H1
DNAT_TCP_PORTS[5]="20->20 21->21 22->22 25->25 53->53 443->8443 8443->8443 7080->7080 8080->8080 9081->9081 9082->9082 9083->9083 9084->9084 9443->8443"
DNAT_UDP_PORTS[5]="53->53"
#bubulka.org (215.236.123.210)
INET_TO_DMZ[6]="215.236.123.210->192.168.1.210" # D3
DNAT_TCP_PORTS[6]="22->22 25->25 53->53"
DNAT_UDP_PORTS[6]="53->53"
LOOPBACK=127.0.0.0/8 # Idea taken from James C. Stephens
# http://www.cs.princeton.edu/~jns/security/iptables
IPTABLES=/sbin/iptables # this is where I have my iptables
MY_IP_BCAST="" # put here broadcast address for your subnet
# for example: MY_IP_BCAST="215.236.123.255"
# find my BROADCAST address (X.X.X.255) if the script was not updated above
if [ "${MY_IP_BCAST}x" = "x" ]; then
MY_IP_BCAST=`echo $MY_IP_ADDRESS | /bin/sed -e 's/\.[0-9]*$/.255/'`
fi
# find RPC UDP ports
RPC_UDP_PORTS=`/usr/sbin/rpcinfo -p localhost | grep udp | awk '{print $4}'`
# find RPC TCP ports
RPC_TCP_PORTS=`/usr/sbin/rpcinfo -p localhost | grep tcp | awk '{print $4}'`
# Mark in the /var/log/messages/notice that we are starting the firewall
/usr/bin/logger -p kern.notice -t NETFILTER \
"====== Netfilter Start: $DATE ========="
# check if needed iptables modules are loaded
/sbin/modprobe ip_tables
/sbin/modprobe ip_queue
/sbin/modprobe iptable_filter
/sbin/modprobe iptable_mangle
/sbin/modprobe iptable_nat
/sbin/modprobe ipt_limit
/sbin/modprobe ipt_LOG
/sbin/modprobe ipt_MASQUERADE
/sbin/modprobe ipt_MIRROR
/sbin/modprobe ipt_multiport
/sbin/modprobe ipt_REDIRECT
/sbin/modprobe ipt_REJECT
/sbin/modprobe ipt_state
/sbin/modprobe ipt_unclean
/sbin/modprobe ip_nat_ftp
/sbin/modprobe ip_conntrack
/sbin/modprobe ip_conntrack_ftp
# do not accept source routed packets
/bin/echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route
# do not accept ICMP redirects
/bin/echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects
$IPTABLES -t nat -P PREROUTING ACCEPT
$IPTABLES -t nat -P POSTROUTING ACCEPT
$IPTABLES -t filter -P INPUT DROP
$IPTABLES -t filter -P OUTPUT DROP
$IPTABLES -t filter -P FORWARD DROP
# Let us define some "routines" which we will "call" in other chains
# Some of those is to drop stuff, while at the same time I set my polices
# to drop, so it is redundant. In theory you could have only -j ACCEPT
# as your actions, but it is easier to DROP junk as soon as possible, so
# you can assume when you do ACCEPT stuff that the bad things are already
# in the trash...
#
# [[======= DropSpoof user defined chain ====]]
#
# DropSpoof -- drops nonroutable source addresses and our addresses
# if they came on $INET_IFACE. We will call them in INPUT
# and FORWARD chain
#
$IPTABLES -N DropSpoof
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 192.168.0.0/16 -j LOG \
# --log-level notice --log-prefix "192.168.x.x on eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 192.168.0.0/16 -j DROP
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 10.0.0.0/8 -j LOG \
# --log-level notice --log-prefix "10.x.x.x on eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 10.0.0.0/8 -j DROP
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 172.16.0.0/12 -j LOG \
# --log-level notice --log-prefix "10.x.x.x on eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 172.16.0.0/12 -j DROP
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 224.0.0.0/4 -j LOG \
# --log-level notice --log-prefix "224.0.0.0 on eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 224.0.0.0/4 -j DROP
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 240.0.0.0/5 -j LOG \
# --log-level notice --log-prefix "240.0.0.0 on eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -s 240.0.0.0/5 -j DROP
# $IPTABLES -t filter -A DropSpoof -i $INET_IFACE -d $LOOPBACK -j LOG \
# --log-level notice --log-prefix "loopback eth0: "
$IPTABLES -t filter -A DropSpoof -i $INET_IFACE -d $LOOPBACK -j DROP
# do not allow spoofing packets with your source address on the INET_IFACE
# The packets can only have our address as destination address but not source
to='*->';
from='->*';
let count=0
while (( $count < ${#INET_TO_DMZ[*]} ))
do
addresses=${INET_TO_DMZ[count]};
inet_address=${addresses%$from}; # extract the stuff before ->
# $IPTABLES -t filter -A DropSpoof -p ! icmp -i $INET_IFACE -s \
# ${inet_address} -j LOG --log-level notice
# --log-prefix "MY_IP on ${INET_IFACE}: "
$IPTABLES -t filter -A DropSpoof -p ! icmp -i $INET_IFACE \
-s ${inet_address} -j DROP
let count="count + 1"
done
# =============== End of DropSpoof ======================
# Kill PortScans (the badly formatted packets
# [[======= KillPortScans user defined chain ====]]
$IPTABLES -N KillPortScans
# REJECT ident requests...
# $IPTABLES -t filter -A KillPortScans -p tcp --dport 113 \
# -j LOG --log-level notice --log-prefix "IDENT1 ACPT : "
$IPTABLES -t filter -A KillPortScans -p tcp --dport 113 \
-j REJECT --reject-with tcp-reset
# reject port scans coming from $INET_IFACE
# $IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
# --tcp-flags ALL FIN,URG,PSH \
# -j LOG --log-level notice --log-prefix "FUP to eth0: "
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--tcp-flags ALL FIN,URG,PSH -j DROP
#
# $IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
# --tcp-flags ALL FIN -j LOG --log-level notice --log-prefix "F to eth0: "
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--tcp-flags ALL FIN -j DROP
# $IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
# --tcp-flags ALL NONE \
# -j LOG --log-level notice --log-prefix "NONE to eth0: "
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--tcp-flags ALL NONE -j DROP
#
# $IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
# --tcp-flags SYN,FIN SYN,FIN \
# -j LOG --log-level notice --log-prefix "SF to eth0: "
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--tcp-flags SYN,FIN SYN,FIN -j DROP
#
# $IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
# --tcp-flags SYN,RST SYN,RST \
# -j LOG --log-level notice --log-prefix "SR to eth0: "
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--tcp-flags SYN,RST SYN,RST -j DROP
# block RPC ports from INET_IFACE
for TCP_PORT in $RPC_TCP_PORTS; do
$IPTABLES -t filter -A KillPortScans -p tcp -i $INET_IFACE \
--dport $TCP_PORT -j DROP
done
# block RPC ports from INET_IFACE
for UDP_PORT in $RPC_UDP_PORTS; do
$IPTABLES -t filter -A KillPortScans -p udp -i $INET_IFACE \
--dport $UDP_PORT -j DROP
done
# ========================= End of KillPortScans =================
# These rules will be called in INPUT and FORWARD chain
# [[======= FilterICMP user defined chain ====]]
$IPTABLES -N FilterICMP
$IPTABLES -t filter -A FilterICMP -p icmp -i $LAN_IFACE -s $MY_IP_ADDRESS \
-j ACCEPT
$IPTABLES -t filter -A FilterICMP -p icmp -i $DMZ_IFACE -s $MY_IP_ADDRESS \
-j ACCEPT
# $IPTABLES -t filter -A FilterICMP -p icmp -i $DMZ_IFACE -j ACCEPT
# The -m limit option slows things down. Once I put something more robust
# for a firewall, I am commenting the ACCEPT/limit stuff
# You may comment the ACCEPT ones with -m limit, if your firewall is slow
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type echo-reply -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type destination-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type network-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type host-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type protocol-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type port-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type fragmentation-needed -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type source-route-failed -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type network-unknown -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type host-unknown -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type network-prohibited -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type host-prohibited -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type TOS-network-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type TOS-host-unreachable -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type communication-prohibited -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type host-precedence-violation -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type precedence-cutoff -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type source-quench -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type redirect -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type network-redirect -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type host-redirect -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type TOS-network-redirect -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type TOS-host-redirect -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type echo-request -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type router-advertisement -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type router-solicitation -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type time-exceeded -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type ttl-zero-during-transit -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type ttl-zero-during-reassembly -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type parameter-problem -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type ip-header-bad -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type required-option-missing -m limit --limit 1/s -j ACCEPT
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type timestamp-request -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type timestamp-reply -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type address-mask-request -j DROP
$IPTABLES -t filter -A FilterICMP -i $INET_IFACE -p icmp \
--icmp-type address-mask-reply -j DROP
# accept the others (though there should be no left, I hope...)
$IPTABLES -t filter -A FilterICMP -p icmp -j ACCEPT
# =============== End of FilterICMP =========================
# [[======= BlockPortFromOutside user defined chain ====]]
$IPTABLES -N BlockPortFromOutside
# block syslog, lpr, rsh, rexec
$IPTABLES -t filter -A BlockPortFromOutside -i $INET_IFACE -p udp \
--dport 514 -j DROP
$IPTABLES -t filter -A BlockPortFromOutside -i $INET_IFACE -p tcp \
--dport 514 -j DROP
$IPTABLES -t filter -A BlockPortFromOutside -i $INET_IFACE -p tcp \
--dport 515 -j DROP
$IPTABLES -t filter -A BlockPortFromOutside -i $INET_IFACE -p tcp \
--dport 512 -j DROP
# =============== End BlockPortFromOutside =================
# These rules will be called in OUTPUT and FORWARD chain
# [[======= DoNotSendOutside user defined chain ====]]
$IPTABLES -N DoNotSendOutside
# block all NetBios (Samba) stuff coming and going to INET_IFACE
# $IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE \
# --sport 137:139 -j LOG --log-level notice --log-prefix "SMB to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE \
--sport 137:139 -j DROP
# protect NFS through the firewall
# $IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE --sport 635 \
# -j LOG --log-level notice --log-prefix "UDP 635 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE \
--sport 635 -j DROP
# $IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE --sport 2049 \
# -j LOG --log-level notice --log-prefix "UDP 2049 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE \
--sport 2049 -j DROP
# $IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE --sport 111 \
# -j LOG --log-level notice --log-prefix "UDP 111 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p udp -o $INET_IFACE \
--sport 111 -j DROP
# block all NetBios (Samba) stuff coming and going to INET_IFACE
# $IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE \
# --sport 137:139 -j LOG --log-level notice --log-prefix "SMB to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE \
--sport 137:139 -j DROP
# protect NFS through the firewall
# $IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE --sport 635 \
# -j LOG --log-level notice --log-prefix "635 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE \
--sport 635 -j DROP
# $IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE --sport 2049 \
# -j LOG --log-level notice --log-prefix "2049 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE \
--sport 2049 -j DROP
# $IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE --sport 111 \
# -j LOG --log-level notice --log-prefix "111 to eth0: "
$IPTABLES -t filter -A DoNotSendOutside -p tcp -o $INET_IFACE \
--sport 111 -j DROP
# =============== End DoNotSendOutside =================
#==================================================================
#[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
#==================================================================
#
# This is where we start filtering (the stuff above is "subroutines"...
# While it is irrelevant which chain I start to shake first, I will try to
# follow the "abstract" route of a packed in netfilter
#
#[][][][][][][][][] PREROUTING [][][][][][][][][][][][][][][][][][]
#
# []*** PREROUTING ***[]
# Packet just entered the interface (ANY INTERFACE, i.e., eth0, eth1, or eth2)
#
#
# [[======= Rules for UDP protocol in PREROUTING chain ====]]
# perform DNAT for UDP addresses/ports
to='*->';
from='->*';
let count=0
while (( $count < ${#INET_TO_DMZ[*]} ))
do
addresses=${INET_TO_DMZ[count]};
inet_address=${addresses%$from};
dmz_address=${addresses#$to};
for ports in ${DNAT_UDP_PORTS[count]}
do
inet_port=${ports%$from};
dmz_port=${ports#$to};
# $IPTABLES -t nat -A PREROUTING -p udp -i $INET_IFACE \
# -d ${inet_address} --dport ${inet_port} -j DNAT \
# --to ${dmz_address}:${dmz_port}
$IPTABLES -t nat -A PREROUTING -p udp \
-d ${inet_address} --dport ${inet_port} -j DNAT \
--to ${dmz_address}:${dmz_port}
done
let count="count + 1"
done
# [[======= Rules for TCP protocol in PREROUTING chain ====]]
# perform DNAT on TCP addresses/ports
to='*->';
from='->*';
let count=0
while (( $count < ${#INET_TO_DMZ[*]} ))
do
addresses=${INET_TO_DMZ[count]};
inet_address=${addresses%$from};
dmz_address=${addresses#$to};
for ports in ${DNAT_TCP_PORTS[count]}
do
inet_port=${ports%$from};
dmz_port=${ports#$to};
# $IPTABLES -t nat -A PREROUTING -p tcp -i $INET_IFACE \
# -d $inet_address --dport ${inet_port}
# --log-level notice --log-prefix "PRE port ${INET_IFACE}:${dmz_port}: "
# $IPTABLES -t nat -A PREROUTING -p tcp -i $INET_IFACE \
# -d ${inet_address} --dport ${inet_port} -j DNAT \
# --to ${dmz_address}:${dmz_port}
$IPTABLES -t nat -A PREROUTING -p tcp \
-d ${inet_address} --dport ${inet_port} -j DNAT \
--to ${dmz_address}:${dmz_port}
done
let count="count + 1"
done
#[][][][][][][][][] INPUT [][][][][][][][][][][][][][][][][][]
#
# []*** INPUT ***[]
# Packet is destined FOR THE FIREWALL ITSELF.
#
# Reject spoof
$IPTABLES -t filter -A INPUT -j DropSpoof
# Kill port scans
$IPTABLES -t filter -A INPUT -j KillPortScans
# Filter ICMP
$IPTABLES -t filter -A INPUT -j FilterICMP
# Block certain ports from outside
$IPTABLES -t filter -A INPUT -j BlockPortFromOutside
# Allow SSH to Firewall
# This strange looking port is the SSHD port which I will be using
# on the firewall rather than the 22 port. I changed port 22 to 2222 in
# /etc/ssh/sshd_config and restarted sshd. Note that Port 22 will be
# forwarded to the DMZ zone (so I can log in directly to my DMZ machines).
# There is one problem though if you are logging with ssh to FW and to the DMZ
# machine which has matching address. Since on your local machine the file
# $HOME/.ssh/known_hosts and/or known_hosts2 are created the ssh will not
# allow you to connect to the "same" machine with different fingerprint
# (for ssh it is the same machine, since it does not mark entries known_hosts
# with the port number). You can cheat in a number of ways:
# 1) by deleting (or moving it to some file temporarily) known_hosts
# in $HOME/.ssh/known_host* before using ssh to FW
# 2) By using different ssh protocol (so in one case, the known_hosts
# is used, and in the other case, the known_hosts2 is used). For example
# ssh -2 -l root -p 22 my.machine.com
# ssh -1 -l root -p 2222 my.machine.com
# 3) You can change the /etc/ssh/ss_config file for ssh on your machine
# and set: StrictHostKeyChecking no
# 4) You can use:
# ssh -2 -l root -p 22 -o 'StrictHostKeyChecking no' 215.236.123.129
# One of them may work for you.
#
#
$IPTABLES -t filter -A INPUT -p tcp --syn --dport 2222 -m state \
--state NEW -j LOG --log-prefix "New SSH on FW:"
$IPTABLES -t filter -A INPUT -p tcp --syn --dport 2222 -m state \
--state NEW -j ACCEPT
# Allow NEW connections to anything on LAN and DMZ
# This assumes that you TRUST your LAN and DMZ. If you do not, you need
# to modify this... But then, you may not be able to log into your FW
# beside on its own keyboard...
# I probably should be paranoid, and think "What if someone breaks to my
# firewall? But then, if they break into, they will correct this table
# the way they want, so why bother...
#
$IPTABLES -t filter -A INPUT -i $LAN_IFACE -m state --state NEW \
-j ACCEPT
$IPTABLES -t filter -A INPUT -i $DMZ_IFACE -m state --state NEW \
-j ACCEPT
$IPTABLES -t filter -A INPUT -m state --state ESTABLISHED,RELATED \
-j ACCEPT
#[][][][][][][][][] FORWARD [][][][][][][][][][][][][][][][][][]
#
# []*** FORWARD ***[]
# Packets that are going LAN/DMZ <=> INET, and LAN <=> DMZ. These
# packets do not originate or end on the FW itself.
#
#
# Reject spoof
$IPTABLES -t filter -A FORWARD -j DropSpoof
# Kill port scans
$IPTABLES -t filter -A FORWARD -j KillPortScans
# Filter ICMP
$IPTABLES -t filter -A FORWARD -j FilterICMP
# Block certain ports from outside
$IPTABLES -t filter -A FORWARD -j BlockPortFromOutside
# log each SSH connection to DMZ
$IPTABLES -t filter -A FORWARD -p tcp -o $DMZ_IFACE --syn --dport 22 \
-m state --state NEW -j LOG --log-prefix "New SSH to DMZ"
# Allow the DNAT packets in the FORWARD chain
let count=0
while (( $count < ${#INET_TO_DMZ[*]} ))
do
addresses=${INET_TO_DMZ[count]};
inet_address=${addresses%$from};
dmz_address=${addresses#$to};
for ports in ${DNAT_UDP_PORTS[count]}
do
inet_port=${ports%$from};
dmz_port=${ports#$to};
# $IPTABLES -t filter -A FORWARD -p udp -i $INET_IFACE \
# -d ${dmz_address} --dport ${dmz_port} \
# -m state --state NEW \
# --log-level notice --log-prefix "FORW ${INET_IFACE}:${inet_port}: "
# $IPTABLES -t filter -A FORWARD -p udp -i $INET_IFACE \
# -m state --state NEW \
# -d ${dmz_address} --dport ${dmz_port} -j ACCEPT
$IPTABLES -t filter -A FORWARD -p udp \
-m state --state NEW \
-d ${dmz_address} --dport ${dmz_port} -j ACCEPT
done
let count="count + 1"
done
let count=0
while (( $count < ${#INET_TO_DMZ[*]} ))
do
addresses=${INET_TO_DMZ[count]};
inet_address=${addresses%$from};
dmz_address=${addresses#$to};
for ports in ${DNAT_TCP_PORTS[count]}
do
inet_port=${ports%$from};
dmz_port=${ports#$to};
# $IPTABLES -t filter -A FORWARD -p tcp -i $INET_IFACE \
# -d ${dmz_address} --dport ${dmz_port} \
# -m state --state NEW \
# --log-level notice --log-prefix "FORW ${INET_IFACE}:${inet_port}: "
# $IPTABLES -t filter -A FORWARD -p tcp -i $INET_IFACE \
# -m state --state NEW \
# -d ${dmz_address} --dport ${dmz_port} -j ACCEPT
$IPTABLES -t filter -A FORWARD -p tcp \
-m state --state NEW \
-d ${dmz_address} --dport ${dmz_port} -j ACCEPT
done
let count="count + 1"
done
# Allow NEW connections to anywhere and anything from LAN and DMZ
# This assumes that you TRUST your LAN and DMZ.
#
$IPTABLES -t filter -A FORWARD -i $LAN_IFACE -m state --state NEW \
-j ACCEPT
$IPTABLES -t filter -A FORWARD -i $DMZ_IFACE -m state --state NEW \
-j ACCEPT
$IPTABLES -t filter -A FORWARD -m state --state ESTABLISHED,RELATED \
-j ACCEPT
#[][][][][][][][][] OUTPUT [][][][][][][][][][][][][][][][][][]
#
# []*** OUTPUT ***[]
# Packets that were created by FW itself and go outside:
# FW => INET, FW => LAN, FW => DMZ
# Again... I trust that all connections initiated from FW are OK
#
$IPTABLES -t filter -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED \
-j ACCEPT
#[][][][][][][][][] POSTROUTING [][][][][][][][][][][][][][][][][][]
#
# []*** POSTROUTING ***[]
# *** set SNAT/MASQUARADING on the MY_IP_ADDRESS on the list ***
$IPTABLES -t nat -A POSTROUTING -o $INET_IFACE -s ${LAN_IP} -j SNAT \
--to $MY_IP_ADDRESS
$IPTABLES -t nat -A POSTROUTING -o $INET_IFACE -s ${DMZ_IP} -j SNAT \
--to $MY_IP_ADDRESS
# =================================================================
# These are commented out. You use them for debugging.
# These LOG entries list all packets which were missed by previous rules
# Not, all policies are set to DROP
# You have a choice:
# Uncomment only -j LOG rules (packets will be logged but dropped nevertheless
# Use it occassionally to see what kind of garbage hits your firewall
# Uncomment all lines, so packets are ACCEPTed and LOGged
# Use this, when you want to provide rules for a new protocol or service
# and you want to ALLOW everything, and then look up in messages.notice
# which rules are need to make it through the firewall.
# In production setting, these rules SHOULD BE ALWAYS commented out.
#
# $IPTABLES -t nat -A POSTROUTING -j LOG \
# --log-level notice --log-prefix "POST DEBUG: "
# $IPTABLES -t nat -A POSTROUTING -j ACCEPT
#
# $IPTABLES -t nat -A PREROUTING -j LOG \
# --log-level notice --log-prefix "PRE DEBUG: "
# $IPTABLES -t nat -A PREROUTING -j ACCEPT \
#
# $IPTABLES -t filter -A INPUT -j LOG \
# --log-level notice --log-prefix "INPUT DEBUG: "
# $IPTABLES -t filter -A INPUT -j ACCEPT
#
# $IPTABLES -t filter -A OUTPUT -j LOG \
# --log-level notice --log-prefix "OUTPUT DEBUG: "
# $IPTABLES -t filter -A OUTPUT -j ACCEPT
#
# $IPTABLES -t filter -A FORWARD -j LOG \
# --log-level notice --log-prefix "FORWARD DEBUG: "
# $IPTABLES -t filter -A FORWARD -j ACCEPT
#
# $IPTABLES -t nat -A POSTROUTING -j LOG \
# --log-level notice --log-prefix "POST DEBUG: "
# $IPTABLES -t nat -A POSTROUTING -j ACCEPT
# $IPTABLES -t filter -A INPUT -j LOG \
# --log-level notice --log-prefix "INPUT DEBUG: "
# $IPTABLES -t filter -A INPUT -j ACCEPT
# $IPTABLES -t filter -A OUTPUT -j LOG \
# --log-level notice --log-prefix "OUTPUT DEBUG: "
# $IPTABLES -t filter -A OUTPUT -j ACCEPT
# $IPTABLES -t filter -A FORWARD -j LOG \
# --log-level notice --log-prefix "FORWARD DEBUG: "
# $IPTABLES -t filter -A FORWARD -j ACCEPT
# Turn on the IP Forwarding
/bin/echo 1 > /proc/sys/net/ipv4/ip_forward
|