Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Jan 2004 11:14:52 +0000
From:      Alex Zbyslaw <xfb52@dial.pipex.com>
To:        freebsd-questions@freebsd.org
Subject:   Re: ipfw/nated stateful rules example
Message-ID:  <400D0DAC.7080104@dial.pipex.com>
In-Reply-To: <20040119201738.B30318@fremont.bolingbroke.com>
References:  <MIEPLLIBMLEEABPDBIEGAEDEFFAA.fbsd_user@a1poweruser.com> <20040119201738.B30318@fremont.bolingbroke.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Ken Bolingbroke wrote:
> I just jumped in the middle here, so I may be out of context.
> 
> But, stateful rules don't play nice with NAT.

You're quite right, they don't play nice at all.

fbsd_user@a1poweruser.com wrote:
> I disagree with you that the /etc/rc.firewall is the best example.
> It's really a good example of stateless rules, & how to use
> scripting Symbolic substitution.

I found it OK for stateful rules, as long as you don't use natd!  I couldn't 
find any examples *anywhere* of how to get it to work.

So I posted on a newsgroup a while back and got a working idea (see below) and 
in the meantime came up with one of my own.  I found it really helpful to draw 
a little picture of the gateway machine and its interfaces and trace how 
packets went out including the natd in the middle.  When working with natd you 
really do have to consider packets that come in/out your *internal* network 
interface.  Without natd you can effectively ignore them (which all examples do).

Note that in a standard setup it's a little more complicated since packets 
that come in from the local network get nat'ed whereas packets originating 
from the gateway machine don't.  Anyway, here's my final message on the topic 
which contains two ways you might go.  I have extensively traced the packets 
on the second, less elegant solution and it really does work.


> Michael Sierchio wrote:
> 
>> Alex wrote:
>>
>>> The basic thrust of the problematic section is:
>>>
>>>   ipfw add divert natd all from any to any via external_interface
>>>   ipfw add pass udp from any to any ntp out xmit external_interface
>>>   ipfw add pass udp from any ntp to any ntp in recv external_interface
>>
>>
>>
>> Try this:
>>
>> # local rules for this gateway's traffic (hope DF is set for UDP)
>>     ipfw add allow udp from me to any out xmit $ext_if keep-state
>> # divert
>>     ipfw add divert natd ip from any to any via $ext_if
>> # this rule looks a bit strange here, but it's to allow the
>> # nat-ed packets outbound to leave.  If you're concerned about
>> # egress filtering from the gateway itself, add appropriate
>> # non-stateful allow rules
>>     ipfw add allow ip from me to any out xmit $ext_if
>>     ipfw add check-state
>>     ipfw add allow udp from any to any in recv $int_if keep_state
> 
> 
> Putting the keep-state on the internal ethernet is a neat solution, thanks. (It conflicts somewhat with some of the way my firewall is set up prior to the ntp/natd stuff, but I'm looking at rewriting that).
> 
> I did think of one more solution which works on the external interface only, but it's not as elegant.
> 
> # Check all inbound ntp calls
>     ipfw add skipto 20500 udp from any ntp to any in recv $ext_if
> # Checks all outbound ntp calls and (by dynamic rule) all inbound ntp calls
>     ipfw add skipto 20000 udp from any to any out xmit $ext_if keep-state
> 
> [ rest of firewall including natd go here ]
> 
> # Make sure we do not fall through into special rulesets
>     add deny log all from any to any
> 
> # Only get to these rules in two circumstances:
> # 1) Any outbound ntp packet which has been keep-state'ed
> # 2) Any inbound ntp packet which matched a dynamic rule
>     ipfw add 20000 divert natd all from any to any out xmit $ext_if
>     ipfw add allow udp from any ntp to any in recv $ext_if
>     ipfw add allow udp from any to any ntp out xmit $ext_if
>     ipfw add deny log all from any to any
> 
> # Only get here on an incoming ntp packet.  Need to see
> # if we want to accept it or not.  Check-state will
> # trigger dynamic rule and skipto 20000 on match
>     ipfw add 20500 divert natd all from any to any in recv ${ext_if}
>     ipfw add check-state
>     ipfw add deny log all from any to any

--Alex



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