LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Security
User Name
Password
Linux - Security This forum is for all security related questions.
Questions, tips, system compromises, firewalls, etc. are all included here.

Notices

Reply
 
Search this Thread
Old 03-28-2009, 05:11 PM   #1
niels.horn
Senior Member
 
Registered: Mar 2007
Location: Rio de Janeiro - Brazil
Distribution: Slackware64-current
Posts: 1,004

Rep: Reputation: 89
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...
 
Old 03-29-2009, 06:46 AM   #2
unSpawn
Moderator
 
Registered: May 2001
Posts: 27,489
Blog Entries: 54

Rep: Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903
Looks pretty OK I think except most people put the sysctls in first. (On the topic of sysctls, check out if you have sane defaults for log_martians, accept_source_route and accept_redirects and network perf?) What you could add is a switch for enabling those logging rules you commented out as it may help with troubleshooting and it's always good to see what gets rejected anyway. If you enable logging you might want to -m limit --limit it. Filtering you could add: --state INVALID, ! --syn -m state --state NEW and --tcp-option (64|128), bogons, ICMP types you do not want to see (say quench, redirs), SYN flood. But as I said before, it looks pretty much like what you'd want to have. Good start definately.
 
Old 03-29-2009, 07:44 AM   #3
niels.horn
Senior Member
 
Registered: Mar 2007
Location: Rio de Janeiro - Brazil
Distribution: Slackware64-current
Posts: 1,004

Original Poster
Rep: Reputation: 89
OK, thanks for all the suggestions!
I will do some research on all of them and improve my script.

I commented out the lines that log the rejected packets because my log file was growing like crazy
I read about the 'limit' option so I will study that first.

If I encounter any problems I'll come back for more help.

<edit>
I was thinking of defining logging with a variable, like:
0 = log nothing (bad idea)
1 = log attacks only
2 = log attacks & illegal traffic attempts
3 = log everything rejected
</edit>

Last edited by niels.horn; 03-29-2009 at 08:00 AM. Reason: idea to define logging
 
Old 03-29-2009, 09:10 AM   #4
unSpawn
Moderator
 
Registered: May 2001
Posts: 27,489
Blog Entries: 54

Rep: Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903Reputation: 2903
Depends on how you look at it. Even if your log would go crazy, I mean you shouldn't read anyway but use something like Logwatch, fwlogwatch or another reporting tool to tally things for you, right? For me I try to filter things out in several chains: bogons ranges first, then invalid packets, then certain protocols, then certain ICMP traffic, then "trusted" networks and what remains gets filtered more specifically. That way the logs don't overflow while still retaining a good overview of what's going on. One nice thing about filtering is it can show you unexpected things. For instance I found that Firefox-3 (when you select an entry in the bookmarks thingie by single-mouse-clicking it) immediately sends a request to that URI. That isn't a flaw or disclosure problem itself but to say it's expected (or even remotely useful) would be pushing it...
 
Old 03-29-2009, 09:21 AM   #5
win32sux
Guru
 
Registered: Jul 2003
Location: Los Angeles
Distribution: Ubuntu
Posts: 9,870

Rep: Reputation: 371Reputation: 371Reputation: 371Reputation: 371
Quote:
Originally Posted by unSpawn View Post
I found that Firefox-3 (when you select an entry in the bookmarks thingie by single-mouse-clicking it) immediately sends a request to that URI. That isn't a flaw or disclosure problem itself but to say it's expected (or even remotely useful) would be pushing it...
I hadn't noticed this behavior before. What a weird feature. Yikes.
 
Old 03-29-2009, 09:38 AM   #6
niels.horn
Senior Member
 
Registered: Mar 2007
Location: Rio de Janeiro - Brazil
Distribution: Slackware64-current
Posts: 1,004

Original Poster
Rep: Reputation: 89
So many new things to learn...
I've been in the IT business for over 25 years and still feel like a newbie at times

I *was* checking the log manually, but had already found out it is not the way to do it. I actually started looking for a tool that could read the log for me and e-mail me / SMS me / wail a horn / whatever in case of trouble.

I still have a lot of learning to do - and having fun at doing so.
 
Old 04-04-2009, 01:17 PM   #7
CoffeeKing!!!
Member
 
Registered: Mar 2008
Posts: 117

Rep: Reputation: Disabled
Quote:
Originally Posted by niels.horn View Post
So many new things to learn...
I've been in the IT business for over 25 years and still feel like a newbie at times

I *was* checking the log manually, but had already found out it is not the way to do it. I actually started looking for a tool that could read the log for me and e-mail me / SMS me / wail a horn / whatever in case of trouble.

I still have a lot of learning to do - and having fun at doing so.
Have you found any programs that do what you stated above?
 
Old 04-04-2009, 02:32 PM   #8
niels.horn
Senior Member
 
Registered: Mar 2007
Location: Rio de Janeiro - Brazil
Distribution: Slackware64-current
Posts: 1,004

Original Poster
Rep: Reputation: 89
Quote:
Originally Posted by CoffeeKing!!! View Post
Have you found any programs that do what you stated above?
I am studying logwatch as I write this... I'll report back when I get things working
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Request for Comments on Linux article irfanhab General 8 12-12-2005 01:37 AM
Handy Runner - Request For Comments pcweirdo Programming 0 04-29-2005 03:36 AM
Comments request for "O'Reilly's Linux iptables Pocket Reference" carboncopy General 3 03-03-2005 09:24 PM
Request For Comments: E-mail security site chort Linux - Security 2 02-28-2004 04:43 PM
Bash, input validation: request for comments unSpawn Programming 3 07-25-2003 08:03 PM


All times are GMT -5. The time now is 06:25 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration