ipfw, nat and stateful firewall: why "keep-state" on "skipto" works at all and how do this properly?
Ian Smith
smithi at nimnet.asn.au
Fri Jan 30 10:50:20 UTC 2015
On Fri, 30 Jan 2015 12:05:07 +0300, Lev Serebryakov wrote:
> On 30.01.2015 05:33, Julian Elischer wrote:
>
> >> 12700 skipto 12900 ip from any to any keep-state 12800 deny ip
> >> from any to any 12900 nat 1 ip from any to any out 12999 allow ip
> >> from any to any
> >>
> >> And rules for inbound ones are:
> >>
> >> 11000 deny ip from any to not me 11500 nat 1 ip from any to any
> >> 11510 check-state 11600 allow tcp from any to me ssh,http setup
> >> keep-state 11999 deny ip from any to any
> > ok so the dynamic rule is created on the outgoing packet, and
> > associated with skipto 12900 which sets up a NAT session.
> >
> > on a later incoming packet, the rule 11500 is hit first so the
> > packets are NAT'd back, and then their state is compared to that
> > stored in the outgoing path, and if they match, they go to 12900
> > where they are not checked again becasue they are not 'out'
> > packets. so it falls through to 12999 and is allowed in. (in its
> > changed form). packets that are not in a known session fall through
> > teh check-state and are dropped.
> >
> > it all looks ok to me. kinda cute actually.
> Not cute at all for me, as 12900 needs "out" (it is already in "out"
> group of rules!) and incoming packet is jumped to outbound section :)
So, don't do it that way. I've also always found skipto .. keep-state
rules confusing, so I'll reinforce wishmaster's initial comment:
: At first, i think you should move keep-state from skipto to explicit
: allow rule.
Use skipto to distinguish inbound from outbound packets, on both/all of
inside and outside interfaces, then use keep-state in the appropriate
sections to avoid confusion.
> Other filtration is hypothetical now, but I don't like this "skip ->
> nat with additional "redundant" check -> allow" pattern.
Frankly the examples in the IPFW handbook section still suck, despite
some recent good work in cleaning up that document. I would suggest
basing a ruleset on one of those - probably 'simple' in this case - in
/etc/rc.firewall, adding whatever stateful rules you want there. I
failed in several attempts to get the newer kernel nat code used in
'client' and 'open' rulesets into 'simple', but it's straightforward.
Even then, I extend the _structure_ of that example to split inbound
from outbound flows as described below, rather than just nat everything.
> > I always do what is done here and separate inwards and outwards
> > packets for the external interface into two different sets of
> > rules (and another set for other interfaces).
> Yep, it is exactly what I do, these two groups of rules are not only
> rules, of course.
Something else I learned from Julian a long time ago regarding natd -
though it applies equally well to kernel nat:
"Don't waste natd's time with packets it doesn't care about".
You need to nat all inbound packets from the outside - well, those to
the $nat_if address anyway, if you have multiple IPs - but you only need
to nat outbound packets on the outside interface that have earlier been
accepted in from the inside interface from an internal address:
$fwadd skipto $NATIN ip4 from any to ${ext_ip} in recv ${ext_if}
[..]
$fwadd skipto $NATOUT ip4 from any to any out xmit $ext_if recv $int_if
[..]
$fwadd $NATIN divert natd ip4 from any to any in recv ${nat_if}
[..]
$fwadd $NATOUT divert natd ip4 from any to any out xmit ${nat_if}
Simply replacing 'divert natd' with 'nat N' of course.
If you can't follow your own ruleset a year later, it's just not clear
enough .. speaking from bitter experience :)
cheers, Ian
More information about the freebsd-net
mailing list