The primary benefit of this scheme over NAT is that your client machines can interact with other IPv6 sites on the Internet in a completely native manner. Presuming you use 6to4 or have a connection to the 6bone or some other provider of real IPv6 connectivity, your experience with IPv6 sites will be native and pure. Your interaction with IPv4 sites will be simulated, but that's no different than having to hide behind NAT.
There are two pieces to the puzzle that you will need to set up. The first is the translation layer. FreeBSD (and probably other KAME derived IPv6 stacks) provides the faith/faithd system to translate IPv6 streams into IPv4 streams. But faith/faithd operate on one destination port at a time, sort of like a proxy. A much better solution is NATPT. NATPT is currently available for FreeBSD only in KAME snapshots, but it is pretty easy to extract the functionality from a snapshot and drop it into FreeBSD -stable or -current. here's how:
kame/freebsd4/sys/netinet/ip_input.c. Copy all of the
#ifdef NATPTchanges into your own kernel source. Do the same for
kame/kame/sys/netinet6/ip6_input.c. Make sure that all 3 of these files include
ip6_setpktaddrs. You can put the declaration and set-up of
sa6_dstand the call to
#ifdef HAVE_IP6_SETPKTADDRSblocks. This call is not present in stock FreeBSD.
netinet6directory in your kernel source.
conf/optionsin your kernel source. Add two lines that say
conf/filesand add an entry for each file that matches
sys/netinet6/natpt*.cwith the right side saying
optional ipv6 natpt.
option NATPTto your kernel configuration file.
NATPT initializedwhen it boots.
natptconfigfrom the kame snapshot.
In order for the clients to use these mechanism, you need to have DNS lookups for Internet sites return AAAA records instead of A records, and the IPv4 address has to be encapsulated in a prefix that will send it through your NATPT prefix. The piece that makes this possible is the Trick-Or-Treat Daemon (totd). There is a FreeBSD port for it here.
So with NATPT set up on your border machine and a totd set up as the DNS server for all your client machines, it becomes possible to do completely without IPv4, presuming your applications will run correctly that way.
That begs the question, however. How do you migrate all of your applications?
The answer is a technique called "Bump in the API". It is described here. A Windows implementation is here (note that Mozilla does not properly render the page, which means the download link doesn't show up. Either view the source or use IE).
Here's how it works: IPv4 applications typically use the sockets API. You call gethostbyname() (or any of a few other mechanisms) to get the IP address of the host to which you are connecting, then call socket(), specifying the address family you want to use, then you call connect() with the sockaddr of the thing to which you want to connect.
You can modify the behavior of all of these routines using LD_PRELOAD to load a library that replaces these calls in libc with routines that subtly change the behavior.
We first rewrite gethostbyname() so that it instead calls getaddrinfo(), which is the new-and-improved address-family-agnostic API for host name translation. The problem is that the data structures returned by getaddrinfo() have way too much data in them (IPv6 addresses are 4 times larger than IPv4 addresses, among other things) to pass them back to callers of gethostbyname(). So we will instead cache the results in a list and return a phony IPv4 address to the caller.
We then intercept connect(). connect() will (hopefully) be presenting us with the dummy IP addresses we generated in our phonied-up gethostbyname() call. We look up the previously cached results, create our own *replacement* socket using the cached data, connect with it, then use dup2 to replace the user's socket with the newly created one.
Having done this, we should be able to transparently deal with IPv4 or IPv6 remote hosts from IPv4-only applications. Because of LD_PRELOAD, we don't even require the source code to the applications we're "repairing".
This technique breaks if the program uses the IPv4 address other than simply as an end-point in connect(). For example, ftp clients in some circumstances send IP addresses through their command streams to do various things. IM clients that attempt to do peer-to-peer communication fail in similar ways.
But for the general client-server case, the technique has been shown to work reasonably well.
Check out this bit of source
If you have a slightly more modest goal in mind, there are some shortcuts you can take. If your goal is to allow IPv4 programs to communicate with IPv4 sites, but without having to configure IPv4 on your network, then you could simply change all PF_INET sockets into PF_INET6 sockets and change all sockaddr_in addresses into sockaddr6_in addresses with your NATPT prefix tacked on the front.
Your IPv4 applications will not be able to talk to IPv6 sites this way, but it does preserve their legacy functionality while still pushing IPv4 out to your enterprise's border router.
Here's an implementation of the shortcut library. You must set an environment variable NATPT_PREFIX to be the "host 0" address of your NATPT region (that is, the NATPT address for 0.0.0.0). For example, 3ffe:1200:301b:4444::.
P.s. Here's a trick for you... Add
fec0:0:0:ffff::1 as an alias on the machine
that is your DNS server and use
fec0:0:0:ffff::1 in the nameserver line on all
of your clients.
fec0:: is the 'site local' prefix and so long as your
routers all know where
fec0:0:0:ffff::1 is (you probably want to run
route6d -l on
that machine), that will always work, even if you change your prefix.
You can even have multiple machines announce
fec0:0:0:ffff::1 and RIP will make
sure that the requests always go to the closest one. Just make sure you
do NOT put link- or site-local addresses in your DNS zones - they won't
work outside of your organization (by definition). Read
more about this.