Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Oct 2003 12:50:21 -0700
From:      Wes Peters <wes@softweyr.com>
To:        Nick Rogness <nick@rogness.net>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Changing the NAT IP on demand?
Message-ID:  <200310071250.21692.wes@softweyr.com>
In-Reply-To: <20031005193343.F47183-100000@skywalker.rogness.net>
References:  <20031005193343.F47183-100000@skywalker.rogness.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sunday 05 October 2003 19:11, Nick Rogness wrote:
> On Sun, 5 Oct 2003, Wes Peters wrote:
> > On Sunday 05 October 2003 01:02 am, Nick Rogness wrote:
> > > On Sat, 4 Oct 2003, Leo Bicknell wrote:
> > > > I'm considering options for a new project, and I think I've
> > > > discovered what I think is the best idea, but I don't think
> > > > current software supports the config.  I'd like to get some
> > > > confirmation, and comments on if it would be hard to implement.
> > > >
> > > > Consider:
> > > >
> > > >
> > > > ISP #1-------\
> > > >               \
> > > >               FreeBSD Box----LAN
> > > >               /
> > > > ISP #2-------/
> > > >
> > > > In this case the LAN would be 1918 space, the two ISP's would
> > > > each provide a public IP for the FreeBSD box.
> > > >
> > > > Now, NAT would be required.  What I want to do is write an
> > > > external application to decide the performance of ISP #1 and
> > > > ISP#2, and somehow tell NAT which outside address to use.
> > > >
> > > > That, by itself, is not hard.  Here's the trick.  I want the
> > > > switch to be seamless.  That is, if NAT is translating to ISP
> > > > #1 and the application says switch to #2 the existing
> > > > translations to #1 (until they go away naturally) should be
> > > > kept, while new ones go to #2.
> > > >
> > > > The only ways I know to change the outside address seem to tear
> > > > down all existing connections.
> > > >
> > > > Is it possible to make this work today?  Would it be hard to
> > > > fix if it doesn't work today?
> > >
> > > 	This can simply not work without resetting connections.  The
> > > 	socket pair on the "outside" would break as your outside traffic
> > > 	switches from one to the other (src/dst would change).  There is
> > > 	no fix, as this breaks basic IP principals.
> >
> > That's not at all what Leo was asking.
>
> 	Sorry bout that, didn't read carefully enough.  I understand the
> 	question now after more careful reading.
>
> > Leo, you may be able to do this with ipfilter's ipnat.  Nat rules
> > are traditionally processed with 'ipnat -CF', the -C clears the
> > rules and the -F option clears the currently active NAT mappings. 
> > You should experiment with rewriting the rules and instantiating
> > them with -C only. This should leave the existing stateful mappings
> > to the formerly preferred interface while creating all new mappings
> > on the newly preferred interface.
>
> 	In addition to keeping your NAT translations (as suggested by
> 	Wes), you need to also keep routes for those entries as well, so
> 	that preserved traffic remains to route out the right ISP even if
> 	a switch occurs.

Ah, yes, another sticky bit of the problem.  It seems you could do a 
least a partial workaround by creating and maintaining a host route for 
each active NAT mapping.  The NAT engine would have to reference-count 
the routes it is maintaining.

This *is* a simpler alternative than hacking source routing into FreeBSD 
at this point.

> 	The reason for this is simple.
> 	When you switch the route(s) to the other ISP (which you would
> 	have to do), your existing translations would get routed out to
> 	the wrong ISP.  You would need to keep routes for existing
> 	translations to make sure they leave the proper 'old' interface.
> 	This would not be necessary if each ISP allowed you to use either
> 	public IP on each others network (not likely).
>
> 	Nat (AFAIK) does not determine which interface to leave.  You can

ipnat operates quite differently from natd; it bears looking into.  It's 
been a while since I was intimate with ipnat, so I can't say off the 
top of my head how hard this might be.

> 	change the source address in the packet to anything you want, this
> 	will not tell it to leave 'interace_to_ISP#1' or
> 	'interface_to_ISP#2'. That is a decision made using the routing
> 	table. 

ipnat redirections already have a limited sort of round-robin load 
balancing capability.  A quick read through ipnat(5) may enlighten.  It 
would be instructive to search out the round-robin code and think about 
how to extend it into a mechanism to do failover or smarter load 
balancing.

>       Your app would have to keep track of these NAT things and
> 	also add and remove routes from the routing table.

Nat mappings are already available, via the /dev/ipnat device and 
ioctl's, with ipnat.

> 	That is, if everything is going out ISP#1 and you decide to switch
> 	to ISP#2 you would need to:
>
> 		1) Keep exisiting NAT translation(s) like suggested by
> 		   Wes.
> 		2) Add routing table entry for each of the NAT
> 		   translations you want to preserve to ISP#1
> 		3) Switch default routing to ISP#2
> 		4) When sessions are finsihed and NAT translations
> 		   removed to ISP#1, the route(s) that pertain to those
> 		   NAT translations would need to be removed.

Yeah, conceptually it's pretty simple isn't it?  The devil is, as 
always, in the details. ;^)

-- 
         "Where am I, and what am I doing in this handbasket?"

Wes Peters                                              wes@softweyr.com




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