In my last post I talked about running a pure IPv6 network, as part of my ISP building project, but still allowing access to resources on the internet currently only available via IPv4.
This works well assuming all the clients on the local network are IPv6 capable, unfortunately this is not always the case. There are legacy devices that do not understand IPv6.
This is a real problem with IoT devices that are either no longer being maintained or just that have hardware that is incapable of using anything other than IPv4. There is also a small problem that a IP cam with a IPv6 address is probably available to the world with out some firewall rules or a ACL limiting access to the local /64, but those are problems for another day…
Another issue is hard coded IPv4 addresses in legacy applications, this is a problem even if the OS/device supports both IPv4 & IPv6 but is only connected via IPv6.
There is are a few of solution to both these problems.
Dual Stack networks
The simplest is to just run a dual stack network supplying both IPv4 & IPv6 all the way from the end device to the edge of the ISPs network. While this works it either means using lots of IPv4 addresses in the ISPs internal network and probably 2 layers of NAT (one at the customers router and then CGNAT at the edge of the ISPs network) assuming the ISP is not handing out publicly routed IPv4 addresses directly to customers.
464XLAT
464XLAT -> 4 to 6 to 4 X transLATion and the X can be either a Client or Provider.
464CLAT comes in 2 main types
464CLAT – on host
464CLAT works by doing the conversion from IPv4 to IPv6 on the client. This works for sites that are only available via IPv4 and for hard coded IPv4 addresses. It all happens in the TCP/IP stack on the host OS. For this to work the OS needs a way to work out what the DNS64 prefix is.
This paper discusses methods for a client to determine the NAT64 prefix. It suggests that the simple method of looking up the IPv6 address of a hostname known to only have a IPv4 entry ipv4only.arpa
and using returned address (This behaviour is described in rfc7050).
There is an important step to validate that the address is returned is valid, because DNS64 breaks DNSSEC it takes a few extra steps.
- Make a IPv6 (AAAA) look up for
ipv4only.arp
with DNSSEC checking disabled - Make a reverse (PTR) lookup of the IPv6 address
64:ff9b::c000:ab
- This should return a pointer to a fully qualified domain name for a host in the ISPs domain (
nat64.hardill.me.uk
). - Finally make a IPv6 (AAAA) lookup for this hostname, which should return the same IPv6 address and a valid DNSSEC signature (RRSIG AAAA) record signed by the ISPs domain keys.
All of the required parts for this are running on my test network, I just need to attach some client devices to see if it works.
464CLAT – on router (Stateless translation)
This is a form of dual stack network, but it limits the dual stack to just the customer side of their router.
In this case the client network runs both native IPv6 and a RFC1918 range IPv4 and the clients router does the conversion by adding the IPv6 prefix. As well as running DHCPv6/SLAAC for IPv6 addressing it also runs DHCPv4 and hands out IPv4 addresses.
This works for devices that can’t support IPv6 (e.g. cheap IoT devices) and you still get to run a IPv6 only network in the ISP network.
The router generates it’s own prefix from the publicly routed IPv6 range it’s been allocated for it’s client side network. It then uses this prefix to generate 1 to 1 IPv6 addresses for each IPv4 address it hands out.
Jool can also be used to handle this in SIIT mode, you have to tell it what the input IPv4 range is and the IPv6 prefix it can work with.
#!/bin/sh
modprobe jool_siit
jool_siit instance add "example" --iptables
jool_siit -i "example" eamt add fd12:3456:789a:ff46:2::/96 10.99.0.0/24
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.ppp0.accept_ra=2
sysctl -w net.ipv6.conf.all.forwarding=1
ip6tables -t mangle -A PREROUTING -j JOOL_SIIT --instance "example"
iptables -t mangle -A PREROUTING -j JOOL_SIIT --instance "example"
Here I’ve hardcoded the IPv6 prefix, but for a real deployment we would need to use a delegated IPv6 prefix that is routed to the gateway. This should be run using the script
option for dhcp6c when the prefixes are delegated.
interface ppp0 {
send ia-na 0;
send ia-pd 0;
script "/etc/dhcp6c/reply.sh";
};
id-assoc na {
};
id-assoc pd 0 {
prefix-interface eth1 {
sla-len 0;
sla-id 1;
};
};
This config takes the /64
prefix and assigns it to eth1
for clients to use as part of SLAAC. I’m still working out how to extract the second /96
prefix and pass it to the script.
We can then update the script that starts jool as follows and point to it in the dhcp6c.conf
file so it gets run once the network is up.
#!/bin/sh
#IPv6=`ip -o -6 a show dev eth1 | awk '/global/ { print $4 }'`
#PREFIX=`subnetcalc $IPv6 -n | awk '/Network/ { print $3}'`
IPv4=`ip -4 -o a show dev eth1 | awk '/global/ {print $4}'`
SUBNET=`subnetcalc $IPv4 -n | awk '/Network/ {print $3}'`
#need to make sure this only runs once
modprobe jool_siit
jool_siit instance add "example" --iptables
jool_siit -i "example" eamt add fd12:3456:789a:ff46:2::/96 $SUBNET/24
sysctl -w net.ipv4.conf.all.forwarding=1
sysctl -w net.ipv6.conf.all.forwarding=1
ip6tables -t mangle -A PREROUTING -j JOOL_SIIT --instance "example"
iptables -t mangle -A PREROUTING -j JOOL_SIIT --instance "example"
464PLAT
This is usually just the NAT64 we talked about in the last post running in the ISPs network.