IPFW NAT and IPFW cannot get it to work

Hello,
I have followed the instructions in the handbook regarding NAT and IPFW but somewhere along the line I have made a mistake. Unfortunately I had it going but when I went to re-apply it upon a server rebuild NAT refuses to work.

I am using the following ruleset script for ipfw(8) on FreeBSD 10.2.
Code:
#!/bin/sh
# Flush out the list before we begin.

ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
pif="bge0"
skip="skipto 500"
ks="keep-state"
good_tcpo="22,25,37,53,80,443,110"

# Change xl0 to LAN NIC interface name
$cmd 00005 allow all from any to any via em0
# No restrictions on Loopback Interface
$cmd 00010 allow all from any to any via lo0

$cmd 00100 divert natd ip from any to any in via $pif # NAT any inbound packets
$cmd 00101 check-state

# Allow access to public DNS
# Replace x.x.x.x with the IP address of a public DNS server
# and repeat for each DNS server in /etc/resolv.conf
$cmd 00110 allow tcp from any to 122.150.6.70 53 out via $pif setup keep-state
$cmd 00111 allow udp from any to 122.150.6.70 53 out via $pif keep-state
$cmd 00112 allow tcp from any to 122.150.7.70 53 out via $pif setup keep-state
$cmd 00113 allow udp from any to 122.150.7.70 53 out via $pif keep-state

# Authorized outbound packets
$cmd 120 $skip udp from any to 10.0.0.1 53 out via $pif $ks
$cmd 121 $skip udp from any to 10.0.0.1 67 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks
# Allow outbound HTTP and HTTPS connections
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state
# Allow outbound email connections
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state
# Allow outbound ping
$cmd 00250 allow icmp from any to any out via $pif keep-state
# Allow outbound NTP
$cmd 00260 allow tcp from any to any 37 out via $pif setup keep-state
# Allow outbound SSH
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state
# deny and log all other outbound connections
$cmd 00299 deny log all from any to any out via $pif

$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif

# Deny public pings
$cmd 00310 deny icmp from any to any in via $pif
# Deny ident
$cmd 00315 deny tcp from any to any 113 in via $pif

#deny netbios
$cmd 00320 deny tcp from any to any 137 in via $pif
$cmd 00321 deny tcp from any to any 138 in via $pif
$cmd 00322 deny tcp from any to any 139 in via $pif
$cmd 00323 deny tcp from any to any 81 in via $pif

# Deny fragments
$cmd 00330 deny all from any to any frag in via $pif

# Deny ACK packets that did not match the dynamic rule table
$cmd 00332 deny tcp from any to any established in via $pif

# Allow traffic from ISP's DHCP server.
# Replace x.x.x.x with the same IP address used in rule 00120.
$cmd 00360 allow udp from any to 10.0.0.1 67 in via $pif keep-state

# Allow HTTP connections to internal web server
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Allow inbound SSH connections
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2
# Reject and log all other incoming connections

$cmd 499 deny log all from any to any
$cmd 500 divert natd ip from any to any out via $pif # skipto location for outbound stateful
$cmd 510 allow ip from any to any

10.0.0.1 - represents the ADSL modem that I have connected to the server via bge0. All NAT is done through em0 which represents the network segment 192.168.0.*.

Thanking you in advance,
Jonathan
 
I don't like to muck around with the kernel as a rule, I prefer loadable modules. This is the main reason I want to avoid pf.

And the weird thing is I had the thing going for quite sometime so there has to be a simple type-o or something in rc.conf or ipfw.rules. Which is a merge of the documentation in the handbook for ipfw and NAT.

talking about rc.conf files I forgot to include mine....
Code:
# firewall
firewall_enable="YES"
firewall_type="simple"
firewall_script="/etc/ipfw.rules"
firewall_logging="YES"

#NAT
gateway_enable="YES"
natd_enable="YES"
natd_interface="bge0"
natd_flags="-dynamic -m"

Any further input would be much appreciated.

Thanking you in advance,
Jonathan.
 
I don't like to muck around with the kernel as a rule, I prefer loadable modules. This is the main reason I want to avoid pf.

What are you basing this on? You don't have compile a custom kernel to use PF for the most common use cases. It's only if you want to use ALTQ and in that case you're better off looking at OpenBSD since they have much better system now for traffic prioritization.
 
Why are you using natd instead of IPFW kernel NAT?

As one that just made the move from natd to kernel NAT (and fully agree this is preferable) via IPFW, its probably due to the lack of documentation on how to set it up. The FreeBSD Handbook documents using natd as the way to do NAT.
 
For some reason you do not get a huge amount of help on the forums in regards to IPFW with NAT, I am not sure why yet.

This is a good example of using NAT with IPFW configured as default allow - https://forums.freebsd.org/threads/ipfw-nat-setting.46929/#post-262399

If you do not need to use IPFW, you should use PF, its extremely easy to setup NAT with.

If you need to use IPFW you should use kernel NAT and not NATd.

IPFW and NAT (whether in-kernel or via natd) is easy.

IPFW and NAT and stateful filtering is a royal pain in the arse to get working reliably. Especially if you need to double-NAT or have more than 2 interfaces. I generally avoid stateful filtering on our firewalls for this reason.

Just as getting dummynet bandwidth shaping to work with stateful filtering is a royal pain; and don't try to get those working with NAT unless you really want a long-term migraine. :)

Thus, while I have lots of experience using IPFW and NAT on FreeBSD (from 4.0 through to 9.3), and some experience with IPFW, NAT, and dummynet, I avoid commenting on threads that use stateful rules. :) My rule of thumb is to use stateful filtering or NAT, but not both at the same time.
 
This seems to work for stateful IPFW with NAT and default Deny. I have successfully used this with many jails on the same host without vimage. A proxy server is configured to accept all traffic on the NAT wan IP and forward it to the correct Jail.

Not quite happy that incoming and outgoing NAT are together, will probably try to change that when I have solved my second issue. My second issue is nginx proxy_pass from jail to jail (excluding the reverse proxy as it is aware of the local IPs) does not work properly. proxy_pass does not seem to work from jail (url1.example.com) to jail (url2.example.com). When proxy passing the traffic between the two jails gets mucked up and I start getting traffic from the NAT IP to the local jail ip on the lo1 interface. This wouldn't be a problem except that the outgoing traffic is treated like its a response, so the destination port is not 443 (its some high number) when in actual fact it needs to be a new connection from the jail which is proxy passing so the destination port is 443 (so the firewall will not block it). Not sure why this is occurring quite yet and if anyone has any ideas, I would be grateful. If you are not proxy passing between jails then you should be fine with the below rule set.

Code:
#!/bin/sh

# Configuration
wif="bce0" # WAN interface
jif="lo1" # Jail interface
jsn="10.0.0.0/16" # Jail subnet
pip="10.0.0.1" # Proxy IP

hip="aaa.bbb.ccc.ddd" # Host WAN IP
jip="www.xxx.yyy.zzz" # Jail WAN IP

# Script variables
cmd="ipfw -q add"
ks="keep-state"
sks="setup keep-state"

# Flush all rules
ipfw -q -f flush

# Enable NAT
ipfw nat 1 config ip $jip same_ports log redirect_port tcp $pip:443 443

$cmd 5 allow ip from any to any via lo0
$cmd 6 deny ip from any to not me in via $wif

$cmd 100 nat 1 log ip from any to $jip recv $wif
$cmd 101 check-state log

# Host
$cmd 110 allow icmp from any to $hip in via $wif $ks
$cmd 111 allow tcp from any to $hip 65222 in via $wif $sks
$cmd 112 allow icmp from $hip to any out via $wif $ks
$cmd 113 allow tcp from $hip to any 53, 80, 443, 22, 65222 out via $wif $sks
$cmd 114 allow udp from $hip to any 53, 123 out via $wif $ks
# NAT
$cmd 120 skipto 65510 log tcp from any to $jsn recv $wif $sks
$cmd 121 skipto 65510 log udp from any to $jsn recv $wif $ks
$cmd 122 skipto 65510 log tcp from $jsn to not $jsn xmit $wif $sks
$cmd 123 skipto 65510 log udp from $jsn to not $jsn xmit $wif $ks

# JAILS RULES 200-65000

# Block any further traffic
$cmd 65501 deny log ip from any to any

# Incoming/Outgoing NAT
$cmd 65510 nat 1 log ip from $jsn to any xmit $wif $ks
$cmd 65511 allow log ip from $jip to any xmit $wif $ks
$cmd 65512 allow log ip from any to $jsn recv $wif $ks
$cmd 65513 deny log ip from any to any
 
IPFW and NAT (whether in-kernel or via natd) is easy.

IPFW and NAT and stateful filtering is a royal pain in the arse to get working reliably. Especially if you need to double-NAT or have more than 2 interfaces. I generally avoid stateful filtering on our firewalls for this reason.

Just as getting dummynet bandwidth shaping to work with stateful filtering is a royal pain; and don't try to get those working with NAT unless you really want a long-term migraine. :)

Thus, while I have lots of experience using IPFW and NAT on FreeBSD (from 4.0 through to 9.3), and some experience with IPFW, NAT, and dummynet, I avoid commenting on threads that use stateful rules. :) My rule of thumb is to use stateful filtering or NAT, but not both at the same time.

phoenix

Can you please provide example of using stateless IPFW with built in NAT?
One for outgoing(any or 80,443) and one for incoming like http(s), or SSH.
 
Code:
#!/bin/sh

public_ip=<whatever>

private_net=<whatever>

server_ip=<whatever>

public_nic=<whatever>
private_nic=<whatever>

# Configure outgoing NAT
ipfw nat 8668 config same_ports ip $public_ip

# Configure incoming 1:1 NAT
ipfw nat 1234 config same_ports ip $public_ip redirect_addr $server_ip $public_ip

# Allow incoming connections
ipfw add nat 1234 tcp from any to $public_ip 22,80,443 in recv $public_nic
ipfw add allow tcp from any to $server_ip 22,80,443 out xmit $private_nic

ipfw add allow tcp from $server_ip 22,80,443 to any in recv $private_nic established
ipfw add nat 1234 tcp from $server_ip 22,80,443 to any out xmit $public_nic established

# Allow outgoing connections
ipfw add allow ip from $private_net to any in recv $private_nic
ipfw add nat 8668 ip from $private_net to any out xmit $public_nic

ipfw add nat 8668 ip from any to $public_ip in recv $public_nic
ipfw add allow ip from any to $private_net out xmit $private_nic

The NAT rule translates the packet and allows it through, all at once. You used to have to do two rules, one to NAT the packet, and a second one to allow the packet. Just make sure net.inet.ip.fw.one_pass=1 is set in /etc/sysctl.conf.

The number you use for the NAT instance doesn't matter. The default NAT "port" is 8668, from the natd days, but you can use any number you want. Just make sure you use the correct NAT number in the IPFW rules to match with the NAT instance you configure, so that it does what you want it to do.

The first "ipfw nat" call sets up the outgoing many-to-one NAT instance, using $public_ip for the NAT IP. This is a source NAT setup.

The second "ipfw nat" call sets up a 1:1 NAT instance for a specific server, using $public_ip and $server_ip for pre-/post-NAT IPs (it's a source NAT and a destination NAT in one).

Then the rules just allow traffic in one interface, and out the other interface in the firewall, doing NAT as needed depending on the direction and protocol.

Stateless rules are easy. :) But it doesn't provide as much protection as stafeful filtering does, and it requires more rules. But it's very easy to do.
 
Thanks phoenix, I installed PF as I am trying our sysutils/cbsd for managing jails/containers. NAT, redirection was becoming a headache.
I preferred IPFW as it is actively developed, PF is lagging behind OpenBSDs PF.
 
Back
Top