#!/bin/sh
# rc.firewall - Initial SIMPLE IP Firewall script for Linux 2.4.x and iptables
# Copyright (C) 2001  Oskar Andreasson <bluefluxATkoffeinDOTnet>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program or from the site that you downloaded it
# from; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA  02111-1307   USA

#################################################################################
#################################################################################
# TODO: this isn't nearly perfect yet.  should unload modules upon stopping,
# TODO: consider whether NAT should remain enabled or disabled upon stopping,
# TODO: and maybe more.  also clean up the rest of this file a lot.
# TODO: currently can't be used for forwarding one port range to another.
# TODO: see DESTINATION variable (can't have ip:port1:port2).
#################################################################################
#################################################################################
 
#################################################################################
# allowPort - opens the specified port and forwards to another IP, if necessary.
# usage: allowPort <protocol> <src ip> <ext port> <int ip> <int port> <port desc> <dest hostname>
# 
# src ip: wan source ip/subnet of packet.  can be the word "all".
# int ip: lan destination for packet.
#
# external port and internal port allow you to forward from an external port on the
# public ip to a different internal port on a private ip.
#
# port desc: quoted string describing the port usage, ie "www", "unreal tournament".
#
# optional dest hostname is currently not used, and is more for informational purposes.
# in the future it may be used for dynamic hostname/ip forwarding.
#################################################################################
function setPorts {
	allowPort tcp all 22					192.168.0.1		22					"ssh"								Gateway
	allowPort tcp all 53					192.168.0.1		53					"dns (bind)"				Gateway
	allowPort tcp all 113					192.168.0.1		113					"ident (irc)"				Gateway
	
	allowPort udp all 53					192.168.0.1		53					"dns (bind)"				Gateway
	allowPort udp all 67					192.168.0.1		67					"dhcp (isp)"				Gateway
	allowPort udp all 68					192.168.0.1		68					"dhcp (isp)"				Gateway
	
	allowPort tcp all 20					192.168.0.2		20					"ftp-data"					TheCart
	allowPort tcp all 21					192.168.0.2		21					"ftp-control"				TheCart
	allowPort tcp all 25					192.168.0.2		25					"smtp"							TheCart
	allowPort tcp all 80					192.168.0.2		80					"http"							TheCart
	allowPort tcp all 110					192.168.0.2		110					"pop3"							TheCart
	allowPort tcp all 143					192.168.0.2		143					"imap"							TheCart
	allowPort tcp all 443					192.168.0.2		443					"https"							TheCart
	allowPort tcp all 873					192.168.0.2		873					"rsync"							TheCart
	allowPort tcp all 993					192.168.0.2		993					"imap/ssl"					TheCart
	allowPort tcp all 1214				192.168.0.2		1214				"fasttrack"					TheCart
	allowPort tcp all 1723				192.168.0.2		1723				"pptp vpn"					TheCart
	allowPort tcp all 2010:2020		192.168.0.2		2010:2020		"karr dcc"					TheCart
	allowPort tcp all 2525				192.168.0.2		25					"smtp (xjjk relay)"	TheCart
	allowPort tcp all 2222				192.168.0.2		22					"ssh (www people)"	TheCart
	allowPort tcp all 3333				192.168.0.2		3333				"karr telnet"				TheCart
	allowPort tcp all 3334				192.168.0.2		3334				"/dev/bot telnet"		TheCart
	allowPort tcp all 4662				192.168.0.2		4662				"mldonkey"					TheCart
	allowPort tcp all 6346				192.168.0.2		6346				"gnutella"					TheCart
	allowPort tcp all 6347				192.168.0.2		6347				"gnutella 2"				TheCart
	allowPort tcp all 6885:6889		192.168.0.2		6885:6889		"bt client"					TheCart
	allowPort tcp all 6891:6892		192.168.0.2		6891:6892		"bt/filelist"				TheCart
	allowPort tcp all 8082				192.168.0.2		8082				"bt tracker 1"			TheCart
	allowPort tcp all 8083				192.168.0.2		8083				"bt tracker 2"			TheCart
	allowPort tcp all 8084				192.168.0.2		8084				"bt 1 link"					TheCart
	allowPort tcp all 8888:8892		192.168.0.2		8888:8892		"openvpn server"		TheCart
	allowPort tcp all 60000:60010	192.168.0.2		60000:60010	"ftp (passive)"			TheCart
	
	allowPort udp all 5000				192.168.0.2		5000				"openvpn server"		TheCart
	allowPort udp all 8888:8892		192.168.0.2		8888:8892		"also openvpn?"			TheCart
	allowPort udp all 6891:6892		192.168.0.2		6891:6892		"bt/filelist"				TheCart
	
	allowPort tcp all 6881:6884		192.168.0.17	6881:6884		"bt"								VeeAte
	allowPort tcp all 6894				192.168.0.17	6894				"bt/filelist"				VeeAte
	allowPort tcp all 8081				192.168.0.17	8081				"crackattack"				VeeAte
	allowPort tcp all 6000				192.168.0.17	6000				"gunzonline 1"			VeeAte
	allowPort tcp all 7700				192.168.0.17	7700				"gunzonline 2"			VeeAte
	allowPort tcp all 4400				192.168.0.17	4400				"gunzonline 3"			VeeAte
	allowPort udp all 6000				192.168.0.17	6000				"gunzonline 1"			VeeAte
	allowPort udp all 7700				192.168.0.17	7700				"gunzonline 2"			VeeAte
	allowPort udp all 4400				192.168.0.17	4400				"gunzonline 3"			VeeAte
	
	allowPort tcp all 6890				192.168.0.25	6890			"bt/filelist"					Colgate
}

# examples of other things that can be done.
# #$IPTABLES -A INPUT -p TCP -s $IPV6_SVR --dport 4343 -j ACCEPT
# #$IPTABLES -t nat -A PREROUTING -p TCP -s 0/0 --dport 1723 -j LOG
# #$IPTABLES -t nat -A PREROUTING -p TCP -s 0/0 --dport 25 -j LOG
# # ASB, 20021228, allow ipv6 tunnel traffic
# #$IPTABLES -A INPUT -p ipv6-tunnel -s $IPV6_SVR -j ACCEPT
# # 20040102, ASB, block outgoing 44000 udp for ravenshield
# #$IPTABLES -A OUTPUT -p udp -o $INET_IFACE --dport 44000 -j DROP

# 1.5 IPTables Configuration.
IPTABLES="/usr/sbin/iptables"
	
function flush {
	# ASB, 20021228, flush rulesets (more or less)
	$IPTABLES -F
	$IPTABLES -t nat -F
	$IPTABLES -t mangle -F
	$IPTABLES -X
	$IPTABLES -t nat -X
	$IPTABLES -t mangle -X
}

# see documentation for allowPort above, where it's called.
function allowPort {
	if [ $# -lt 6 -o $# -gt 7 ]; then
		echo "ERROR (allowPort): must specify 5-6 args (specified $(($# - 1)))."
		return
	fi

	PROTOCOL=$1; EXT_PORT=$3; INT_IP=$4; INT_PORT=$5; PORT_DESC="$6" DEST_HOST=$7
	# allow for wildcard: all = 0/0
	if [ "$2" = "all" ]; then
		SRC_IP=0/0
	else
		SRC_IP="$2"
	fi

	# _insert_ rules for localhost at beginning of chains.
	if [ "$INT_IP" = "$LAN_IP" ]; then
		#if [ "$EXT_PORT" != "$INT_PORT" ]; then
			#$IPTABLES -t nat -I PREROUTING -p $PROTOCOL -d $INET_IP -s "$SRC_IP" --dport $EXT_PORT -j DNAT --to-destination $INET_IP:
		#fi
		if echo "$PROTOCOL" | grep -i '^tcp$' 1> /dev/null 2> /dev/null ; then
			$IPTABLES -I tcp_packets -p $PROTOCOL -s "$SRC_IP" --dport $INT_PORT -j allowed
		elif echo "$PROTOCOL" | grep -i '^udp$' 1> /dev/null 2> /dev/null; then
			$IPTABLES -I udpincoming_packets -p $PROTOCOL -s "$SRC_IP" --destination-port $INT_PORT -j ACCEPT
		else
			echo "ERROR (allowPort): bad protocol \"$PROTOCOL\"."
		fi
	else
		# _insert_ rules FORWARD rules for opening/forwarding ports for other boxen.
		# PREROUTING can be -I or -A, but will -I to keep things consistent for now.
		if [ "$EXT_PORT" = "$INT_PORT" ]; then
			DESTINATION="$INT_IP"
			DPORT=$INT_PORT
			$IPTABLES -I FORWARD -p $PROTOCOL -i $INET_IFACE -o $LAN_IFACE -d $INT_IP --dport $DPORT -j ACCEPT
		else
			DESTINATION="$INT_IP:$INT_PORT"
			DPORT=$EXT_PORT
				$IPTABLES -I FORWARD -p $PROTOCOL -i $INET_IFACE -o $LAN_IFACE -d $INT_IP --dport $INT_PORT -j ACCEPT
		fi
		$IPTABLES -t nat -I PREROUTING -p $PROTOCOL -d $INET_IP -s "$SRC_IP" --dport $DPORT -j DNAT --to-destination $DESTINATION
	fi
}

function start {
	###########################################################################
	# 1. Configuration options.
	
	# 1.1 Internet Configuration.
	INET_IFACE="eth0"
	INET_IP="$(ifconfig $INET_IFACE | sed -ne 's/.*inet addr:\([0-9\.]*\) .*/\1/p')"
	if [ -z "$INET_IP" ]; then
		echo "FATAL ERROR: Could not get IP for internet interface \"$INET_IFACE\"! Exiting."
		exit -1
	fi
	
	# 1.2 Local Area Network configuration.
	# your LAN's IP range and localhost IP. /24 means to only use the first 24
	# bits of the 32 bit IP adress. the same as netmask 255.255.255.0
	
	LAN_IFACE="eth1"
	LAN_IP="$(ifconfig $LAN_IFACE | sed -ne 's/.*inet addr:\([0-9\.]*\) .*/\1/p')"
	# next line turns 192.168.0.1 into 192.168.0.0/24, assumes Class C.
	LAN_IP_RANGE="$(echo $LAN_IP | cut -d . -f -3).0/24"
	LAN_BCAST_ADRESS="255.255.255.255"
	
	# 1.4 Localhost Configuration.
	LO_IFACE="lo"
	LO_IP="127.0.0.1"
	
	# 1.6 Other Configuration.
	
	###########################################################################
	# 2. Module loading.


#	<krazyivan> yeah, i had a problem with diff ext/int ports on the gateway
#	<krazyivan> i have a suggestion for your module loading section too
#	<krazyivan> if you're serving up FTP from behind the firewall on a non-standard port, the modprobes need to look like this
#	<krazyivan> modprobe ip_conntrack_ftp ports=21,2121
#	<krazyivan> modprobe ip_nat_ftp ports=21,2121
#	<krazyivan> where 2121 is that non-standard port
#	<krazyivan> and ports= can define up to 8 ports
#	<krazyivan> might wanna make a note of that in a comment
#	<amrit> ahh, i see.. i never knew how to use that anyway
#	<krazyivan> yeah, those are needed for passive ftp to work nat'd

	
	# Needed to initially load modules
	/sbin/depmod -A
	
	# 2.1 Required modules
	/sbin/modprobe ip_tables
	/sbin/modprobe ip_conntrack
	/sbin/modprobe iptable_filter
	/sbin/modprobe iptable_mangle
	/sbin/modprobe iptable_nat
	/sbin/modprobe ipt_LOG
	/sbin/modprobe ipt_limit
	/sbin/modprobe ipt_state
	
	# 2.2 Non-Required modules
	#/sbin/modprobe ipt_owner
	#/sbin/modprobe ipt_REJECT
	#/sbin/modprobe ipt_MASQUERADE
	/sbin/modprobe ip_conntrack_ftp
	/sbin/modprobe ip_conntrack_irc
	
	###########################################################################
	# 3. /proc set up.
	
	# 3.1 Required proc configuration
	# moved to the end
	
	# 3.2 Non-Required proc configuration
	#echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter
	#echo "1" > /proc/sys/net/ipv4/conf/all/proxy_arp
	#echo "1" > /proc/sys/net/ipv4/ip_dynaddr
	
	###########################################################################
	# 4. rules set up.
	
	# 4.0.5 All allowed ports
	
	# 4.1 Filter table
	
	# 4.1.1 Set policies
	$IPTABLES -P INPUT DROP
	$IPTABLES -P OUTPUT DROP
	$IPTABLES -P FORWARD DROP
	
	# 4.1.2 Create userspecified chains
	# Create chain for bad tcp packets
	$IPTABLES -N bad_tcp_packets
	
	# Create separate chains for ICMP, TCP and UDP to traverse
	$IPTABLES -N allowed
	$IPTABLES -N icmp_packets
	$IPTABLES -N tcp_packets
	$IPTABLES -N udpincoming_packets
	
	# 4.1.3 Create content in userspecified chains
	# bad_tcp_packets chain
	$IPTABLES -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j LOG \
	--log-prefix "New not syn:"
	$IPTABLES -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j DROP
	
	# allowed chain
	$IPTABLES -A allowed -p TCP --syn -j ACCEPT
	$IPTABLES -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
	$IPTABLES -A allowed -p TCP -j DROP
	
	# 20050115, ASB, for dad's laptop
	$IPTABLES -A INPUT -i ath0 -m mac --mac-source 00:0d:88:c1:4a:22 -j ACCEPT
	# 20050115, another on 23?
	$IPTABLES -A INPUT -i ath0 -m mac --mac-source 00:13:46:01:ba:ad -j ACCEPT
	
	# ICMP rules
	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -j ACCEPT
	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT
	
	# 4.1.4 INPUT chain
	# Bad TCP packets we don't want.
	$IPTABLES -A INPUT -p tcp -j bad_tcp_packets
	
	# Rules for special networks not part of the Internet
	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -s $LAN_IP_RANGE -j ACCEPT
	# 20050115, ASB, for dad's laptop
	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -s 192.168.1.0/24 -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -s $INET_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LO_IFACE -s $LO_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LO_IFACE -s $LAN_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LO_IFACE -s $INET_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -d $LAN_BCAST_ADRESS -j ACCEPT
	
	# Rules for incoming packets from the internet.
	$IPTABLES -A INPUT -p ALL -d $INET_IP -m state --state ESTABLISHED,RELATED \
	-j ACCEPT
	$IPTABLES -A INPUT -p TCP -i $INET_IFACE -j tcp_packets
	$IPTABLES -A INPUT -p UDP -i $INET_IFACE -j udpincoming_packets
	$IPTABLES -A INPUT -p ICMP -i $INET_IFACE -j icmp_packets
	
	# Log weird packets that don't match the above.
	$IPTABLES -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG \
	--log-level DEBUG --log-prefix "IPT INPUT packet died: "
	
	# 4.1.5 FORWARD chain
	# Bad TCP packets we don't want
	$IPTABLES -A FORWARD -p tcp -j bad_tcp_packets
	
	# Accept the packets we actually want to forward
	$IPTABLES -A FORWARD -i $LAN_IFACE -j ACCEPT
	# 20050115, ASB, for dad's laptop
	$IPTABLES -A FORWARD -i ath0 -j ACCEPT
	$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
	
	# 20030628, ASB, workaround to make lanIPs->wanIP:forwardedPort work
	$IPTABLES -t nat -A POSTROUTING -s 192.168.0.0/24 -d 192.168.0.2 -j SNAT --to-source 192.168.0.1
	
	# Log weird packets that don't match the above.
	$IPTABLES -A FORWARD -m limit --limit 3/minute --limit-burst 3 -j LOG \
	--log-level DEBUG --log-prefix "IPT FORWARD packet died: "
	
	# 4.1.6 OUTPUT chain
	# Bad TCP packets we don't want.
	$IPTABLES -A OUTPUT -p tcp -j bad_tcp_packets
	
	# Special OUTPUT rules to decide which IP's to allow.
	$IPTABLES -A OUTPUT -p ALL -s $LO_IP -j ACCEPT
	$IPTABLES -A OUTPUT -p ALL -s $LAN_IP -j ACCEPT
	# 20050115, ASB, for dad's laptop
	$IPTABLES -A OUTPUT -p ALL -s 192.168.1.1 -j ACCEPT
	$IPTABLES -A OUTPUT -p ALL -s $INET_IP -j ACCEPT
	
	# Log weird packets that don't match the above.
	$IPTABLES -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG \
	--log-level DEBUG --log-prefix "IPT OUTPUT packet died: "
	
	# Enable simple IP FORwarding and Network Address Translation
	$IPTABLES -t nat -A POSTROUTING -o $INET_IFACE -j SNAT --to-source $INET_IP

	setPorts

	# enable forwarding after all rules are setup
	echo "1" > /proc/sys/net/ipv4/ip_forward
}

case "$1" in
	'start')
		start
		;;
	'stop')
		flush
		;;
	'restart')
		flush
		start
		;;
	*)
		echo "Usage: $0 start|stop|restart"
esac

# EOF
#vim:ts=2:sw=2
