From owner-freebsd-questions@FreeBSD.ORG Sat Jun 25 07:56:12 2011 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D9E3B106566B for ; Sat, 25 Jun 2011 07:56:12 +0000 (UTC) (envelope-from smithi@nimnet.asn.au) Received: from sola.nimnet.asn.au (paqi.nimnet.asn.au [115.70.110.159]) by mx1.freebsd.org (Postfix) with ESMTP id 286618FC0C for ; Sat, 25 Jun 2011 07:56:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by sola.nimnet.asn.au (8.14.2/8.14.2) with ESMTP id p5P7u9ki052053; Sat, 25 Jun 2011 17:56:10 +1000 (EST) (envelope-from smithi@nimnet.asn.au) Date: Sat, 25 Jun 2011 17:56:09 +1000 (EST) From: Ian Smith To: umage In-Reply-To: <4E032C1A.9000707@gmail.com> Message-ID: <20110624004909.F34951@sola.nimnet.asn.au> References: <20110621223335.2C145106579B@hub.freebsd.org> <20110623205741.K34951@sola.nimnet.asn.au> <4E032C1A.9000707@gmail.com> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Cc: freebsd-questions@freebsd.org Subject: Re: ipfw nat inbound keep-state with net.inet.ip.fw.one_pass=0 X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Jun 2011 07:56:12 -0000 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@)