Firewalls / ipfw – protect your subnet

A firewall is
a good line of defense against external intruders. It can allow precisely what you want
and exclude everything you don’t want. I’m using ipfw which [I think] means
Internet Packet FireWall.

Deny everything. Accept nothing.

My first step was to try invoking the simple firewall by telneting to my box and
typing sh /etc/rc.firewall. That worked. But it also terminated my
telnet session! <grin> Then, from the console, I did sh
/etc/rc.firewall simple. That worked but it also stopped IRC from working.
It must be something in the rules.

The existing rules did not allow me to ping
other machines from my FreeBSD box. That’s because, by default, everything is
denied. That’s a good thing because it means you aren’t allowing things you don’t
want. It also means you must explicitly state what you do want.

Getting ping to work

I received the following message. This applied to local machines and to those in
the outside world.

ping: sendto: Permission denied

After some thought I noticed that I did not have the following rule:

$fwcmd add pass all from any to any

This allowed me to ping my local network. And the outside world. NOTE:
The above rule isn’t for long term use. I plan to explicitly allow things
rather than allow everything like that.

What is denying?

But I have bigger problems. I can access my local webserver via internal address
and by external address. But I cannot access an external website. I can access
my local POP3 server but not my ISP. Something in the rules is preventing this.
I think I must explicitly allow these things.

I tried removing some of the deny
rules, but that didn’t achieve anything. Here is the firewall rules you get if you
don’t specify which model you want:

00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 divert 8668 ip from any to any via ed0
65000 allow ip from any to any
65535 deny ip from any to any

The above rule set allows me me to do whatever I need to do. So these rules
within the simple rule set aren’t the problem. It must be the other rules.

Found!

I’ve done some testing. By removing rules one at a time and trying connections
to the outside world, I’ve found that the rules which prevent the connections.

Here are
the rules and the connections they prevented:

prevents Agent from connecting to my ISP’s news server.

$fwcmd add deny all from any to 192.168.0.0:255.255.0.0 via ${oif} out

prevents IRC connections from occurring.

$fwcmd add deny log tcp from any to any in via ${oif} setup

IRC

I spent some time talking to virus on Undernet #FreeBSD. He suggested I
add some rules to allow these two rules to allow IRC:

21 October 1998

$fwcmd add deny all from any to 192.168.0.0:255.255.0.0 via ${oif} out

I’m not sure what’s at fault. It’s either the rule or it’s ipfw.
I’m undecided. I’ve posted a message to the questions mailing
list.

I’ve also noticed that it takes much longer to connect via IRC with the simple firewall
model than with the open model. I have no idea why.

rc.firewall model

open

simple

time to connect via IRC

0:02

1:30

Something is definitely wrong somewhere. I’ll find out where.

ipfw version

I’ve discovered which version of ipfw I’m running (as taken from /usr/src/sbin/ipfw/ipfw.c)

* $Id: firewall.php,v 1.26 2007/08/27 16:34:46 dan Exp $

Speeding things up

In attempt at speeding up the connection time, I decided to remove some rules.
After a few tests, I found this rule was the culprit:

$fwcmd add deny log tcp from any to any in via ${oif} setup

This was the bottleneck. For whatever reason, this causes the connection time to
become unacceptable long. Without this rule, the connect time is < 2s. With
this rule, the time required to connect is > 1:30. Interesting! Perhaps I
need other rules before this in order to speed things up.

After some talk in #nz, I was told that I was probably blocking ident. So I added
the following two rules:

ipfw with DHCP etc (added on 8 August 2000)

If you’re trying to configure your firewall to work with DHCP or another dynamic
connection, then use this line in /etc/rc.firewall (ed. note: remember to
change ep0 as appropriate to your situation):

onet=`ifconfig ep0 |grep "inet " |awk '{print $6}'`

to replace:

onet=255.255.255.x

Also replace the entry for the ip address with:

oip=`onet=`ifconfig ep0 |grep "inet " |awk '{print $2}'`

This works because rc.firewall is a shell script, and using the backticks
runs the command within. Note that ifconfig ep0 gets all the information
on the specified network interface, grep gets the right line, and awk sucks in the right
field. (in this case, the netmask). I’d try this command at the command line before
putting it into rc.firewall though. 🙂

Also remember when you’re setting up your firewall to actually block things, (ie, not
"open") that the order of the firewall rules is very important, and that when
ipfw blocks internet requests, it logs the information in /var/log/security
(and sometimes /var/log/messages) complete with the rule number, which you can
look up in the output from "ipfw show," making it easy to find out why people
can’t get into your webserver. 🙂

(Hmmm… looking at this, I note that it you have multiple IP
addresses assigned to the NIC in question — of course, for this
application, no one would do that, I suppose…. Anyhow, things
could get Fairly Weird for someone who might try such a thing.)

Someone people consider the reject rule to be an acknowledgement that yes, the service exists, but not, I’m not going to deal with you. In this regard, from a security point of view, some consider deny better than reject.

I would suggest that you investigate the IP address(es) of your favorite IRC servers, then add rules to either REJECT (** or ALLOW), from those IP(s), then another broader rule, to DENY IDENT from any.

That way, you’d be able to connect to your favorite IRC server(s) quickly, while remaining as secure as possible (any nefarious IDENT requests, could go to hell).

As a sweet by-product of your diligence, this is also a little friendlier to your chosen IRC servers.

** You may want to ALLOW IDENT as some IRC servers won’t allow you to connect without a valid IDENT.