Question that has dogged me for a while.

Freddie Cash fjwcash at gmail.com
Thu May 4 16:58:56 UTC 2017


On Thu, May 4, 2017 at 9:22 AM, Karl Denninger <karl at denninger.net> wrote:

> Consider the following network configuration.
>
>
> Internet ------- Gateway/Firewall ---------- Inside network (including a
> web host)
>             70.16.10.1/28     192.168.0.0/24
>
> The address of the outside is FICTIONAL, by the way.
>
> For policy reasons I do NOT want the gateway machine to actually have
> the host on it.  There may be a number of things running on there but
> for the instant moment let's assume a standard pedestrian web host on
> port 80.
>
> I have DNS pointing at "webhost.domain" @ 70.16.10.1.
>
> I have NAT on the gateway (NAT internal to the kernel), and a "hole
> punch" in there with redirect_port tcp 192.168.1.1:80 70.16.10.1:80 as
> pat of the nat configuration statement.
>
> This works fine for anyone on the outside.  HOWEVER, anyone on the
> INTERNAL network cannot see the host.
>
> My NAT configuration looks like this:
>
> #
> # Now divert all inbound packets that should go through NAT. Since this
> is NAT
> # it can only match a packet that previously was NATted on the way out.
> #
>         ${fwcmd} add 6000 nat 100 ip4 from any to me recv ${oif}
> #
> # Check stateful rules; we want to go there directly if there is a match
> #
>         ${fwcmd} add 7000 check-state
> #
> # Now pick up all *outbound* packets that originated from an inside address
> # and put them through NAT.  We then have
> # a packet with a local source address and we can allow it to be sent.
> # Therefore, if the packet is outbound let it pass and be done with it.
> #
>         ${fwcmd} add 8000 nat 100 ip4 from 192.168.0.0/16 to any xmit
> ${oif}
> >>    ${fwcmd} add 8001 nat 100 ip4 from 192.168.0.0/16 to ${oip}
>         ${fwcmd} add 8009 deny log ip4 from 192.168.0.0/16 to any xmit
> ${oif}
>         ${fwcmd} add 8010 pass ip4 from ${onet} to any xmit ${oif}
>
> Without the ">>" line I get nothing; the packets get to the gateway and
> disappear.
>
> With the ">>" line I DO get the packets re-emitted on the internal
> interface HOWEVER there is no translation to the internal interface IP
> on the gateway box.  So what I see on the internal box is this:
>
> 11:19:16.369634 IP 192.168.10.40.60924 > 192.168.10.100.11443: Flags
> [S], seq 292171178, win 8192, options [mss 1460,nop,wscale
> 8,nop,nop,sackOK], length 0
> 11:19:16.369662 IP 192.168.10.100.11443 > 192.168.10.40.60924: Flags
> [S.], seq 3088872007, ack 292171179, win 65535, options [mss
> 1460,nop,wscale 6,sackOK,eol], length 0
>
> Which won't work because the internal box got and sent this:
>
> 11:19:16.369337 IP 192.168.10.40.60924 > 70.169.168.7.11443: Flags [S],
> seq 292171178, win 8192, options [mss 1460,nop,wscale 8,nop,nop,sackOK],
> length 0
> 11:19:16.369433 IP 192.168.10.40.60925 > 70.169.168.7.11443: Flags [S],
> seq 2666765817, win 8192, options [mss 1460,nop,wscale
> 8,nop,nop,sackOK], length 0
> >> 11:19:16.369502 IP 192.168.10.40.60924 > 192.168.10.100.11443: Flags
> [S], seq 292171178, win 8192, options [mss 1460,nop,wscale
> 8,nop,nop,sackOK], length 0
> >> 11:19:16.369511 IP 192.168.10.40.60925 > 192.168.10.100.11443: Flags
> [S], seq 2666765817, win 8192, options [mss 1460,nop,wscale
> 8,nop,nop,sackOK], length 0
>
> But since the gateway emitted the packet back on the wire *without*
> remapping the source address (to itself) it doesn't match on the client
> box 'cause there's no way back for it.
>
> There has to be a solution to this somewhere and I'm obviously missing
> it..... :)


​You need to do a double-NAT (or hairpin-NAT or whatever you want to call
it), where you first NAT the destination address on the incoming interface
which will initiate the routing decision for where to send the packet next,
then NAT the source address on the outgoing interface (which can be the
same interface) in order to get the return packets sent back to the correct
gateway.

Something along the lines of:

ipfw nat 100 blah blah blah <convert from 192.168.0.0/16 to 70.16.10.x>
ipfw nat 200 blah blah blah <convert from 70.16.10.1 to 192.168.1.1>

ipfw add nat 200 tcp from 192.168.0.0/16 to 70.16.10.1  80 in  recv <int>
ipfw add nat 100 tcp from 192.168.0.0/16 to 192.168.1.1 80 out xmit <int>

ipfw add nat 100 tcp from 192.168.1.1 80 to 70.16.10.x     in  recv <int>
ipfw add nat 200 tcp from 70.16.10.1  80 to 192.168.0.0/16 out xmit <int

​Note:  I've only ever done this with non-stateful rulesets.  Once you add
state keeping, NAT configuration becomes horribly, horribly complex with
IPFW.  Stateless rules are super easy, though.  :)
​

-- 
Freddie Cash
fjwcash at gmail.com


More information about the freebsd-ipfw mailing list