Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unbound: restrict creation of PTR records for both the system domain and host overrides #5925

Merged
merged 8 commits into from
Aug 16, 2022
84 changes: 51 additions & 33 deletions src/etc/inc/plugins.inc.d/unbound.inc
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ function unbound_add_host_entries($ifconfig_details = null)
global $config;

$local_zone_type = 'transparent';
$ptr_records = [];
swhite2 marked this conversation as resolved.
Show resolved Hide resolved

openlog("unbound", LOG_DAEMON, LOG_LOCAL4);

if (!empty($config['unbound']['local_zone_type'])) {
$local_zone_type = $config['unbound']['local_zone_type'];
Expand All @@ -459,42 +462,47 @@ function unbound_add_host_entries($ifconfig_details = null)
} else {
$interfaces = array_keys(get_configured_interface_with_descr());
}
foreach ($interfaces as $interface) {
if ($interface == 'lo0' || substr($interface, 0, 4) == 'ovpn') {
continue;
}

list ($laddr) = interfaces_primary_address($interface, $ifconfig_details);
if (!empty($laddr)) {
$domain = $config['system']['domain'];
if (isset($config['dhcpd'][$interface]['enable']) && !empty($config['dhcpd'][$interface]['domain'])) {
$domain = $config['dhcpd'][$interface]['domain'];
}
$unbound_entries .= "local-data-ptr: \"{$laddr} {$config['system']['hostname']}.{$domain}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$domain} A {$laddr}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']} A {$laddr}\"\n";
}
list ($laddr6) = interfaces_primary_address6($interface, $ifconfig_details);
if (!empty($laddr6)) {
$domain = $config['system']['domain'];
if (isset($config['dhcpdv6'][$interface]['enable']) && !empty($config['dhcpdv6'][$interface]['domain'])) {
$domain = $config['dhcpdv6'][$interface]['domain'];
if (empty($config['unbound']['noregrecords'])) {
foreach ($interfaces as $interface) {
if ($interface == 'lo0' || substr($interface, 0, 4) == 'ovpn') {
continue;
}
$unbound_entries .= "local-data-ptr: \"{$laddr6} {$config['system']['hostname']}.{$domain}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$domain} AAAA {$laddr6}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']} AAAA {$laddr6}\"\n";
}
if (empty($config['unbound']['noreglladdr6'])) {
list ($lladdr6) = interfaces_scoped_address6($interface, $ifconfig_details);
if (!empty($lladdr6)) {
/* cannot embed scope */
$lladdr6 = explode('%', $lladdr6)[0];

list ($laddr) = interfaces_primary_address($interface, $ifconfig_details);
list ($laddr6) = interfaces_primary_address6($interface, $ifconfig_details);

foreach (['4' => $laddr, '6' => $laddr6] as $ip_version => $addr) {
if (empty($addr)) {
continue;
}

$domain = $config['system']['domain'];
if (isset($config['dhcpdv6'][$interface]['enable']) && !empty($config['dhcpdv6'][$interface]['domain'])) {
$domain = $config['dhcpdv6'][$interface]['domain'];
$dhcpd = $ip_version == '4' ? 'dhcpd' : 'dhcpd6';
$record = $ip_version == '4' ? 'A' : 'AAAA';
if (isset($config[$dhcpd][$interface]['enable']) && !empty($config[$dhcpd][$interface]['domain'])) {
$domain = $config[$dhcpd][$interface]['domain'];
}
if ($interface === get_primary_interface_from_list($interfaces) && !in_array($addr, $ptr_records, true)) {
fichtner marked this conversation as resolved.
Show resolved Hide resolved
$unbound_entries .= "local-data-ptr: \"{$addr} {$config['system']['hostname']}.{$domain}\"\n";
}
$unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$domain} {$record} {$addr}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']} {$record} {$addr}\"\n";

$ptr_records[] = $addr;
}

if (empty($config['unbound']['noreglladdr6'])) {
if (!empty($lladdr6)) {
/* cannot embed scope */
$lladdr6 = explode('%', $lladdr6)[0];
$domain = $config['system']['domain'];
if (isset($config['dhcpdv6'][$interface]['enable']) && !empty($config['dhcpdv6'][$interface]['domain'])) {
$domain = $config['dhcpdv6'][$interface]['domain'];
}
$unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$domain} AAAA {$lladdr6}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']} AAAA {$lladdr6}\"\n";
}
$unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$domain} AAAA {$lladdr6}\"\n";
$unbound_entries .= "local-data: \"{$config['system']['hostname']} AAAA {$lladdr6}\"\n";
}
}
}
Expand Down Expand Up @@ -560,7 +568,15 @@ function unbound_add_host_entries($ifconfig_details = null)
$unbound_entries .= "local-zone: \"{$alias['domain']}\" redirect\n";
$unbound_entries .= "local-data: \"{$alias['domain']} IN {$host->rr} {$host->server}\"\n";
} else {
$unbound_entries .= "local-data-ptr: \"{$host->server} {$alias['hostname']}{$alias['domain']}\"\n";
if (($alias === $tmp_aliases[0] || $tmp_aliases[0]['hostname'] === '*') && !in_array($host->server, $ptr_records, true)) {
fichtner marked this conversation as resolved.
Show resolved Hide resolved
/* Only generate a PTR record for the non-alias override and only if the IP is not already associated with a PTR.
* The exception to this is an alias whose parent uses a wildcard and as such does not specify a PTR record.
*/
$unbound_entries .= "local-data-ptr: \"{$host->server} {$alias['hostname']}{$alias['domain']}\"\n";
$ptr_records[] = $host->server;
} else {
syslog(LOG_WARNING, 'PTR record already exists for ' . $alias['hostname'] . $alias['domain'] . '(' . $host->server . ')');
}
$unbound_entries .= "local-data: \"{$alias['hostname']}{$alias['domain']} IN {$host->rr} {$host->server}\"\n";
}
break;
Expand Down Expand Up @@ -599,6 +615,8 @@ function unbound_add_host_entries($ifconfig_details = null)
}

file_put_contents('/var/unbound/host_entries.conf', $unbound_entries);

closelog();
}

function unbound_acls_subnets()
Expand Down
16 changes: 16 additions & 0 deletions src/www/services_unbound.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
$pconfig['regdhcpstatic'] = isset($a_unboundcfg['regdhcpstatic']);
$pconfig['txtsupport'] = isset($a_unboundcfg['txtsupport']);
$pconfig['cacheflush'] = isset($a_unboundcfg['cacheflush']);
$pconfig['noregrecords'] = isset($a_unboundcfg['noregrecords']);
// text values
$pconfig['port'] = !empty($a_unboundcfg['port']) ? $a_unboundcfg['port'] : null;
$pconfig['regdhcpdomain'] = !empty($a_unboundcfg['regdhcpdomain']) ? $a_unboundcfg['regdhcpdomain'] : null;
Expand Down Expand Up @@ -111,6 +112,7 @@
}

// boolean values
$a_unboundcfg['noregrecords'] = !empty($pconfig['noregrecords']);
$a_unboundcfg['cacheflush'] = !empty($pconfig['cacheflush']);
$a_unboundcfg['dns64'] = !empty($pconfig['dns64']);
$a_unboundcfg['dnssec'] = !empty($pconfig['dnssec']);
Expand Down Expand Up @@ -295,6 +297,20 @@
</div>
</td>
</tr>
<tr>
<td><a id="help_for_noregrecords" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?= gettext('System A/AAAA records') ?></td>
<td>
<input name="noregrecords" type="checkbox" id="noregrecords" value="yes" <?= !empty($pconfig['noregrecords']) ? 'checked="checked"' : '' ?>/>
<?= gettext('Do not register system A/AAAA records') ?>
<div class="hidden" data-for="help_for_noregrecords">
<?= sprintf(gettext("If this option is set, then no A/AAAA records for " .
"the configured listen interfaces will be generated. " .
"If desired, you can manually add them in %sUnbound DNS: Overrides%s. " .
"Use this to control which interface IP addresses are mapped to the system host/domain name " .
"as well as to restrict the amount of information exposed in replies to queries for the system host/domain name ."), '<a href="ui/unbound/overrides/">', '</a>'); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_txtsupport" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("TXT Comment Support");?></td>
<td>
Expand Down