Core: DHCPv6: static mapping with prefix tracking leads to wrong DNS AAAA entry

Created on 18 Aug 2019  路  12Comments  路  Source: opnsense/core

Important notices
Before you add a new report, we ask you kindly to acknowledge the following:

[*] I have read the contributing guide lines at https://github.com/opnsense/core/blob/master/CONTRIBUTING.md

[*] I have searched the existing issues and I'm convinced that mine is new.

Describe the bug

According to the DHCPv6 settings page a static mapping for a network with IPv6 prefix tracking can be entered in the format ::1:2:3.4.

The static record itself is working for DHCPv6, but the resulting AAAA-DNS records are wrong - the (tracked) IPv6 prefix is missing from them:

$ host test.lan
test.lan has address 192.168.1.5
test.lan has IPv6 address ::1:2:3:4

This essentially breaks all communication with the host, as IPv6 is usually preferred.

To Reproduce
Steps to reproduce the behavior:

  1. Enable IPv6 prefix tracking for an interface
  2. Enable Unbound DNS (with option "register DHCP static mappings")
  3. Add a static DHCPv6 entry for "test.lan", omitting the prefix (just as suggested by the documentation)
  4. Apply changes
  5. This results in a broken DNS AAAA record for "test.lan"

Expected behavior

The DNS-AAAA record for the static host should contain the current prefix and the suffix configured in the static DHCPv6 mapping.

Environment
Software version used and hardware type if relevant.
e.g.:

OPNsense OPNsense 19.7.2 (amd64, OpenSSL).
APU2C4
Network Intel庐 I210-AT

help wanted

Most helpful comment

First of all thanks to everyone who has contributed to this amazing project, it has been a life saver.
@bliss7
Thank you for the patch it worked as intended.

@fichtner
I understand the philosophy of "not planning to add more cross-service (DHCP vs. Unbound) code", but it seems that until a broader plan is hashed out that the product shouldn't suffer from defects.

The patch provided by bliss is 4 lines, it is not like we are talking hundreds of lines of codes here.

All 12 comments

Hmm, this is an Unbound/Dnsmasq issue then. Problem is that prefix merging works in DHCPv6 service but there is no great way of knowing for any other service without creating external plumbing.

@fichtner Wouldn't a script which runs on each prefix change be enough? This script could generate a correct unbound/dnsmasq config containing the full IPv6 addresses of static host mappings.

This would also be an important step for proper IPv6 firewall rules in environments with dynamic prefixes, as then we could use DNS aliases for IPv6 hosts.

Interestingly the /var/dhcpd/etc/dhcpdv6.conf contains the full address, but the core/src/etc/inc/plugins.inc.d/unbound.inc reads the leases from $config['dhcpdv6'] which doesn't seem complete.
If there is information about the interface in the $config['dhcpdv6'] tree, than the address could be reconstructed from the interface.
Or of there is an prefix change the script will write the full IPv6 address somewhere in $config['dhcpdv6']
then there could be some code in https://github.com/opnsense/core/blob/6c4b88070508b52468ad6238bb087f490530f014/src/etc/inc/plugins.inc.d/unbound.inc#L675 like:
if (is_ipaddrv6($host['ipaddrv6'])) {
ipaddrv6 = $host['ipaddrv6']
} else {
ipaddrv6 = $host['ipaddrv6_temp']
}

The prefix is merged with the suffix on config write in DHCPv6. But this is only run time information and we are fairly certain that unbound rewrite for all and any address changes will not be the favourite solution for all users. Tracking is a huge issue because we passively listen on another interface which may lead to event pollution or a lot of cross-service logic which is suboptimal for service isolation and simplicity reasons, eventually also maintenance efforts.

In short, shifting prefixes really really suck in automated scenarios where people expect static and stable runtime configurations.

I can't really follow, but may be I missed something, so please correct me if I am wrong.
For non static DHCP leases I can't see any additional dependency:
If you are talking about "cross-service logic" do you mean the interaction between DHCP and DNS? I think this is a cross-service logic that is highly requested and common. Other tools/router/FW does the the same e.g. AD controller or FritzBox.
And I think there is a cross-service logic on DHCP client and DHCP Server, because the prefix delegation need to be propagated to the server.
If the DHCPv6 service updates the DNS for new leases this should be sufficient, because if the prefix is changing there will be new leases for every client.

For static DHCP release, i think this could work without additional dependencies too:
If DNS entries for static DHCP Leases should be available before the DHCP Server has offered the lease, than DNS needs a new config.
But even this update can be implemented as a DHCP -> DNS cross-service logic, e.g. if DHCP detects new prefix. send new leases to DNS.

Last but not least. IMHO If you run an environment with dynamic prefix changes, you don't expect a static runtime configuration, you expect adoption to the changes and make it feel static, because of DNS pointing to the right IP regardless of the prefix
If you have static prefixes you don't care so much about the functionality we are discussing here.

it looks like dhcpd.inc is generating real ip for static mapping here at :
https://github.com/opnsense/core/blob/master/src/etc/inc/plugins.inc.d/dhcpd.inc#L1510-L1512

But unbound and dnsmasq don't do it.
So, I made the following fix for unbound:

https://github.com/opnsense/core/blob/master/src/etc/inc/plugins.inc.d/unbound.inc#L674-L690

to:

                $_ifcfgipv6 = find_interface_ipv6(get_real_interface($dhcpif, 'inet6'), $ifconfig_details); // added by @bliss7
                foreach ($dhcpifconf['staticmap'] as $host) {
                    if (!$host['ipaddrv6'] || !$host['hostname']) {
                        continue;
                    }

                    $domain = $config['system']['domain'];
                    if ($host['domain']) {
                        $domain = $host['domain'];
                    } elseif ($dhcpifconf['domain']) {
                        $domain = $dhcpifconf['domain'];
                    }

                     // added by @bliss7
                    if (isset($config['interfaces'][$dhcpif]['dhcpd6track6allowoverride'])) {
                        $host['ipaddrv6'] = make_ipv6_64_address($_ifcfgipv6, $host['ipaddrv6']);
                    }

                    $unbound_entries .= "local-data-ptr: \"{$host['ipaddrv6']} {$host['hostname']}.{$domain}\"\n";
                    $unbound_entries .= "local-data: \"{$host['hostname']}.{$domain} IN AAAA {$host['ipaddrv6']}\"\n";
                    if (!empty($host['descr']) && $unboundcfg['txtsupport'] == 'on') {
                        $unbound_entries .= "local-data: '{$host['hostname']}.{$domain} TXT \"" . addslashes($host['descr']) . "\"'\n";
                    }
                }

it's exactly same way with the dhcpd.inc and I just added 4 lines.
you can modify /usr/local/etc/inc/plugins.inc.d/unbound.inc until the issue is resolved.

As I said we're not planning to add more cross-service (DHCP vs. Unbound) code at this point.

https://github.com/opnsense/core/issues/2544 this is the broader challenge and without a plan we just end up with a lot of unmaintainable code in the future of which we already spent some years to undo in OPNsense.

I know this is a bigger thing, bit this all sounds like an event bus or similar would be useful. Plugins and other parts can publish or subscribe events.
This allows to handle dependencies more loosely.
Again nothing that can be implemented without some further design work, just as a design idea.

This issue has been automatically timed-out (after 180 days of inactivity).

For more information about the policies for this repository,
please read https://github.com/opnsense/core/blob/master/CONTRIBUTING.md for further details.

If someone wants to step up and work on this issue,
just let us know, so we can reopen the issue and assign an owner to it.

First of all thanks to everyone who has contributed to this amazing project, it has been a life saver.
@bliss7
Thank you for the patch it worked as intended.

@fichtner
I understand the philosophy of "not planning to add more cross-service (DHCP vs. Unbound) code", but it seems that until a broader plan is hashed out that the product shouldn't suffer from defects.

The patch provided by bliss is 4 lines, it is not like we are talking hundreds of lines of codes here.

Is it planned / on the roadmap to have this feature implemented in the future? I am a Deutsche Telekom customer and having also a dynamic IPv6 prefix. (Also a fan of a robust solution instead of the hack above :) )

Was this page helpful?
0 / 5 - 0 ratings