Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 Jun 2004 02:59:09 +1000
From:      Tony Frank <tfrank@optushome.com.au>
To:        OpenMacNews <freebsd-ipfw.20.openmacews@spamgourmet.com>
Cc:        freebsd-ipfw <freebsd-ipfw@freebsd.org>
Subject:   Re: any ipfw + nat gurus out there?
Message-ID:  <20040605165909.GA62366@marvin.home.local>
In-Reply-To: <39F4B5716A612AA12BB2BCEA@[172.30.11.6]>
References:  <183AEFC8C407F14A0032B498@[172.30.11.6]> <20040604122113.GA51783@marvin.home.local> <39F4B5716A612AA12BB2BCEA@[172.30.11.6]>

next in thread | previous in thread | raw e-mail | index | archive | help
Hi richard,

On Fri, Jun 04, 2004 at 09:53:27AM -0700, OpenMacNews wrote:
> >>in the simple case of
> >Perhaps you are yet to realise this is perhaps not 'simple' ? :)
> Nope. No more 'yet'. Got it. Not necessarily simple.  People getting angry. 
> Loud-n-clear. In over my head. Stateful? ... no flippin idea!   ;-)
> Still, it *should* be ...

Well, I will agree that you are making things overly complex. :)

> great. i'll regurgitate/postulate in order ...
> first, the basics
> 
> initialize the variables:
> 
>        fwcmd = "/sbin/ipfw"
>        exipA = "A.A.A.1"
>        exipB = "A.A.A.2"

Assumptions:
1. These addresses are static allocations to you from your ISP.
2. A.A.A.1 is primary address on your interface, A.A.A.2 is an alias.
3. ISP will route traffic for both A.A.A.1 and A.A.A.2 to you, and you 
will receive the traffic for both IP on your external interface.
4. You are using 4-STABLE or similar 4.x release (4.9 / 4.10)
The answers likely will work equally well on a 5.x release but I have
not tested/tried it.
5. External interface is fxp0, internal interface is fxp1
6. Everything is ethernet based and no extra ppp/gif/whatever is in use.

After configuring, your firewall interfaces will look something like this
in ifconfig(8) output:

fxp0: flags=18843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet A.A.A.1 netmask 0xffffff00 broadcast A.A.A.255
        inet A.A.A.2 netmask 0xffffffff broadcast A.A.A.2
        ether aa:bb:cc:dd:ee:ff
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
fxp1: flags=18843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet 10.0.0.B netmask 0xffffff00 broadcast 10.0.0.255
        ether aa:bb:cc:dd:ee:ff
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000


>        inip = "10.0.0.B"
>        gateway = "R.R.R.R"
> 
>        natd_portA_in=  "8668"
>        natd_portA_out= "8669"
>        natd_portB_in=  "8670"
>        natd_portB_out= "8671"

I believe you have three too many natd ports there.

See below.

> 
> the 'usual' start & finish rules ...
> 
>   # allow localhost traffic
>       ${fwcmd} add 100 allow all from 127.0.0.1 to 127.0.0.1
>   # deny everything else
>        ${fwcmd} add 65000 pass deny from any to any

I'm not sure where you get those as 'usual' ?
In my experience usual loopback rules (from /etc/rc.firewall) are:

00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any

Also your final rule will not work with both pass + deny, I assume 
this is just a typo.
I will make another assumption here that you mean allow all default rule.

65000 allow ip from any to any

> >1. Get the workstation to anywhere case working using the aaa1 address.
> >Standard rc.firewall examples should get you going with regular natd.
> 
> ok, but since my not-so-simple example has TWO external IPs (exipA=A.A.A.1 
> & exipB=A.A.A.2) that will BOTH be sending & receiving IP traffic, I'll set 
> up TWO natd instances, one running on EACH external IP.

I am sorry, but you are jumping ahead too far too quickly.

I strongly recommend learning to crawl before trying to run.

Step 1 is to get basic functionality working in a 'standard' setup with
just a single IP address in use.
Walk before running, crawl before walking... etc.
I will now proceed through each of the steps with a more detailed config
that should be sufficient to achieve each part.
If you cannot match my results for each step, fix the problem before
attempting to proceed.

To achieve step 1 a very simple config should suffice.

IPFW rules will be:

00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
01000 divert 8668 ip from any to any via fxp0
65000 allow ip from any to any

natd can be started:
/sbin/natd -n fxp0 

or the /etc/rc.conf lines on your 'firewall' would be:
ifconfig_fxp0="inet a.a.a.1 netmask 255.255.255.0"
ifconfig_fxp0_alias0="inet a.a.a.2 netmask 255.255.255.255"
ifconfig_fxp1="inet 10.0.0.B netmask 255.255.255.0"
defaultrouter="R.R.R.R"
gateway_enable="YES"
firewall_enable="YES"
firewall_type="OPEN"
natd_enable="YES"
natd_interface="fxp0"
etc

/etc/rc.conf on 'workstation' would be:
ifconfig_fxp0="inet 10.0.0.C netmask 255.255.255.0"
defaultrouter="10.0.0.B"
gateway_enable="NO"
firewall_enable="YES"
firewall_type="CLIENT"
natd_enable="NO"
sshd_enable="YES"
etc

Result should be that anything you route to the internet from internal
network will be modified by natd in transit to appear to originate from
A.A.A.1.
Return traffic that matches natd tables will have their destination updated
to match the original source.

You can test this with a ping (or ssh) from workstation to c.c.c.1 etc.

If you run natd with the verbose (-v) flag, you should get output to prove
this, like so:

Out [ICMP] [ICMP] 10.0.0.C -> C.C.C.1 8(0) aliased to
           [ICMP] a.a.a.1 -> C.C.C.1 8(0)
In  [ICMP] [ICMP] C.C.C.1 -> a.a.a.1 0(0) aliased to
           [ICMP] C.C.C.1 -> 10.0.0.C 0(0)
etc

> >2. Get the ccc1 to workstation working through aaa1.
> >3. Get the ccc2 to workstation working through aaa2.
> 
> >NATD port forward is obvious solution to me here.
> >To restrict this port-forward to the flow ccc1 to aaa1:22 use an ipfw rule 
> >prior to the natd divert.
> >
> >Again, NATD port-forward should do the trick.
> >Another ipfw rule to only permit ccc2 to aaa2:22 before natd should do it.
> 
> this has me confused ... should this not be done with the
> 
>       -redirect_port tcp ${WORKSTATION}:22 22
> 
> natd config option?  my understanding of this is "any/all traffic to this 
> NATd instance's alias_address, port 22 is forwarded to WORKSTATION:22".

Yes, this is correct.
To move from step 1 to step 2 all that should be needed is an expansion of
the natd parameters, ie the -redirect_port parameter.

/sbin/natd -n fxp0 -redirect_port tcp workstation:22 A.A.A.1:22

Now any tcp connection to port 22 on A.A.A.1 will be redirected by natd to
workstation.
This redirection will be done for any remote IP address at the moment.
Verify this by attempting to connect from c.c.c.1 to a.a.a.1:22.
It should work.
If you run natd with verbose flag (-v) you should see something like:

In  [TCP]  [TCP] C.C.C.1:1234 -> a.a.a.1:22 aliased to
           [TCP] C.C.C.1:1234 -> 10.0.0.C:22
Out [TCP]  [TCP] 10.0.0.C:22 -> C.C.C.1:1234 aliased to
           [TCP] a.a.a.1:22 -> C.C.C.1:1234
etc

Moving from step 2 to step 3, we add another redirect_port parameter to
natd config.
ie:

/sbin/natd -n fxp0 -redirect_port tcp workstation:22 A.A.A.1:22 -redirect_port tcp workstation:22 A.A.A.2:22

Now any tcp connection to port 22 on A.A.A.1 or A.A.A.2 will be redirected 
by natd to workstation.
Return traffic will be modified as appropriate, ie either a.a.a.1 or a.a.a.2
will be used depending on where the traffic was originally destined.
Outgoing connections initiated from workstation still all use a.a.a.1 as 
the public address.

> i.e.,
> 
>        /usr/sbin/natd \
>        -alias_address ${exipA} \
>        -in_port ${natd_portA_in} \
>        -out_port ${natd_portA_out} \
>        -dynamic -use_sockets -same_ports -unregistered_only -log 
>        -log_denied \
>        -redirect_port tcp ${WORKSTATION}:22 22
> 
>        /usr/sbin/natd \
>        -alias_address ${exipB} \
>        -in_port ${natd_portB_in} \
>        -out_port ${natd_portB_out} \
>        -dynamic -use_sockets -same_ports -unregistered_only -log 
>        -log_denied \
>        -redirect_port tcp ${WORKSTATION}:22 22
> 
> am i misusing this?  specifically, i'm not sure what your reasoning/intent 
> is with the "use an ipfw rule PRIOR to the natd divert" instruction.

Misusing this - yes, I think so.  You dont need two natd, and personally
I've never need to use the in_port / out_port options.

[... snip ...]

> where the intent of each is:
> 
>       (a) all OUTBOUND traffic via the firewall's internal-LAN-ip (inip) & 
>       the External NIC (exif) specifically to C.C.C.2:22 **MUST** travel 
>       OUT via exipB=A.A.A.2, i.e., the SECOND NATD instance, above
>       (b) all **OTHER** OUTBOUND traffic via inip **MUST** travel OUT via 
>       exipA=A.A.A.1, i.e., the FIRST NATD instance
>       (c) all INBOUND traffic coming into the (exif) & addressed to 
>       exipA=A.A.A.1 gets diverted to the 1st NATd instance
>       (d) all INBOUND traffic coming into the (exif) & addressed to 
>       exipB=A.A.A.2 gets diverted to the 2st NATd instance

Ok, with the setup I have described so far, step 1 achieves point b.
step 2 gets you item c, and step 3 gets you item d.
Obviously not exactly (ie my description does not use multiple natd etc)
but I think the final intent is acheived if I understand your goals 
correctly.

All that is left then is to ensure that any outgoing traffic initiated by
your internal network is translated to a.a.a.2 rather than a.a.a.1.
This is where things become a little more complex, hence my original question.
With the setup described above in step 3, any tcp connection originating from 
c.c.c.2 destined to a.a.a.2:22 will be redirected to workstation:22.
Any return traffic as a result of this connection will automatically be 
corrected in the outbound direction to use a.a.a.2 IP address.

You can add security with extra ipfw rules to ensure only specific traffic
flows are permitted and the rest are denied, eg only allow ccc1 to aaa1 and
ccc2 to aaa2 etc.

If I understand correctly, in addition to the above, you want to ensure that 
any outgoing connection initiated from workstation to c.c.c.2:22 uses a.a.a.2.  

This is where things are tricky/complex and may well require multiple natd
instances.

I would first question whether this cannot be achieved with a simpler approach?
Eg you could perhaps use the natd option redirect_address and define two 
internal ip for workstation - one for use with ccc1 and the other for use with 
ccc2.
A single natd process should then suffice and translate all traffic as needed.

I started experimenting with a multiple natd setup and it quickly becomes very 
complex.  If you add ipfw state-checking on top you then have ipfw keeping state
plus natd keeping state.
I might keep going tomorrow on this one if I get bored; but if a working
configuration makes it out alive, it will not be pretty and I suspect it will 
be a nightmare to maintain.

Hope the above helps,

Tony



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