Friday, February 17, 2012

IPv6-only LAN with dual-stack OpenWRT router

I've managed to set up IPv6-only LAN behind a dual-stack OpenWRT router (not a Rocket Science, set up radvd on a router and don't configure IPv4 on LAN hosts). But I want to access IPv4-only hosts from this network and maybe provide services for these IPv4-only hosts.

First of all I'd like to thank Hurricane Electric for their amazing services, Jonathan McCrohan who made me write this howto and OpenWRT Team for their router software.

It's dangerous to go alone. Tayga, I choose you!

Tayga provides simple NAT64 service, it's good enough for small network.

First, install tayga package on your router (it is available from OpenWRT packages repository, be sure to use revision 30582 or later).

Next, configure NAT64 interface:

# /etc/config/network
config 'interface' 'nat64'
        option 'proto' 'tayga'
        option ipv4_addr
        option ipv6_addr 2001:470:1f09:xxxx::7f00:1
        option prefix 64:ff9b::/96
        option dynamic_pool
        option accept_ra 0
        option send_rs 0

where 2001:470:1f09:xxxx::/64 is IPv6 prefix used in my LAN, is tayga's prefix for 4-to-6 mappings and 64:ff9b::/96 is the prefix I chose for IPv6-mapped IPv4 addresses.

It is safe to add nat64 to lan firewall zone since you need to explicitly NAT44 packets for 4-to-6 inbound connections:

# /etc/config/firewall
config 'zone'
        option 'name' 'lan'
        option 'input' 'ACCEPT'
        option 'output' 'ACCEPT'
        option 'forward' 'ACCEPT'
        option 'network' 'lan nat64'

Let's try it (ifup nat64 interface and apply new firewall rules):

# ping6 -c3 64:ff9b::
PING 64:ff9b:: 56 data bytes
64 bytes from 64:ff9b::c257:32: icmp_seq=1 ttl=56 time=3.42 ms
64 bytes from 64:ff9b::c257:32: icmp_seq=2 ttl=56 time=3.35 ms
64 bytes from 64:ff9b::c257:32: icmp_seq=3 ttl=56 time=4.04 ms

--- 64:ff9b:: ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms
rtt min/avg/max/mdev = 3.354/3.610/4.049/0.319 ms

It's super effective!

So if a stranger calls you / Don't let him whisper his name / 'Cause it's Voodoo, oh!

Now we need a source for AAAA records for hosts that only have A's. This is called DNS64 and is supported by bind version 9.8.0 and up. It is also available from OpenWRT packages repository.

I've modified default named.conf:

# /etc/bind/named.conf
acl rfc1918 { 10/8; 192.168/16; 172.16/12; };

options {
        directory "/tmp";

        auth-nxdomain no;    # conform to RFC1035

        allow-query { localnets; localhost; };

        listen-on { any; };

        listen-on-v6 { any; };

        dns64 64:ff9b::/96 {
                clients { any; };
                mapped { !rfc1918; any; };
                exclude { 64:ff9b::/96; ::ffff:0000:0000/96; };
                suffix ::;

        edns-udp-size 512;
        max-udp-size 512;

// prime the server with knowledge of the root servers
zone "." {
        type hint;
        file "/etc/bind/db.root";

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912

zone "localhost" {
        type master;
        file "/etc/bind/db.local";

zone "" {
        type master;
        file "/etc/bind/db.127";

zone "" {
        type master;
        file "/etc/bind/db.0";

zone "" {
        type master;
        file "/etc/bind/db.255";

All hosts in LAN uses this bind as nameserver (announced via radvd and processed by dnssd). Let's try:

$ host has address has IPv6 address 64:ff9b::c257:32 mail is handled by 5

$ host domain name pointer

$ host 64:ff9b::c257:32 is an alias for domain name pointer

Cry me a river, you'll learn Voodoo!!

Close the city and tell the people that something's coming to call.

So what about giving IPv4 hosts access to services in my IPv6-olny network? It's easy, just need to configure NAT44 to an address from tayga's dynamic pool:

# /etc/config/firewall

# rule for tayga to create static mapping
config 'nat64'
        option 'ipv4_addr' ''
        option 'ipv6_addr' '2001:470:1f09::xxxx::yyyy:zzzz'

# rule for OpenWRT firewall to redirect traffic on port 25
config 'redirect'
        option 'src' 'wan'
        option 'proto' 'tcp'
        option 'src_dport' '25'
        option 'dest_ip' ''
        option 'target' 'DNAT'
        option 'dest' 'lan'

# rule OpenWRT firewall to permit access to port 25 to LAN host
config 'rule'
        option 'target' 'ACCEPT'
        option 'src' 'wan'
        option 'dest' 'lan'
        option 'proto' 'tcp'
        option 'dest_ip' '2001:470:1f09:xxxx::yyyy:zzzz'
        option 'dest_port' '25'
        option 'family' 'ipv6'

Last rule is only needed to provide access to my SMTP service via native IPv6. Since nat64 interface belongs to lan firewall zone there's no need to premit traffic from 64:ff9b::/64, it is already done by permitting traffic to (processed by redirect rule).

An now we can see some dirty spammers in maillog:

Feb 17 12:23:31 hell postfix/smtpd[12288]: connect from[64:ff9b::722a:9dc1]
Feb 17 12:23:31 hell postfix/smtpd[12288]: warning: non-SMTP command from[64:ff9b::722a:9dc1]: GET HTTP/1.0

The Mob Rules!


  1. HI,

    Could you provide more detail on configuring "dual-stack OpenWRT router" ?

    Thanks in advance.

    1. What details do you need? This is just a router with OpenWRT installed, which have both, IPv4 and IPv6 addresses.

  2. hello,

    what is the purpose of the IPv4 "dynamic pool"?

    1. When you access outside IPv4 host from local IPv6 host, the latter need to have source address, also IPv4. Which is taken from dynamic pool. I belive this is described in tayga manual.

  3. I have been reading and I get the dynamic pool. I am not able to get anyting to ping (IPv6 works but the nat64 doesn't seem to) and was wondering if you could tell me what build of openwrt you are running and on what platform for this to work?

    1. What exactly "doesn't seem to" work? You can't ping IPv4 address directly, instead you should ping NAT64PREFIX::I.P.AD.DR IPv6 address.

      I am using acient (december's I guess) snapshot of openwrt trunk in x86_64 VM.

  4. exactly, tayga runs but I cannot ping 64:ff9b:: or 64:ff9b:: or any other IP, including the WAN IP of my device. I am running this on a small router platform, I will try the x86 version and go from there. I might have some missing modules in my trunk build but nothing is complaining. thanks for the help

    1. You only need tun.ko module, because tayga is 100% userspace daemon. Check your routes, mine looks like:

      # ip ro sh dev tayga-nat64 scope link

      # ip -6 ro sh dev tayga-nat64
      64:ff9b::/96 metric 1024 mtu 1500 advmss 1440 hoplimit 0
      2001:470:1f08:xxxx::2 proto kernel metric 256 mtu 1500 advmss 1440 hoplimit 0
      fe80::/64 proto kernel metric 256 mtu 1500 advmss 1440 hoplimit 0

      # ip a sh dev tayga-nat64
      12: tayga-nat64: mtu 1500 qdisc pfifo_fast state UP qlen 500
      inet a.b.c.d/32 scope global tayga-nat64
      inet6 2001:470:1f08:xxxx::2/128 scope global
      valid_lft forever preferred_lft forever

      where a.b.c.d and 2001:470:1f08:xxxx::2 are IPv4 and IPv6 addresses on my "outside" interface(s), note the /24 and /128 masks.

  5. to clarify, the option ipv6_addr is the IPv6 address of your v6-WAN interface?

    1. No, this is tayga's internal address. For example, for sending ICMP Host Unreachable messages and stuff. In my example this is 2001:470:1f09:xxxx::, something that does not exist in my network and certainly NOT the address from any router interface.

  6. i got it working on a physical host. my problem was ip_forwarding for v4 as well as v6. thx for your help!