Merge "Do not announce any DNS resolver if "0.0.0.0" or "::" provided"

This commit is contained in:
Zuul 2021-12-17 18:52:36 +00:00 committed by Gerrit Code Review
commit 5122b1c077
5 changed files with 91 additions and 11 deletions

View File

@ -1153,10 +1153,8 @@ class Dnsmasq(DhcpLocalProcess):
addr_mode == constants.IPV6_SLAAC)):
continue
if subnet.dns_nameservers:
if ((subnet.ip_version == 4 and
subnet.dns_nameservers == ['0.0.0.0']) or
(subnet.ip_version == 6 and
subnet.dns_nameservers == ['::'])):
if common_utils.is_dns_servers_any_address(
subnet.dns_nameservers, subnet.ip_version):
# Special case: Do not announce DNS servers
options.append(
self._format_option(

View File

@ -37,6 +37,8 @@ from ovsdbapp import constants as ovsdbapp_const
from neutron._i18n import _
from neutron.common.ovn import constants
from neutron.common.ovn import exceptions as ovn_exc
from neutron.common import utils as common_utils
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
from neutron.db import models_v2
from neutron.objects import ports as ports_obj
@ -414,6 +416,26 @@ def get_system_dns_resolvers(resolver_file=DNS_RESOLVER_FILE):
return resolvers
def get_dhcp_dns_servers(subnet, ip_version=const.IP_VERSION_4):
"""Retrieve the DHCP option DNS servers
The DHCP should not announce any DNS resolver at all on the subnet if any
configured DNS server is "0.0.0.0" (IPv4) or "::" (IPv6).
https://docs.openstack.org/neutron/latest/admin/config-dns-res.html
"""
if ip_version == const.IP_VERSION_4:
dns_servers = (subnet.get('dns_nameservers') or
ovn_conf.get_dns_servers() or
get_system_dns_resolvers())
else:
dns_servers = subnet['dns_nameservers']
if common_utils.is_dns_servers_any_address(dns_servers, ip_version):
return []
return dns_servers
def get_port_subnet_ids(port):
fixed_ips = list(port['fixed_ips'])
return [f['subnet_id'] for f in fixed_ips]

View File

@ -145,6 +145,13 @@ def get_dhcp_agent_device_id(network_id, host):
return 'dhcp%s-%s' % (host_uuid, network_id)
def is_dns_servers_any_address(dns_servers, ip_version):
"""Checks if DNS server list matches the IP any address '0.0.0.0'/'::'"""
ip_any = netaddr.IPNetwork(n_const.IP_ANY[ip_version]).ip
return (len(dns_servers) == 1 and
netaddr.IPNetwork(dns_servers[0]).ip == ip_any)
class exception_logger(object):
"""Wrap a function and log raised exception

View File

@ -1925,9 +1925,7 @@ class OVNClient(object):
options['server_mac'] = n_net.get_random_mac(
cfg.CONF.base_mac.split(':'))
dns_servers = (subnet.get('dns_nameservers') or
ovn_conf.get_dns_servers() or
utils.get_system_dns_resolvers())
dns_servers = utils.get_dhcp_dns_servers(subnet)
if dns_servers:
options['dns_server'] = '{%s}' % ', '.join(dns_servers)
else:
@ -1966,9 +1964,10 @@ class OVNClient(object):
cfg.CONF.base_mac.split(':'))
}
if subnet['dns_nameservers']:
dns_servers = '{%s}' % ', '.join(subnet['dns_nameservers'])
dhcpv6_opts['dns_server'] = dns_servers
dns_servers = utils.get_dhcp_dns_servers(subnet,
ip_version=const.IP_VERSION_6)
if dns_servers:
dhcpv6_opts['dns_server'] = '{%s}' % ', '.join(dns_servers)
if subnet.get('ipv6_address_mode') == const.DHCPV6_STATELESS:
dhcpv6_opts[ovn_const.DHCPV6_STATELESS_OPT] = 'true'

View File

@ -14,10 +14,13 @@
# under the License.
from collections import namedtuple
from os import path
from unittest import mock
import fixtures
from neutron_lib.api.definitions import extra_dhcp_opt as edo_ext
from neutron_lib import constants as n_const
from oslo_config import cfg
from neutron.common.ovn import constants
from neutron.common.ovn import utils
@ -33,6 +36,7 @@ nameserver foo 10.0.0.4
nameserver aef0::4
foo 10.0.0.5
"""
RESOLV_DNS_SERVERS = ['10.0.0.1', '10.0.0.3']
class TestUtils(base.BaseTestCase):
@ -43,7 +47,7 @@ class TestUtils(base.BaseTestCase):
tmp_resolv_file = open(resolver_file_name, 'w')
tmp_resolv_file.writelines(RESOLV_CONF_TEMPLATE)
tmp_resolv_file.close()
expected_dns_resolvers = ['10.0.0.1', '10.0.0.3']
expected_dns_resolvers = RESOLV_DNS_SERVERS
observed_dns_resolvers = utils.get_system_dns_resolvers(
resolver_file=resolver_file_name)
self.assertEqual(expected_dns_resolvers, observed_dns_resolvers)
@ -379,3 +383,53 @@ class TestConnectionConfigToTargetString(base.BaseTestCase):
for config, target in config_target:
output = utils.connection_config_to_target_string(config)
self.assertEqual(target, output)
class TestGetDhcpDnsServers(base.BaseTestCase):
def test_ipv4(self):
# DNS servers from subnet.
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['1.2.3.4', '5.6.7.8']})
self.assertEqual(['1.2.3.4', '5.6.7.8'], dns_servers)
# DNS servers from config parameter.
cfg.CONF.set_override('dns_servers',
'1.1.2.2,3.3.4.4', group='ovn')
dns_servers = utils.get_dhcp_dns_servers({})
self.assertEqual(['1.1.2.2', '3.3.4.4'], dns_servers)
# DNS servers from local DNS resolver.
cfg.CONF.set_override('dns_servers', '', group='ovn')
with mock.patch('builtins.open',
mock.mock_open(read_data=RESOLV_CONF_TEMPLATE)), \
mock.patch.object(path, 'exists', return_value=True):
dns_servers = utils.get_dhcp_dns_servers({})
self.assertEqual(RESOLV_DNS_SERVERS, dns_servers)
# No DNS servers if only '0.0.0.0' configured.
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['0.0.0.0', '5.6.7.8']})
self.assertEqual(['0.0.0.0', '5.6.7.8'], dns_servers)
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['0.0.0.0']})
self.assertEqual([], dns_servers)
def test_ipv6(self):
# DNS servers from subnet.
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['2001:4860:4860::8888',
'2001:4860:4860::8844']},
ip_version=n_const.IP_VERSION_6)
self.assertEqual(['2001:4860:4860::8888',
'2001:4860:4860::8844'], dns_servers)
# No DNS servers if only '::' configured.
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['2001:4860:4860::8888', '::']},
ip_version=n_const.IP_VERSION_6)
self.assertEqual(['2001:4860:4860::8888', '::'], dns_servers)
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['::']},
ip_version=n_const.IP_VERSION_6)
self.assertEqual([], dns_servers)