AAAA tale of two DNS

Since getting IPv6 up and running, I’ve been trying to figure out a way to map domain names to hosts no matter if they have statically assigned addresses or dhcp/radv generated ones. Additionally, I didn’t want to purchase a new domain. Instead I opted to create a new subdomain and delegated authority to my home IPv6 router’s name server.

In my first attempt, I was using a public FQDN. This presented a problem when using BIND’s allow-update as the private IPv4 range was now public and doesn’t help when trying to access my home computers. After some digging I found update-policy, but this required that each host made use of DNSSEC/TSIG/SIG…something I couldn’t guarantee on my network…yet. So it was back to allow-update.

A couple days later after some further thought, I settled on using a .local domain and via a script, copy the AAAA records to a public domain. This solution gives me easy access to my servers, without exposing the private IPv4 addresses. Even better, the script can be extended to include additional records or rules. For instance, don’t want to map android phones? Cisco switches? Cross reference the IPs to macs and filter away.

Zone config

zone "" {
	type master;
	file "/var/lib/bind/master/";
	//Only allow the updates from the local machine.
	allow-update { localhost; };
	//Only allow the axfr from the local machine.
	allow-transfer { localhost; };

zone "home.example.local" {
	type master;
	file "/var/lib/bind/master/home.example.local.conf";
	//Allow local network hosts with static addresses to update the zone.
	allow-update { LocalIPv6/64; LocalIPv4/24; localhost; };
	//Only allow the axfr from the local machine.
	allow-transfer { localhost; };

The actual zone files are your regular zone files, nothing special.


The script to update the public zone with AAAA records in the private. This is a cron job that only runs every hour as I’m not motivated enough at the moment to create higher res crontab.

//get the aaaa records that have been registered with the local domain...minus the ns records.
$c = "dig @::1 home.example.local. axfr | grep AAAA | grep -v ns.home.example.local";
$out = array();
exec($c, $out);
$hosts = array();

//build array with hostnames for keys pointing to an array of associated ipv6 addresses.
foreach($out as $v) {
	$hn = substr($v,0,strpos($v,'.'));
	if(!isset($hosts[$hn])) {
		$hosts[$hn] = array();
	$ipv6 = preg_split("/( |\t){1,}/", $v);
	$ipv6 = $ipv6[count($ipv6)-1];
	$hosts[$hn][] = $ipv6;

//Now take that array and pump it into nsupdate.
foreach($hosts as $k => $v) {
	$cmds = array("echo server ::1", "echo zone", "echo update delete {$k} AAAA");

	foreach($v as $ipv6) {
		$cmds[] = "echo update add {$k} 86400 AAAA {$ipv6}";
	$cmds[] = "echo send";
	$cmd = implode("\r\n", $cmds);
	exec("(". $cmd . ") | nsupdate", $out2);
	//var_dump("(". $cmd . ") | nsupdate");
	//var_dump(implode("\r\n", $out2));