Date: Wed, 02 Oct 2002 12:06:23 -0300 From: "Daniel C. Sobral" <dcs@tcoip.com.br> To: Georg Graf <georg-ipfw@graf.priv.at> Cc: freebsd-ipfw@FreeBSD.ORG Subject: Re: Natd plus statefull connections impossible? Message-ID: <3D9B0B6F.5020304@tcoip.com.br> References: <20021002115143.GA54827@graf.priv.at>
next in thread | previous in thread | raw e-mail | index | archive | help
Georg Graf wrote:
>
[diet quote: I want to use nat and stateful firewall rules]
>
> Questions:
>
> a) is there a way to do the thing I want at all with ipfw?
> b) if no, is there a proof?
> c) Did I miss something obvious? (Maybe the intelligent use of skipto?)
> d) Did I miss something not so obvious?
For a long time, I also thought it was not possible. But, while working
on another firewall, and trying to understand how NAT interacted with
firewall rules (they were separated), it came to me that all rules
applied to the real addresses, never their translation. I then set out
to reproduce this in ipfw. Here is how.
Requirements:
1) If the packet is outgoing (ie, will be natted on it's way out), you
want the NAT to be the last thing done.
2) If the packet is incoming (ie, will be "un-natted" on it's way in),
you want the NAT to be the first thing done.
Now, the second requirement is easily accomplished. Just put the nat
rules at the beginning:
ipfw add divert natd ip from any to ${NAT_ADDRESSES} in via ${EXT_IF}
There. If a packet is arriving on the external interface to a natted
address, unnat it and be done with it.
Now, the reverse is much more difficult, because the first "accept" rule
will end processing. The secret, alas, is *also* adding it to the beginning.
First, the rule, then the explanation:
ipfw add divert natd ip from ${NATABLE_ADDRESSES} to any out via ${EXT_IF}
ipfw add allow ip from ${NAT_ADDRESSES} to any out via ${EXT_IF}
Well, what it does is easy to see. Nat anything outgoing that needs to
be natted, and then allow it to go out. More difficult to explain is why
this is ok (and when it isn't).
Thing is, a packet goes through ipfw rules two times. First, when
entering through and interface, and second when leaving through another
(or the same, as the case may be).
Remember that I proposed to have rules apply only to the _unnatted_
addresses, right? So, when the packet arrives on the firewall, it
by-passes the first rule because it's "in", not "out". The second rule
is by-passed for the very same reason.
Thus, the packet has to be allowed (or denied) by the normal firewall rules.
The second time around, though, the packet will be blissfully allowed to
go, the filtering having been done on the first time.
Now, what blind-spots may this introduce? First, you have to be sure you
don't have any rules that have to be done on the packet's way out. Mind
you, you still can have such rules for packets going to your internal
networks, or packets going out that do not get natted.
Second, one must never enable any feature that makes ipfw process the
rules only once. IIRC, there are ways to do that.
Third, and most importantly, this rule won't block any outgoing traffic
from the firewall itself, if the nat address is used by the firewall
itself (as is very common).
I have thought of two solutions for this third problem. First, and most
simple, but which goes agains the idea of having the NAT first thing, is
having the firewall own rules as first thing:
# Firewall rules
ipfw check-state
ipfw add allow tcp from me to any ssh setup keep-state out via ${EXT_IF}
ipfw add allow udp from me to any 53 keep-state out via ${EXT_IF}
ipfw add allow icmp from me to any out via ${EXT_IF}
ipfw add deny ip from me to any out via ${EXT_IF}
# Nat rules
...
# Main rules
ipfw check-state
So, what that does is allowing the firewall to do ssh, dns requests and
pings (well, more than pings, but let's not go there), denying anything
else, and only then doing the NAT, which will let *other* kinds of
traffic to go out using the firewall ip. The two check-states ought to
do the right thing. If they don't, then the deny in the first set must
be restricted to outgoing setup TCP packets only, and you'll have to
live with that.
The second alternative is placing the line that allows all outgoing
traffic out at the *end* of the rules, before the denies. This won't
work if you have denies alternated with allows.
I can think of a few other alternatives, but these are the best, IMHO.
So. There you have. The stateful rules will work, because they will
ALWAYS refer to the real address, not the translated one, no matter if
the packet is incoming or outgoing. And it *will* be stateful, because
the packets will have been allowed by the stateful rules when entering
the firewall, or they won't get the *chance* to go out. :-)
If anyone is willing to create an rc.firewall profile with stateful
rules *and* NAT, preferably based on one of the others, I'll see if I
can get it committed.
--
Daniel C. Sobral (8-DCS)
Gerencia de Operacoes
Divisao de Comunicacao de Dados
Coordenacao de Seguranca
TCO
Fones: 55-61-313-7654/Cel: 55-61-9618-0904
E-mail: Daniel.Capo@tco.net.br
Daniel.Sobral@tcoip.com.br
dcs@tcoip.com.br
Outros:
dcs@newsguy.com
dcs@freebsd.org
capo@notorious.bsdconspiracy.net
Mundus vult decipi decipiatur ergo.
-- Xaviera Hollander
[The world wants to be cheated, so cheat.]
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ipfw" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3D9B0B6F.5020304>
