Contributed by jason on from the faith-is-not-just-a-two-legged-dog dept.
Reyk Floeter (reyk@) recently committed some changes to relayd(8) which add support for IPv6-to-IPv4 and IPv4-to-IPv6 translation. This makes it very easy to relay IPv6 traffic to an IPv4-only host behind an OpenBSD PF router and perform application-layer magic on the headers (e.g. HTTP X-Forwarded-For).
Reyk was kind enough to write up a summary of this new functionality and describe how he came to integrate the capabilities from faithd(8). Please continue on to read Reyk's blog entry.
The n2k8 network hackathon in Japan inspired me to do more work on IPv6; it might be the spirit of the KAME project or the IPv6-capable network cable that I bought in Tokio's Akihabara. And there is also an increasing demand in the real world - many governmental organizations are introducing IPv6 to their networks. Altogether I got interested and started doing a few minor IPv6 patches before I decided to make an experiment - run IPv6 or even IPv6-only in my internal networks.
First I needed a connection to the IPv6 internet. Since my ISP does not provide native v6 yet, I had to get a tunnel. I decided for a tunnel from the SixXS IPv6 Deployment & Tunnel Broker project because they're known for very reliable, good, and free tunnels. And they cooperate with various ISPs to provide many PoPs (Points of Presence) for the tunnel endpoints - my PoP is only 16ms and 8 IPv4 hops away.
After requesting the desired static tunnel at SixXS and configuring the gif(4) interface and pf(4) on my gateway I had the IPv6 connection running - but what to do next? Because I didn't have an IPv6 subnet yet, I decided to hook up an Unique Local Unicast network internally using a fd00::/64 prefix and to NAT it on the gateway to the tunnel IPv6 address. That might sound like a bad IPv4 habit but I found it kind of interesting that they introduced something like the good old private RFC1918 addresses for IPv6 with RFC4193 - wasn't IPv6 supposed to get global unicast IPs everywhere ;)?
The next thing was to connect some services to the IPv6 world: www, ssh, submission, and imaps. I requested a real IPv6 /48 network from SixXS but only attached it to the gateway itself and published a few AAAA DNS records. Because I didn't like to configure IPv6 in the DMZ - even if our httpd(8) finally supports IPv6 - I decided to cheat a little bit: relayd(8) is supposed to relay connections from A to B; it can also relay connections between IPv6 and IPv4. A relayd(8) on the gateway accepting IPv6 connections from the Internet to forward them to the local IPv4 services in the DMZ was doing the trick.
Actually I first had to fix a few bugs in relayd(8) regarding IPv6 support - binding to the IPv6 :: "any" address, IPv6 pf NAT lookups did not work in relayd(8), and the daemon did not support IPv6 scope IDs to listen on and forward to link local addresses.
But the IPv6-to-IPv4 configuration was still a little bit complicated because I had to add every single IPv6 address as an alias on the gateway and add an configuration block in relayd.conf(5) for all the translated services. There must have been a better solution to make it simplier and to magically relay the incoming IPv6 connections to the right IPv4 address with almost no configuration. The best solution was faith.
There is a daemon in our tree called faithd(8) from WIDE/KAME and Jun-ichiro "itojun" Hagino. The main purpose of faithd(8) is to be a dynamic IPv6-to-IPv4 relay by doing a clever trick: when faithd(8) receives TCPv6 traffic it will figure out the IPv4 destination by looking at the last 4 octets of the original IPv6 destination. For example, if the original IPv6 destination address is 2001:db8:7395:ffff::a01:101, the connection will be relayed to the IPv4 address 10.1.1.1 (a01:101). It can also be used to connect IPv6-only networks to the IPv4 worlds by embedding the complete IPv4 space in a simple /96 IPv6 network. itojun@ used it this way and he probably had the strongest faith in IPv6.
The problems with faithd(8) are that it depends on the faith(4) pseudo kernel-interface, it is not in the default GENERIC kernels, it does not support the reverse direction of IPv4-to-IPv6, and that it requires some legacy configuration with special sysctls, routes, and the faithd.conf(5) file. In contrast, relayd(8) could replace almost the complete faithd(8) functionality without the need for the faith interface, the special sysctls, and with some assistance of pf.
I implemented the dynamic IPv6-to-IPv4 mapping in relayd(8) and also added the reverse IPv4-to-IPv6 mapping. The former works exactly like the described approach in faithd(8), but the configuration is a little bit different and it needs a pf redirection to replace the faith(4) interface. The latter allows relayd(8) to accept IPv4 connections and to forward them to IPv6 destinations by setting the last 4 octets of a pre-configured IPv6 address-prefix to the 4 octets of the original IPv4 destination.
After getting more faith in relayd(8) I upgraded my own setup using the following 3 steps to connect my services to the IPv6 world:
But there is even more, what about connecting an IPv6-only system to network and using relayd(8) to provide access to the legacy IPv4 world? The configuration was also very simple:
- New AAAA DNS records using IPv6 addresses embedding the IPv4 addresses of the original A records in the last 4 octets. The following example embeds 208.77.188.166 as d04d:bca6 in the AAAA record:
$ host -t A www.my.example.com www.my.example.com has address 208.77.188.166 host -t AAAA www.my.example.com www.my.example.com has IPv6 address 2001:db8::ffff:64:d04d:bca6- Redirections in pf.conf(5) to pass incoming IPv6 traffic for the desired target addresses to relayd(8). There is a special case for HTTP in the following example that will be explained later:
rdr pass inet6 proto tcp toport { imaps ssh submission } \ -> ($ip6_if:0) port 8081 rdr pass inet6 proto tcp to port www \ -> ($ip6_if:0) port 8080 - A simple relay in relayd.conf(5) handling all the TCP connections that get redirected from pf. The new IPv6-to-IPv4 configuration is enabled by simply adding the keyword "inet" to the forwarding directive - it will tell relayd(8) to forward to an IPv4 destination no matter where the source is coming from:
I added a special case for HTTP to add a X-Forwarded-For header to the client's request to see the original IPv6 source address in the httpd(8) logs instead of the IPv4 address of the relaying gateway (the transparent relay mode does not work with two different address families). The Apache httpd(8) webserver can extract the client address from the X-Forwarded-For header by using a module like mod_extract_forwarded (unfortunately the 1.3 version of the module is not online anymore and nobody officially ported it to OpenBSD yet):tcp protocol tcpgeneric { tcp { backlog 128, nodelay, sack, socket buffer 131072 } } relay tcp6to4 { listen on :: port 8081 forward to nat lookup inet protocol tcpgeneric }http protocol httpgeneric { header append "$REMOTE_ADDR" to "X-Forwarded-For" header append "$SERVER_ADDR:$SERVER_PORT" to \ "X-Forwarded-By" header change "Connection" to "close" tcp { backlog 128, nodelay, sack, socket buffer 131072 } } relay http6to4 { listen on :: port 8080 forward to nat lookup inet protocol httpgeneric }
- A new configuration entry in pf.conf(5) redirecting the outgoing traffic from the internal network to the IPv4-mapped IPv6 subnet to relayd(8):
rdr pass on $int_if inet6 proto tcp to 2001:db8::ffff:64::/96 -> ($ip6_if:0) port 8081- No additional configuration in relayd.conf(5) - the existing tcpgeneric block above will already do the right thing.
- A special DNS proxy server that translates AAAA requests to IPv4-mapped IPv6 addresses if no native AAAA record is available. There is net/totd in the ports tree that does this trick. It can simply be used with a configuration like the following example (where the forwarders are the addresses of real DNS servers):
forwarder 192.168.1.1 port 53 forwarder 192.168.1.2 port 53 interfaces sis0 prefix 2001:db8::ffff:64:: retry 300- And the configuration on the client to become an IPv6-only host. This might vary on different client systems, I did the following on my laptop running OpenBSD:
Static non-local IPv4 entries in the hosts(5) file and in your finger memory should be removed, using a local DNS zone for the LAN services which allows to enter AAAA entries directly or to use the translation service by totd.
- I disabled IPv4 in the hostname.em0 file,
#dhcp NONE NONE NONE rtsol- changed the resolv.conf(5) DNS client configuration to use the IPv6 address of the totd proxy,
search lan.example.com nameserver fd00:172:23:61::1 lookup file bind- and added a rule to the local pf.conf(5) file to reject any IPv4 traffic. This is more like a workaround but it seems to fix an issue with several websites in Firefox where it tries to load something via IPv4 even if the IPv6 AAAA record is available. The "return" option tells pf to send a TCP RST instead of just dropping the IPv4 packets, this helps firefox to remember that it should really use IPv6.
# Gracefully reject any IPv4 attempts block return quick inetI finally got a useable IPv6-only setup with a few drawbacks: no access to UDPv4, no ICMP, no other IPv4 protocols like ESP. But this can easilly be ignored with enough faith in relayd(8)... In the future I will probably have to run an IPv4-to-IPv6 relay to connect the remaining legacy IPv4 hosts to a subset of the IPv6 internet after the global flag day of switching everything to the new protocol (hahaha) which is of course already possible with relayd(8):
relay tcp4to6 { listen on 127.0.0.1 port 8081 forward to nat lookup inet6 2001:db8::ffff:64:: } #EOT
I'd like to thank Reyk for all the time he spent putting together this blog entry. This is a very interesting re-use of functionality from an older IPv6 daemon. Please email us if you find creative uses for this feature, we'd love to hear about it.
(Comments are closed)
By jirib (89.176.154.98) on
By Anonymous Coward (76.117.79.177) on
but these improvements are very very welcome! thanks a lot!
Comments
By Anonymous Coward (70.173.52.51) on
>
> but these improvements are very very welcome! thanks a lot!
>
I'm sure diffs from you to improve wherever you feel it is lacking will be given due consideration.
By henning (80.86.183.226) on
crawl out from under your rock?
By De Ganseman Amaury (195.13.31.240) on
It's a nice solution for IPv4-only client to access IPv6 networks.
Comments
By Reyk Floeter (2a01:198:295:0:ffff:ffff:ffff:ffff) reyk@openbsd.org on http://team.vantronix.net/~reyk/
> It's a nice solution for IPv4-only client to access IPv6 networks.
Bump-In-The-Stack is weird (RFC 2767), the proposed network stack implementation is something that can be done in user space on a gateway (eg. with relayd) or in the kernel if we would support NAT-PT (protocol NAT). I don't like the idea of something new that magically snoops off packets between network stack and NIC driver... *shudder*. Shouldn't it be done by the OS's packet filter?
The only interesting section is the "Extension Name Resolver" which is the DNS service. Instead of using a fixed 4 to 6 mapping is looks up an AAAA IPv6 record and temporary assigns an IPv4 address for the IPV4-only client like a 32bit query Id. Maybe this could be done by patching the net/totd port, but I didn't think about the implications yet.
Comments
By Anonymous Coward (195.13.31.240) on
> The only interesting section is the "Extension Name Resolver" which is the DNS service. Instead of using a fixed 4 to 6 mapping is looks up an AAAA IPv6 record and temporary assigns an IPv4 address for the IPV4-only client like a 32bit query Id. Maybe this could be done by patching the net/totd port, but I didn't think about the implications yet.
>
Yes I'm ok with that (it's quite similar to BIS). But today there isn't any implementation for that (ipv4-only-->v6 world) but I think it's an important thing during the transition and ther's nothing.
Ok now there's a lot of dual stack (*BSD,Linux,vista,...) but there will be a lot of clients with older system and so IPv4 only.
By Seth (71.30.208.239) on
From RFC 4193, (section 3.1) isn't the Unique Local Unicast prefix supposed to be fc00::?
Maybe I'm missing something....
Comments
By Reyk Floeter (2a01:198:295:0:ffff:ffff:ffff:ffff) reyk@vantronix.net on http://team.vantronix.net/~reyk/
The 8th bit 'L' indicates that the prefix is locally assigned. In fact, it should always be fd00:: because "Set to 0 may be defined in the future".
By Lennie (2001:610:612:0:217:31ff:fe75:76a5) on
I mean you could use DHCPv6, but we didn't need it for the address, so why use it for the rest ?
I heared they are working on an extension to Router Solicitation to allow for it, but I've not seen any implementations.
I know there is avahi-daemon which implements zero-conf, but that also might not be what people want.
Or do we just set it to fe80::1%if statically everywhere ?
What do you think will be the new fancy way to configure a IPv6-only network ?
Because if can have automatic IPv6-configuration behind the firewall... why configure IPv4 on your desktop(s) ?
Comments
By Paul 'WEiRD' de Weerd (weerd) on http://www.weirdnet.nl/
>
> I mean you could use DHCPv6, but we didn't need it for the address, so why use it for the rest ?
Because the address came from router solicitation, further Dynamic Host Configuration can be done with DHCP. What's the problem with that ?
> Or do we just set it to fe80::1%if statically everywhere ?
Sounds like a very bad plan to me...
> What do you think will be the new fancy way to configure a IPv6-only network ?
DHCPv6 seems like a viable option, but we'll have to see what we get.
> Because if can have automatic IPv6-configuration behind the firewall... why configure IPv4 on your desktop(s) ?
That's the spirit ;)
Comments
By Anonymous Coward (2a01:348:108:155:216:41ff:fe53:6a45) on
> Sounds like a very bad plan to me...
Whatever happened to draft-ietf-ipv6-dns-discovery-07?
By Lennie (2001:610:612:0:230:1bff:fe46:a618) on
> >
> > I mean you could use DHCPv6, but we didn't need it for the address, so why use it for the rest ?
>
> Because the address came from router solicitation, further Dynamic Host Configuration can be done with DHCP. What's the problem with that ?
Well, it seems double to me.
You first have one protocol, then an other.
By Anonymous Coward (128.171.90.200) on http://ipv6experiment.com/
By Anonymous Coward (216.75.164.158) on
It sucks that Im going to have to use NetBSD for my ipv6 needs, I'd rather have OpenBSD, but really, is there any other better way of doing Ipv6 short of 6to4 with an ISP that only does IPv4, and an internet that is largely ipv4 based???
With Windows server 2008 & Vista being IPv6 primary stack machines, the time is now.
So, what am I missing?
What is better than 6to4 on a ipv4 internet connection??
Comments
By Paul 'WEiRD' de Weerd (weerd) on http://www.weirdnet.nl/openbsd/
>
> It sucks that Im going to have to use NetBSD for my ipv6 needs, I'd rather have OpenBSD, but really, is there any other better way of doing Ipv6 short of 6to4 with an ISP that only does IPv4, and an internet that is largely ipv4 based???
Ask your ISP to provide native IPv6. Get them to at least provide tunneling services until native IPv6 is available. Look into switching to a provider that does offer IPv6. Use a tunnel provider (such as http://www.sixxs.net/) until you have ISP provided IPv6.
> With Windows server 2008 & Vista being IPv6 primary stack machines, the time is now.
Yes, the time is now. Make your ISP aware of customer demand for IPv6. If you don't ask, they'll never switch. Ask, so that they are at least aware.
> So, what am I missing?
>
> What is better than 6to4 on a ipv4 internet connection??
Actually sending out IPv6 traffic to the world.
By Todd T. Fries (2001:240:58a:1:203:93ff:fed1:3670) todd@openbsd.org on http://todd.fries.net/
/etc/relayd.conf:
/etc/pf.conf:
With those lines, anything passing through pf on this system from an external system to port 80 will end up going through the remote v6 system as advertised.
This is fine if you are at an office with an IPv4 router with IPv6 connectivity and want to relay some IPv4 traffic over IPv6. However, if you are a single laptop wanting to relay some IPv4 traffic over IPv6, you'll need a slightly different scenario. The relayd.conf stays the same, but the pf.conf changes to this:
/etc/pf.confSuddenly you can access any IPv4 website from your laptop if you have an IPv6 only laptop and an IPv6 router running relayd to reverse the process. (Well, technically, IPv6 only is a stretch, since 127.0.0.1 is an IPv4 address on lo0, but no IPv4 on the wire, I guess is more accurate...)
Comments
By Todd T. Fries (todd) todd@openbsd.org on http://todd.fries.net/