SLAAC and local IPv6 AAAA records in DNS forwarder

I have a fairly simple home network with both IPv4 and IPv6. I get a IPv6 prefix from my ISP and advertise it to local devices on my LAN through RA. Each device configures itself using SLAAC.

I have also configured a DNS forwarder in VyOS to cache DNS requests and provide DNS for LAN devices. All devices are informed about the DNS through either DHCP or RA. The local devices identify with the home.arpa domain. This works well for local IPv4 devices which advertise their hostname to the IPv4 DHCP server. The DHCP server writes the resulting hostname and IPv4 address to /etc/hosts such that the VyOS DNS forwarder picks it up. I can lookup mydevice as mydevice.home.arpa from any device on the network.

I can not figure out how to get this kind of local DNS resolution for the IPv6 addresses. Does SLAAC even inform VyOS about the resulting IP? And is there a way I can feed those dynamic IPv6 addresse into the DNS forwarder? What is the recommended way to get the IPv6 address of local devices when using SLAAC?

I am fairly new with VyOS. I have used an EdgeRouter 4 for the last eight years without really touching the tree config, and now I have a new box with VyOS. I am pretty sure that I got DNS resolution of IPv6 addresses on EdgeRouter, but I do not know how it did it.

Below is the sanitized config for VyOS (eth0 is WAN, eth1 is LAN):

firewall {
    group {
        interface-group WAN {
            interface "eth0"
        }
    }
    ipv4 {
        name LAN-LOCAL {
            default-action "accept"
        }
        name LAN-WAN {
            default-action "accept"
            rule 6 {
                action "drop"
                state "invalid"
            }
        }
        name LOCAL-LAN {
            default-action "accept"
        }
        name LOCAL-WAN {
            default-action "accept"
        }
        name WAN-LAN {
            default-action "drop"
            rule 5 {
                action "accept"
                description "Allow Established/Related traffic from WAN to LAN"
                state "established"
                state "related"
            }
            rule 6 {
                action "drop"
                state "invalid"
            }
            rule 10 {
                action "accept"
                connection-status {
                    nat "destination"
                }
                description "Allow all destination NAT (DNAT) port forwarding connections."
            }
            rule 20 {
                action "accept"
                protocol "icmp"
            }
        }
        name WAN-LOCAL {
            default-action "drop"
            rule 5 {
                action "accept"
                description "Allow Established/Related traffic to LOCAL from WAN."
                state "established"
                state "related"
            }
            rule 6 {
                action "drop"
                state "invalid"
            }
            rule 10 {
                action "accept"
                connection-status {
                    nat "destination"
                }
                description "Allow all estination NAT (DNAT) port forwarding connections."
            }
            rule 20 {
                action "accept"
                protocol "icmp"
            }
        }
    }
    ipv6 {
        name LAN-LOCAL {
            default-action "accept"
        }
        name LAN-WAN {
            default-action "accept"
            rule 6 {
                action "drop"
                state "invalid"
            }
        }
        name LOCAL-LAN {
            default-action "accept"
        }
        name LOCAL-WAN {
            default-action "accept"
        }
        name WAN-LAN {
            default-action "drop"
            rule 5 {
                action "accept"
                state "established"
                state "related"
            }
            rule 6 {
                action "drop"
                state "invalid"
            }
            rule 20 {
                action "accept"
                protocol "ipv6-icmp"
            }
        }
        name WAN-LOCAL {
            default-action "drop"
            rule 5 {
                action "accept"
                state "established"
                state "related"
            }
            rule 6 {
                action "drop"
                state "invalid"
            }
            rule 20 {
                action "accept"
                protocol "ipv6-icmp"
            }
            rule 30 {
                action "accept"
                description "Allow DHCPv6 configuration"
                destination {
                    port "546"
                }
                protocol "udp"
                source {
                    port "547"
                }
            }
            rule 40 {
                action "accept"
                description "Allow Wireguard to router."
                destination {
                    port "51820"
                }
                protocol "udp"
            }
        }
    }
    zone LAN {
        default-action "drop"
        description "Zone for LAN"
        from LOCAL {
            firewall {
                ipv6-name "LOCAL-LAN"
                name "LOCAL-LAN"
            }
        }
        from WAN {
            firewall {
                ipv6-name "WAN-LAN"
                name "WAN-LAN"
            }
        }
        member {
            interface "eth1"
            interface "wg1"
        }
    }
    zone LOCAL {
        default-action "drop"
        description "Zone for LOCAL (router-internal)"
        from LAN {
            firewall {
                ipv6-name "LAN-LOCAL"
                name "LAN-LOCAL"
            }
        }
        from WAN {
            firewall {
                ipv6-name "WAN-LOCAL"
                name "WAN-LOCAL"
            }
        }
        local-zone
    }
    zone WAN {
        default-action "drop"
        description "Zone for WAN (big internet)"
        from LAN {
            firewall {
                ipv6-name "LAN-WAN"
                name "LAN-WAN"
            }
        }
        from LOCAL {
            firewall {
                ipv6-name "LOCAL-WAN"
                name "LOCAL-WAN"
            }
        }
        member {
            interface "eth0"
        }
    }
}
interfaces {
    ethernet eth0 {
        address "dhcp"
        address "dhcpv6"
        description "WAN"
        dhcp-options {
            default-route-distance "10"
        }
        dhcpv6-options {
            pd 0 {
                interface eth1 {
                    address "1"
                    sla-id "16"
                }
                length "48"
            }
        }
        hw-id "00:d0:b4:05:c5:90"
        ipv6 {
            address {
                autoconf
            }
        }
        mac "fc:ec:da:43:fd:b8"
        offload {
            gro
            gso
            sg
            tso
        }
    }
    ethernet eth1 {
        address "192.168.10.1/24"
        address "fd00:10::1/64"
        description "LAN"
        hw-id "00:d0:b4:05:c5:91"
        ipv6 {
            address {
                autoconf
            }
        }
        offload {
            gro
            gso
            sg
            tso
        }
    }
    loopback lo {
    }
}
nat {
    source {
        rule 100 {
            description "NAT of regular LAN traffic to WAN."
            outbound-interface {
                group "WAN"
            }
            source {
                address "192.168.10.0/24"
            }
            translation {
                address "masquerade"
            }
        }
    }
}
service {
    dhcp-server {
        hostfile-update
        shared-network-name LAN {
            authoritative
            option {
                domain-name "home.arpa"
                domain-search "home.arpa"
                name-server "192.168.10.1"
            }
            subnet 192.168.10.0/23 {
                lease "86400"
                option {
                    bootfile-name "netboot.xyz-snponly.efi"
                    bootfile-server "192.168.10.10"
                    default-router "192.168.10.1"
                    tftp-server-name "192.168.10.10"
                }
                range 0 {
                    start "192.168.10.64"
                    stop "192.168.10.250"
                }
                static-mapping myfixeddevice {
                    ip-address "192.168.10.10"
                    mac "f8:b1:56:a3:b3:4d"
                }
                subnet-id "1"
            }
        }
    }
    dns {
        forwarding {
            allow-from "192.168.10.0/24"
            allow-from "fd00:10::/64"
            listen-address "192.168.10.1"
            listen-address "fd00:10::1"
            system
        }
    }
    ntp {
        allow-client {
            address "127.0.0.0/8"
            address "169.254.0.0/16"
            address "10.0.0.0/8"
            address "172.16.0.0/12"
            address "192.168.0.0/16"
            address "::1/128"
            address "fe80::/10"
            address "fc00::/7"
        }
        server time1.vyos.net {
        }
        server time2.vyos.net {
        }
        server time3.vyos.net {
        }
    }
    router-advert {
        interface eth1 {
            dnssl "home.arpa"
            name-server "fd00:10::1"
            prefix ::/64 {
            }
            prefix fd00:10::/64 {
            }
        }
    }
}
system {
    console {
        device ttyS0 {
            speed "115200"
        }
    }
    domain-name "home.arpa"
    host-name "vyos-router"
    name-server "1.1.1.1"
    name-server "8.8.8.8"
    name-server "2606:4700:4700::1111"
    name-server "2001:4860:4860::8888"
    option {
        kernel {
            disable-mitigations
        }
        keyboard-layout "no"
        reboot-on-upgrade-failure "5"
        startup-beep
    }
    syslog {
        local {
            facility all {
                level "info"
            }
            facility local7 {
                level "debug"
            }
        }
    }
    time-zone "Europe/Oslo"
}

No, when using router-advertisements the router has no way of knowing wat clients are there so it cannot updates your DNS forwarder. They just pick up the RA, create their config and start using it.

I guess if you want the DNS part to work you have to use DHCPv6, but I never tried if that works.

No, when using router-advertisements the router has no way of knowing wat clients are there so it cannot updates your DNS forwarder. They just pick up the RA, create their config and start using it.

I guess if you want the DNS part to work you have to use DHCPv6, but I never tried if that works.

That is not entirely true, there might be no automatism (at least not in the exact same way as with IPv4), but every host in an IPv6 subnet is well aware of its neighbors and their addresses via NDP.

Regarding the original question: This setup is also something I want to achieve in the long run; it is of quite low priority though, thus I haven’t investigated too much yet. In short it should work via mDNS. How one would implement that with VyOS (so that mDNS announcements are taken over into static DNS) I can’t tell (yet) :confused:

EDIT: At least 2024 it was not yet possible to resolve mDNS from VyOS, IMHO implying VyOS can’t do anything with it (besides relaying).

Thanks for the suggestions. It would be cool if NDP could feed link-local IPv6 into DNS. When I look at show ipv6 neighbors state reachable I see a bunch of LL addresses. However, it does not show hostname. Is hostname a part of NDP, or is NDP limited to only MAC and LL address?

I will look a bit more into mDNS to see if I can get something to work. The strange thing is that I feel that this was working well on the EdgeRouter 4. Perhaps I should poke a bit around in that one as well to see which services it runs.

It would be cool if NDP could feed link-local IPv6 into DNS.

Depending on your actual layout, that might not even be that useful :confused: Such hosts would only be reachable within the same L2 domain, besides that, what name would they be given?

Is hostname a part of NDP, or is NDP limited to only MAC and LL address?

I don’t think so, IPv6 got quite strict in separation of concerns. It takes care of quite some basic stuff, but names ain’t one of them. Without mDNS you’ll probably have a hard time. If you did some research and are able to confirm my assumption about VyOS being unable to do much with mDNS, you could open a feature request to change that. It would be really great to allow VyOS to ingest any mDNS info from networks attached to it.

The strange thing is that I feel that this was working well on the EdgeRouter 4.

Is that running VyOS as well? I’m not too familiar with proprietary networking stuff, I focus more on the OSS side of things. :sweat_smile:

Edgerouter series are just like VyOS a fork of Vyatta.

As I recall it Ubiquiti forked it to add support for MIPS64 as CPU architecture or something like that while VyOS forked due to misbehaviour from Brocade who tried to kill the Vyatta community.

Interesting, I was unaware of that!

On the other hand, this must mean for EdgeRouter there was some mDNS handling added, which is still missing on the VyOS side of things :confused:

Broadcom has a habit of doing that, they also killed the free VMware ESXi hypervisor.

When you use DHCP, you have a central service in charge of issuing IP adresses or IPv6 prefixes and hostnames. It can update a DNS server with this information, providing the DNS server supports RFC 2136.

The DHCP server in VyOS, kea, supports that (via set service dhcp-server dynamic-dns-update), but the DNS in VyOS is only a recursor, it can emulate authorative zones, but it is not a full authorative DNS server. So you need an external DNS server with RFC2136 support.

SLAAC has no central component, so you will have to rely on mDNS. Which is a local segemnt broadcast mechanism, so it works without a central service, as long as clients support mDNS (which apart from Windows all do). VyOS has an mDNS repeater to deal with the “local segment only” issue of mDNS.

Workaround for lack of “proper” authoritive DNS server in VyOS is to add one as a container in VyOS.

Either the official bind9 image or use Technitium or such:

Youtube video about Technitium:

Thanks! If I set up a proper DNS server with support for RFC2136, would kea update it with SLAAC-configured devices as well? Or only with devices that are configured through DHCPv4/DHCPv6?

You need to configure it: DHCP Server — VyOS rolling release (current)

Sure, but since I only use SLAAC I am not even using the dhcp6-server. I am only using the router-advert service. So can the router-advert service be configured such that SLAAC-configured devices sends RFC2136?

Edit: Or can the kea dhcp-server be configured to handle AAAA records from SLAAC devices?

No, the entire idea behind SLAAC is that it is server agnostic.

It is the client that determines that IPv6 address it takes for itself, so only the client is in a position to send an RFC2136 update to the DNS, which requires a compatible client and allowing your DNS server to accept unsecure DNS updates.

Afaik such a client does not exist, the normal route for DNS resolving in a SLAAC environment is to use mDNS. It should not be to complex for a developer to create an mDNS-to-RFC2136 proxy, capturing mDNS add/update/delete events and convert them to RFC2136 updates.

But I don’t know if one exists. Normally, the setup is either SLAAC + mDNS (home setups) or DHCPv6 (enterprise setups).

Thanks for the clarification!

An mDNS-to-RFC2136 proxy sounds like a fun side-project. I might be able to put that together with this mDNS library and some sort of RFC2136 client implementation.

Normally, the setup is either SLAAC + mDNS (home setups) or DHCPv6 (enterprise setups).

Regarding DHCPv6. As far as I understood, there is no support for DHCPv6 on Android. Do enterprise setups mainly deploy DHCPv6 even though Android does not support it?

I don’t know any enterprises that allow BYOD on their internal networks. For guest networks, DNS is not very relevant, nothing ever needs to connect to an Android device by name.

Apple seems to have a DNS-SD solution that implements RFC8766, which describes an mDNS to RFC2136 proxy.

Looking around when doing traceroutes its much more common of missing PTR-records in the IPv6 world than in the IPv4 world.

When it comes to clients one major difference is the concept of being able to not only use onlink addresses but also routed (assigned through DHCP6-PD (prefix delegation)) along with the not to uncommon way of simply just do link-local or even site-local for routing in order to not waste public IP-addresses.

That is a single physical interface will often in the IPv6 world use multiple IPv6-addresses for different purposes.

Accepting DNS updates from clients is a very bad idea.

What I would do if you really need PTR-records of the clients is to set the M-flag for the RA announcements and setup a DHCP6 that hands out the IPv6-addresses. Perhaps along with DHCP-relay and Option82 so you get semi-static assignment throughout your network. As in whatever is connected to SW1-INT5 will always get the same IPv4 and IPv6 assigned through DHCP/DHCP6.

And then just statically preconfigure the needed PTR-records. This way the precomputed PTR-record could then be sw1-int5.net.example.com

At enterpriselevel when you are in control of the clients then I think normal way today is just use some kind of inventory tool like Snow or whatever and have the client report all its metadata once its connected to the network. This way you will also fetch and store computername, SID (if using samba), CPU/RAM/storage, logged in username (this metadata will come from the loginserver itself but can still be handy to collect from the client) etc.

So in order to locate where PC123456 was connected in your network at a specific date and time you look in the logs of the inventory system rather than trying to use DNS or such.

I think using it for forensics is a bad idea, very unreliable and easily faked. Most enterprises I’ve encountered with requirements like this use 802.1x for LAN access (and usually also for VLAN selection), the logs of the switches and the authentication backend are much more reliable sources.

Imho you only need a DNS entry if you need a access the device from the outside by name because you don’t know its IP address. There is seldom, if not never, a need to access a regular LAN client that way, they never run services you need to access.