IPFW Is my IPFW NAT setup ok?

Hello everyone, over this weekend I spent some time by replacing my PFSense firewall with a FreeBSD IPFW one. Mostly because I wanted the flexibility that comes with FreeBSD and that I can install all kind of third party software on the same machine as it has plenty of available resources.

Anyway, getting IPFW to work has been a pain. I've spenth hours searching this forum for advice and tutorials, the FreeBSD mailing list and several blogs. There is a lot of confusing setups out there like if you should use natd() or IPFW-NAT.

Anyway I ended up with this configuration:

Code:
#!/bin/sh

#Quietly flush out rules
/sbin/ipfw -q -f flush

#Set command prefix (add "-q" option after development to turn on quiet mode)
cmd="/sbin/ipfw add"

# set outside and inside network interfaces
wan_if="em1"
lan_if="em2"
ipmi_if="em3"

/sbin/ipfw nat 1 config if $wan_if unreg_only \
  reset \
  redirect_port tcp 192.168.0.2:22 22

# Allow anything within the LAN - interface with heaviest traffic shall come first.
$cmd 10 allow ip from any to any via $lan_if
$cmd 20 allow ip from any to any via lo0
$cmd 30 allow ip from any to any via $ipmi_if

# Catch spoofing from outside.
$cmd 70 deny ip from any to any not antispoof in recv $wan_if

# you need this to be able to renew your DHCP lease from your ISP
$cmd 80 allow udp from 92.221.96.1 67 to any 68 in recv $wan_if

# allow dns to host
$cmd 82 allow udp from any to any dst-port 53 in setup keep-state
$cmd 83 allow udp from any to any dst-port 53 out setup keep-state
$cmd 88 allow tcp from any to any dst-port 53 in setup keep-state
$cmd 89 allow tcp from any to any dst-port 53 out setup keep-state

# NAT rule for incomming packets.
$cmd 100 nat 1 ip4 from any to any in recv $wan_if
$cmd 101 check-state

# Rules for outgoing traffic - allow everything that is not explicitely denied.
$cmd 1000 deny ip from not me to any 25,53 out xmit $wan_if
$cmd 1010 deny ip from any to any 5353 out xmit $wan_if
$cmd 1020 deny ip from any to any 1900,2195,2196,4488,5223,5350,5351 out xmit $wan_if

# Allow all other outgoing connections.
$cmd 2000 skipto 10000 tcp from any to any out xmit $wan_if setup keep-state
$cmd 2010 skipto 10000 udp from any to any out xmit $wan_if keep-state

# Rules for incomming traffic - deny everything that is not explicitely allowed.
$cmd 5020 allow udp from any to me in recv $wan_if frag

# Rules for allowing dial-in calls to services which are listening on a LAN interface behind the NAT
$cmd 6000 skipto 10000 tcp from any to any 22 in recv $wan_if setup keep-state

# Catch tcp/udp packets, but don't touch gre, esp, icmp traffic.
$cmd 9998 deny tcp from any to any via $wan_if
$cmd 9999 deny udp from any to any via $wan_if

# NAT rule for outgoing packets.
$cmd 10000 nat 1 ip4 from any to any out xmit $wan_if

# Allow anything else, just in case IPFW is not configured as open firewall.
$cmd 65534 allow ip from any to any

This seems to work well, I also changed net.inet.ip.fw.dyn_syn_lifetime from 20 to 300 as some connections would timout way too fast (Especially websockets). Even though every line is documented, I don't fully understand them, especially rule 5020 is confusing.

When you read these rules, are there anything unnecessary there? Am I missing something?
 
Are you really sure that rule number 80 is necessary? My DHCP client on the WAN interface is working without this.

Rule number 1020 was used in my setup for completely blocking any iServices communication of internal Mac and iOS clients to the servers of Apple. This is only useful if you got systems with Mac OS X > 10.7 and/or iOS clients in your LAN, AND if you don't want to use FaceTime, iMessage, and other services. I disabled rule 1020 in my setup for some time now, because I started to like using iMessage and FaceTime on my Mac.

Rule number 5020 serves in my setup for a special purpose only. The rational of it is, that UDP fragments don't get port numbers associated, and therefore won't trigger any port based allow rule, and without rule number 5020 would simply be blocked. This hit me during the setup of a IKEv2-VPN service for Windows clients. Windows frequently sends UDP fragments for establishing IKEv2-VPN and the connection failed without said rule. I assume, that you don't need this rule because you didn't even allow regular UDP connections to your router, so external clients won't come to unconditionally sending UDP fragments to your system.
 
I've never needed such rule as the rule 80 for DHCP (client) to work. It might have been an issue ten years ago or earlier when connections were slower and the reply packet containing the ok to use the lease might have arrived very late and the state created by the DHCP client had already expired. A very busy DHCP server might have also caused this.
 
Ok, I will try to remove those three rules. I do have a Mac and I'm fine with not sending anything to Apple, but it may be too much and I have friends who will hate this when they are over :P
 
I have a challenge here which I guess I can blame my firewall NAT configurations. I'm trying to use a service called ZeroTier. This service creates a virtual private network. Everything works fine if I join that virtual network from the firewall machine. But every NAT'ed client gets tunneled. I've read their fix NAT guidelines, but I have to admit I don't fully understand symmetric NAT vs full cone / port restricted cone.

I've tried to change my IPFW rules to be less restrictive, but without any results. Do anyone have any idea what could be wrong?

This is my current rules:
Code:
#!/bin/sh

#Quietly flush out rules
/sbin/ipfw -q -f flush

#Set command prefix (add "-q" option after development to turn on quiet mode)
cmd="/sbin/ipfw add"

# set outside and inside network interfaces
wan_if="em1"
lan_if="em2"

/sbin/ipfw nat 1 config if $wan_if same_ports \
  unreg_only  \
  reset \
  redirect_port tcp 192.0.0.10:2222 22

# Allow anything within the LAN - interface with heaviest traffic shall come first.
$cmd 10 allow ip from any to any via $lan_if
$cmd 20 allow ip from any to any via lo0
$cmd 30 allow ip from any to any via $ipmi_if

# Catch spoofing from outside.
$cmd 60 deny ip from any to any not antispoof in recv $wan_if
$cmd 64 deny ip from any to any 953 in recv $wan_if

# allow zerotier
#$cmd 72 allow udp from any to any dst-port 9993 in setup keep-state
#$cmd 73 allow udp from any to any dst-port 9993 out setup keep-state

# allow to host
$cmd 82 allow udp from any to any dst-port 53 in setup keep-state
$cmd 83 allow udp from any to any dst-port 53 out setup keep-state
$cmd 88 allow tcp from any to any dst-port 53 in setup keep-state
$cmd 89 allow tcp from any to any dst-port 53 out setup keep-state
$cmd 90 allow tcp from any to any dst-port 80 in setup keep-state
$cmd 92 allow tcp from any to any dst-port 443 in setup keep-state

# NAT rule for incomming packets.
$cmd 100 nat 1 ip4 from any to any in recv $wan_if
$cmd 101 check-state

# Rules for outgoing traffic - allow everything that is not explicitely denied.
$cmd 1000 deny ip from not me to any 25,53 out xmit $wan_if

# Allow all other outgoing connections.
$cmd 2000 skipto 10000 tcp from any to any out xmit $wan_if setup keep-state
$cmd 2010 skipto 10000 udp from any to any out xmit $wan_if keep-state

# Allow IP fragments to pass through
$cmd 5020 allow udp from any to me in recv $wan_if frag
$cmd 5800 pass all from any to any frag

# Catch tcp/udp packets, but don't touch gre, esp, icmp traffic.
#$cmd 9998 deny tcp from any to any via $wan_if
#$cmd 9999 deny udp from any to any via $wan_if

# NAT rule for outgoing packets.
$cmd 10000 nat 1 ip4 from any to any out xmit $wan_if

# Allow anything else, just in case IPFW is not configured as open firewall.
$cmd 65534 allow ip from any to any
 
... Everything works fine if I join that virtual network from the firewall machine. But every NAT'ed client gets tunneled. ...

I do not understand what "gets tunneled" means.

The ipfw(8) rules are evaluated in the order of the rule numbers, and once a rule matches packet all the following rules are ignored. My understanding is that ZeroTier works on UDP port 9993 and uses port 443 as the fallback port.

The matching rules for this are #72, #73 and #92. All these rules are evaluated before the NAT rule #100, and because of this incoming ZeroTier packets won't see the NAT and hence won't arrive on clients on the LAN behind the NAT.

Try the following:

1. delete rules #72 to #92
2. modify rule 1000 by removing port 53 from the list

After this all connections over UDP 9993 and TCP 443 to ZeroTier should work also from clients on the LAN.
 
I tried that, but that didn't work either. I tried this on my parents firewall, which is running PFSense. Everything out is allowed, but only port 22 in. Every NAT client could establish a high performance connection. What I mean with tunneling is that all the traffic with your ZeroTier network will pass through a proxy, very slow. A proper connection will make p2p measures and find the shortest route to another client. So if they're on the same LAN they will talk directly. This is really cool as my ISP has a really high performance network as I can get less than 1ms latency between my building and my parents building even when there is a couple of kilometers between our buildings.

I guess there is something really advanced NAT stuff that has to be configured. I think I will rather spend time and try setup a PF NAT, it may work instead of spending a lot more hours getting IPFW to work with this.
 
Back
Top