IPFW strange behavior

Hello!

Can anyone please explain to me what I'm doing wrong?

I needed to set up a content control and banner removal pack, and I ended up with Squid+SquidGuard, everything was fine at that moment. Then I noticed that if users change their browser to "No Proxy", they'll be able to bypass and browse whatever they want.

The solution appeared: setup IPFW to forward all WWW traffic to Squid using the 'fwd' option, which needed to compile and install a custom kernel. After installing the new kernel the internal LAN lost ability to pass to the default gateway.

Code:
[LAN PC]---------[em1_____SERVER_____em0]---------------[default_router]
192.168.2.3/24   192.168.2.1/24      192.168.1.198/24   192.168.1.1/24

New kernel options:
Code:
include		GENERIC
ident		MYKERNEL1
options		IPFIREWALL
options		IPFIREWALL_VERBOSE
options		IPFIREWALL_FORWARD
options		IPFIREWALL_VERBOSE_LIMIT=5
options		IPFIREWALL_DEFAULT_TO_ACCEPT
options		IPDIVERT

/etc/rc.conf:
Code:
ifconfig_em0="inet 192.168.1.198 netmask 255.255.255.0"
ifconfig_em1="inet 192.168.2.1 netmask 255.255.255.0"
defaultrouter="192.168.1.1"
sshd_enable="YES"
gateway_enable="YES"
firewall_enable="YES"
firewall_type="/etc/ipfw.conf"
firewall_nat_enable="YES"
firewall_nat_interface="em0"
natd_enable="YES"
natd_interface="em0"
natd_flags="-dynamic -m"
squid_enable="YES"
/etc/ipfw.conf is empty for now. The LAN PC can ping both em1 and em0, but cannot reach default_gateway (Request timed out.). The server can ping anything successfully.

# ipfw -f flush doesn't change anything, and has
Code:
65535 allow ip from any to any
at the end of the list.

Any suggestions would be greatly appreciated. Thanks in advance.
 
your /etc/rc.ipfw is empty

With a "nat" ruleset you must use the default /etc/rc.firewall script because it contains default NAT rules, or write your own in ipfw.conf.

Change
Code:
firewall_type="/etc/ipfw.conf"
to
Code:
firewall_type="open"
then
# service ipfw restart

Or edit your own rc.ipfw and add the following lines:

Code:
if [ -z "${source_rc_confs_defined}" ]; then
if [ -r /etc/defaults/rc.conf ]; then
  . /etc/defaults/rc.conf
  source_rc_confs
elif [ -r /etc/rc.conf ]; then
  . /etc/rc.conf
fi

${fwcmd} add 50 divert natd ip4 from any to any via ${natd_interface}
 
First I got several comments:

  1. You do not need (anymore) to compile a custom kernel for ipfw, however, it doesn't harm either.
  2. You enabled the modern in kernel NAT as well as the old natd, you would need to decide for one.
  3. The flag for specifying the ipfw script is named firewall_script, and not firewall_type.
  4. The default router at 192.168.1.1 needs to have NAT enabled at its external interface too.
  5. On the NAT interface it is best to disable TSO.

Next, here come my recommendations for the modern in kernel NAT:

In your /etc/rc.conf remove all natd related flags and correct firewall_type to firewall_script. Specify the NAT interface within /etc/ipfw.conf.
Code:
ifconfig_em0="inet 192.168.1.198 netmask 255.255.255.0"
ifconfig_em1="inet 192.168.2.1 netmask 255.255.255.0 -tso"
defaultrouter="192.168.1.1"
sshd_enable="YES"
gateway_enable="YES"
firewall_enable="YES"
firewall_nat_enable="YES"
firewall_script="/etc/ipfw.conf"
squid_enable="YES"

In your /etc/ipfw.conf add the following:

Code:
#!/bin/sh
ipfw -q flush
ipfw -q nat 1 config if em1 reset

# Allow everything within the LAN
ipfw -q add 10 allow ip from any to any via em0
ipfw -q add 20 allow ip from any to any via lo0

ipfw -q add 90 deny ip from any to any not antispoof in

#replace this line with your customized actual ruleset

ipfw -q add 65534 allow ip from any to any

Now you have to decide, whether you are going to set up a stateful or a traditional firewall.

In the traditional case, you would #replace this line... with:

Code:
# traditional (no state) ruleset
# the actual allow/deny rules are only examples, adapt them to your specific requirements

ipfw -q add nat 1 ip from any to any via em1

# Rules for outgoing traffic - allow everything that is not explicitely denied
ipfw -q add 1000 deny ip from not me to any 25 via em1
ipfw -q add 1001 deny ip from any to any 5353 via em1

# Rules for incomming traffic - deny everything that is not explicitely allowed
ipfw -q add 5000 allow tcp from any to me 22,25,80,443,587 via em1

# Catch all other tcp/udp packets, but don't touch other packets, e.g. gre, esp, icmp
ipfw -q add 9998 deny tcp from any to any via em1
ipfw -q add 9999 deny udp from any to any via em1


In the stateful case, you would #replace this line... with:
Code:
# statful ruleset
# the actual allow/deny rules are only examples, adapt them to your specific requirements

ipfw -q add 100 nat 1 ip from any to any via em1 in
ipfw -q add 101 check-state

# Rules for outgoing traffic - allow everything that is not explicitely denied
ipfw -q add 1000 deny ip from not me to any 25 via em1 out
ipfw -q add 1001 deny ip from any to any 5353 via em1 out

# Allow all other outgoing connections
ipfw -q add 2000 skipto 10000 tcp from any to any via em1 out setup keep-state
ipfw -q add 2010 skipto 10000 udp from any to any via em1 out keep-state

# Rules for incomming traffic - deny everything that is not explicitely allowed
ipfw -q add 5000 allow tcp from any to me 22,25,80,443,587 via em1 in setup keep-state

# Catch all other tcp/udp packets, but don't touch other packets, e.g. gre, esp, icmp
ipfw -q add 9998 deny tcp from any to any via em1
ipfw -q add 9999 deny udp from any to any via em1

ipfw -q add 10000 nat 1 ip from any to any via em1 out

Note, that there are two NAT rules in the stateful case, one for incoming and one for outgoing traffic. Also in the stateful case, the packets may pass more than once the ruleset, so you need to allow this by setting the respective sysctl variable, so add in /etc/sysctl.conf:

Code:
net.inet.ip.fw.one_pass=0

And once you are there anyway, add another useful one:

Code:
net.inet.ip.fastforwarding=1
 
Back
Top