From owner-freebsd-ipfw Wed Oct 2 8: 7:25 2002 Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 5827537B401 for ; Wed, 2 Oct 2002 08:07:22 -0700 (PDT) Received: from mail.tcoip.com.br (erato.tco.net.br [200.220.254.10]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8665043E42 for ; Wed, 2 Oct 2002 08:07:20 -0700 (PDT) (envelope-from dcs@tcoip.com.br) Received: from tcoip.com.br ([10.0.2.6]) by mail.tcoip.com.br (8.11.6/8.11.6) with ESMTP id g92F6Nx18574; Wed, 2 Oct 2002 12:06:23 -0300 Message-ID: <3D9B0B6F.5020304@tcoip.com.br> Date: Wed, 02 Oct 2002 12:06:23 -0300 From: "Daniel C. Sobral" User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20020905 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Georg Graf Cc: freebsd-ipfw@FreeBSD.ORG Subject: Re: Natd plus statefull connections impossible? References: <20021002115143.GA54827@graf.priv.at> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Sender: owner-freebsd-ipfw@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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