Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Jun 2011 17:56:09 +1000 (EST)
From:      Ian Smith <smithi@nimnet.asn.au>
To:        umage <theultramage@gmail.com>
Cc:        freebsd-questions@freebsd.org
Subject:   Re: ipfw nat inbound keep-state with net.inet.ip.fw.one_pass=0
Message-ID:  <20110624004909.F34951@sola.nimnet.asn.au>
In-Reply-To: <4E032C1A.9000707@gmail.com>
References:  <20110621223335.2C145106579B@hub.freebsd.org> <20110623205741.K34951@sola.nimnet.asn.au> <4E032C1A.9000707@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 23 Jun 2011, umage wrote:

 > Some points:
 > 1) I did use the handbook as reference, and my ruleset mimics the layout used
 > there.

Excuse the late response, I've been away.  The best reference, apart 
from ipfw(8), is /etc/rc.firewall.  'Nuff said.

 > 2) Handbook uses divert natd, which I used until I switched to the kernel nat
 > approach.

Assuming that was working, is changing to ipfw nat the only difference?  
Or is that when you added fwd to the mix?  Is 192.168.0.55 another box 
on the LAN, or an IP alias on this box?  What says 'netstat -finet -rn'?
Is this on FreeBSD 8.x?

 > 3) I did not find any concrete examples of ipfw nat rule usage, so I'm using
 > them the old natd way.

Apart from the 'NAT, REDIRECT AND LSNAT' section in ipfw(8), natd(8) is 
still useful as fuller reference, given a few less, renamed parameters.  
As mentioned in that section, libalias(3) gives detail of all functions.

 > I did some more experiments, and noticed that for example, an inbound
 > connection can still communicate both ways after the initial state table rule
 > expires (20 seconds for some reason).

ipfw(8) 'SYSCTL VARIABLES' covers timeouts (sysctl net.inet.ip.fw.dyn_*) 
20 seconds suggests a SYN timeout, so a TCP connection - but see below.

Perhaps that 'works' because you're not denying established connections 
and using only 'setup' on keep-state rules, again assuming TCP protocol?

 > If they communicate while the state
 > entry is alive, the timeout resets, but it seems like it doesn't matter at
 > all. This leads me to believe that 'ipfw nat' keeps an internal state table,
 > which cannot be viewed, but is checked when doing check-state. Or
 > something... which I have no way of knowing.

NAT aliasing tables are entirely distinct from ipfw dynamic rule state 
tables.  Try adding 'log' (and maybe same_ports) to ipfw nat parameters 
at least while debugging connections.  That log, 'ipfw -ted show' and 
a tcpdump on each interface should show exactly what's going on.

'ipfw nat 1 show config'.

 > Here's a pruned version of the ruleset I used. Rule 600 is the one that adds
 > that remote <--> local state table entry that messes everything up. If I omit
 > keep-state on it, then traffic from the local side will be the one creating
 > the states when replying, with a 5-second timeout.

sysctl net.inet.ip.fw.dyn_udp_lifetime is 5 seconds by default.  So now 
we're talking UDP?  Please be more specific, or best, cut&paste results.

 > --------------------
 > $fw add 100 allow all from any to any via $lan_if

This passes all packets coming in from the LAN, bound for anywhere - ie 
this box OR the outside - but before/without performing NAT - as well as 
passing packets being transmitted to the LAN, whether locally generated 
or routed after having been NAT'd on inbound pass.  Not what you wanted.

You mentioned packets mistakenly reaching the outside with 192.168.* 
source addresses, that'll be this rule.  Try specifying 'in recv $if' 
and 'out xmit $if' avoiding 'via' when it's ambiguous, especially on 
outbound packets where 'via $if' is also true when they've come _in_ on 
that specified interface.  You need to do outbound NAT first anyway.

 > $fw nat 1 config if $wan_if redirect_port 192.168.0.55:12345 12345
 > $fw add 200 nat 1 ip4 from any to any in via $wan_if

Ok, you're doing inbound NAT before checking state, however you've not 
specified protocol (tcp or udp) with redirect_port.  I can't find any 
example in ipfw(8), natd(8) or libalias(3) where proto is optional, but 
I haven't read the code or tried this myself.  We can't tell from this 
(or rule 600) whether your port '12345' is TCP or UDP.

 > $fw add 300 check-state

At this point any packet, in or out, matching dynamic state tables will 
execute the action of the matching keep-state rule.  For packets going 
out to the WAN the action is a skipto, so all ip4 packets matching that 
flow will execute the 'skipto 800', where you NAT the outbound packets, 
and allow the corresponding return packets.

 > $fw add 400 skipto 800 ip4 from any to any out via $wan_if keep-state

Again, 'out via $wan_if' is ambiguous, and includes packets _received_ 
on $wan_if and now being transmitted to the inside, again before NAT.  
Specify 'out xmit' if you only want to apply this to packets being sent 
out to $wan_if, as I think you do; these are the only ones you want to 
perform NAT on anyway.

 > $fw add 500 allow all from any to any out keep-state

Ok, only inbound packets get to here, and they've already been NAT'd ..

 > $fw add 600 allow all from any to any dst-port 12345 in keep-state
 > $fw add 700 deny all from any to any in

While 'all | ip' will work for tcp or udp packets, better to specify the 
protocol targetted.

Ok, not only outbound packets get here, but also the return packets 
coming in with matching state, from the skipto.

 > $fw add 800 nat 1 ip4 from any to any out
 > $fw add 900 allow all from any to any

Bottom line is you need to do NAT on packets outbound to $wan_if before 
encountering the first check-state or keep-state rule, as you have for 
packets inbound from the WAN.  Then your dynamic rules will be matching 
packets with addressing between inside IPs and external hosts.

I strongly suggest following the flow pattern of the 'simple' ruleset in 
/etc/rc.firewall especially regarding placement of NAT rules, never mind 
whether using natd or ipfw nat, rather than the poor Handbook examples.

Depending on what protocol port 12345 is, you may be better off using 
static rather than dynamic rules to handle it .. another area where that 
Handbook section is inappropriately deprecatory; rc.firewall uses both.

HTH, Ian

(but if not, try posting afresh but with more detail to freebsd-ipfw@)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20110624004909.F34951>