Secure dnsmasq process against external abuse
Currently any dhcp agent instance will work as an open resolver. For
deployments using publicly routed addresses for tenant networks, this
allows the agent being abused in dDoS attacks, see [1].
By setting the `--local-service` option dnsmasq will filter DNS queries
and reply only to queries from directly attached networks.
[1] https://bugs.launchpad.net/neutron/+bug/1501206
Conflicts:
neutron/cmd/sanity_check.py
Closes-Bug: 1501206
Change-Id: I76d810aad2ce0f15a88bd798963012fa0efca74e
(cherry picked from commit 0fce3ca2c1
)
This commit is contained in:
parent
262a978ea7
commit
f599c15e33
@ -334,24 +334,21 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
'dnsmasq',
|
'dnsmasq',
|
||||||
'--no-hosts',
|
'--no-hosts',
|
||||||
_no_resolv,
|
_no_resolv,
|
||||||
'--except-interface=lo',
|
|
||||||
'--pid-file=%s' % pid_file,
|
'--pid-file=%s' % pid_file,
|
||||||
'--dhcp-hostsfile=%s' % self.get_conf_file_name('host'),
|
'--dhcp-hostsfile=%s' % self.get_conf_file_name('host'),
|
||||||
'--addn-hosts=%s' % self.get_conf_file_name('addn_hosts'),
|
'--addn-hosts=%s' % self.get_conf_file_name('addn_hosts'),
|
||||||
'--dhcp-optsfile=%s' % self.get_conf_file_name('opts'),
|
'--dhcp-optsfile=%s' % self.get_conf_file_name('opts'),
|
||||||
'--dhcp-leasefile=%s' % self.get_conf_file_name('leases'),
|
'--dhcp-leasefile=%s' % self.get_conf_file_name('leases'),
|
||||||
'--dhcp-match=set:ipxe,175',
|
'--dhcp-match=set:ipxe,175',
|
||||||
|
'--local-service',
|
||||||
]
|
]
|
||||||
if self.device_manager.driver.bridged:
|
if self.device_manager.driver.bridged:
|
||||||
cmd += [
|
cmd += [
|
||||||
'--bind-interfaces',
|
'--bind-interfaces',
|
||||||
'--interface=%s' % self.interface_name,
|
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
cmd += [
|
cmd += [
|
||||||
'--bind-dynamic',
|
'--bind-dynamic',
|
||||||
'--interface=%s' % self.interface_name,
|
|
||||||
'--interface=tap*',
|
|
||||||
'--bridge-interface=%s,tap*' % self.interface_name,
|
'--bridge-interface=%s,tap*' % self.interface_name,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -198,6 +198,21 @@ def get_dnsmasq_version_with_dhcp_release6():
|
|||||||
return DNSMASQ_VERSION_DHCP_RELEASE6
|
return DNSMASQ_VERSION_DHCP_RELEASE6
|
||||||
|
|
||||||
|
|
||||||
|
def dnsmasq_local_service_supported():
|
||||||
|
cmd = ['dnsmasq', '--test', '--local-service']
|
||||||
|
env = {'LC_ALL': 'C'}
|
||||||
|
obj, cmd = agent_utils.create_process(cmd, addl_env=env)
|
||||||
|
_stdout, _stderr = obj.communicate()
|
||||||
|
returncode = obj.returncode
|
||||||
|
if returncode == 127:
|
||||||
|
LOG.debug("Exception while checking dnsmasq version. "
|
||||||
|
"dnsmasq: No such file or directory")
|
||||||
|
return False
|
||||||
|
elif returncode == 1:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def dnsmasq_version_supported():
|
def dnsmasq_version_supported():
|
||||||
try:
|
try:
|
||||||
cmd = ['dnsmasq', '--version']
|
cmd = ['dnsmasq', '--version']
|
||||||
|
@ -118,6 +118,15 @@ def check_dnsmasq_version():
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def check_dnsmasq_local_service_supported():
|
||||||
|
result = checks.dnsmasq_local_service_supported()
|
||||||
|
if not result:
|
||||||
|
LOG.error('The installed version of dnsmasq is too old. '
|
||||||
|
'Please update to a version supporting the '
|
||||||
|
'--local-service option.')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def check_keepalived_ipv6_support():
|
def check_keepalived_ipv6_support():
|
||||||
result = checks.keepalived_ipv6_supported()
|
result = checks.keepalived_ipv6_supported()
|
||||||
if not result:
|
if not result:
|
||||||
@ -304,6 +313,9 @@ OPTS = [
|
|||||||
help=_('Check for VF extended management support')),
|
help=_('Check for VF extended management support')),
|
||||||
BoolOptCallback('read_netns', check_read_netns,
|
BoolOptCallback('read_netns', check_read_netns,
|
||||||
help=_('Check netns permission settings')),
|
help=_('Check netns permission settings')),
|
||||||
|
BoolOptCallback('dnsmasq_local_service_supported',
|
||||||
|
check_dnsmasq_local_service_supported,
|
||||||
|
help=_('Check for local-service support in dnsmasq')),
|
||||||
BoolOptCallback('dnsmasq_version', check_dnsmasq_version,
|
BoolOptCallback('dnsmasq_version', check_dnsmasq_version,
|
||||||
help=_('Check minimal dnsmasq version'),
|
help=_('Check minimal dnsmasq version'),
|
||||||
deprecated_for_removal=True,
|
deprecated_for_removal=True,
|
||||||
@ -367,6 +379,9 @@ def enable_tests_from_config():
|
|||||||
cfg.CONF.set_default('read_netns', True)
|
cfg.CONF.set_default('read_netns', True)
|
||||||
if cfg.CONF.OVS.ovsdb_interface == 'native':
|
if cfg.CONF.OVS.ovsdb_interface == 'native':
|
||||||
cfg.CONF.set_default('ovsdb_native', True)
|
cfg.CONF.set_default('ovsdb_native', True)
|
||||||
|
if cfg.CONF.dhcp_driver == 'neutron.agent.linux.dhcp.Dnsmasq':
|
||||||
|
cfg.CONF.set_default('dnsmasq_local_service_supported', True)
|
||||||
|
cfg.CONF.set_default('dnsmasq_version', True)
|
||||||
if cfg.CONF.l3_ha:
|
if cfg.CONF.l3_ha:
|
||||||
cfg.CONF.set_default('keepalived_ipv6_support', True)
|
cfg.CONF.set_default('keepalived_ipv6_support', True)
|
||||||
cfg.CONF.set_default('ip_nonlocal_bind', True)
|
cfg.CONF.set_default('ip_nonlocal_bind', True)
|
||||||
|
@ -1218,15 +1218,14 @@ class TestDnsmasq(TestBase):
|
|||||||
'dnsmasq',
|
'dnsmasq',
|
||||||
'--no-hosts',
|
'--no-hosts',
|
||||||
no_resolv,
|
no_resolv,
|
||||||
'--except-interface=lo',
|
|
||||||
'--pid-file=%s' % expected_pid_file,
|
'--pid-file=%s' % expected_pid_file,
|
||||||
'--dhcp-hostsfile=/dhcp/%s/host' % network.id,
|
'--dhcp-hostsfile=/dhcp/%s/host' % network.id,
|
||||||
'--addn-hosts=/dhcp/%s/addn_hosts' % network.id,
|
'--addn-hosts=/dhcp/%s/addn_hosts' % network.id,
|
||||||
'--dhcp-optsfile=/dhcp/%s/opts' % network.id,
|
'--dhcp-optsfile=/dhcp/%s/opts' % network.id,
|
||||||
'--dhcp-leasefile=/dhcp/%s/leases' % network.id,
|
'--dhcp-leasefile=/dhcp/%s/leases' % network.id,
|
||||||
'--dhcp-match=set:ipxe,175',
|
'--dhcp-match=set:ipxe,175',
|
||||||
|
'--local-service',
|
||||||
'--bind-interfaces',
|
'--bind-interfaces',
|
||||||
'--interface=tap0',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
seconds = ''
|
seconds = ''
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes bug `1501206 <https://bugs.launchpad.net/neutron/+bug/1501206>`_.
|
||||||
|
This ensures that DHCP agent instances running dnsmasq as a DNS server
|
||||||
|
can no longer be exploited as DNS amplifiers when the tenant network is
|
||||||
|
using publicly routed IP addresses by adding an option that will allow
|
||||||
|
them to only serve DNS requests from local networks.
|
Loading…
Reference in New Issue
Block a user