Always fill UDP checksums in DHCPv6 replies

Bug #1244589 re-appeared for IPv6.

This change adds an ip6tables rule to fix the checksum of DHCPv6
response packets. Those checksums were left unfilled by virtio (as a
hypervisor internal optimization), but some picky dhcp clients (AFAIU
particularly ISC dhclient) try verifying the checksums, so they fail
to acquire an address if the checksums are left incorrect.

Change-Id: I4a045e0dcfcbd3c7959a78f1460d5bf7da0252ff
Closes-Bug: #1811639
Related-Bug: #1244589
This commit is contained in:
Bence Romsics 2019-01-11 16:08:53 +01:00 committed by Slawek Kaplonski
parent 53bfd949bd
commit 26eb2509fe
3 changed files with 21 additions and 5 deletions

View File

@ -1561,9 +1561,12 @@ class DeviceManager(object):
def fill_dhcp_udp_checksums(self, namespace):
"""Ensure DHCP reply packets always have correct UDP checksums."""
iptables_mgr = iptables_manager.IptablesManager(use_ipv6=False,
iptables_mgr = iptables_manager.IptablesManager(use_ipv6=True,
namespace=namespace)
ipv4_rule = ('-p udp -m udp --dport %d -j CHECKSUM --checksum-fill'
% constants.DHCP_RESPONSE_PORT)
ipv6_rule = ('-p udp -m udp --dport %d -j CHECKSUM --checksum-fill'
% n_const.DHCPV6_CLIENT_PORT)
iptables_mgr.ipv4['mangle'].add_rule('POSTROUTING', ipv4_rule)
iptables_mgr.ipv6['mangle'].add_rule('POSTROUTING', ipv6_rule)
iptables_mgr.apply()

View File

@ -187,6 +187,9 @@ IP_ALLOWED_VERSIONS = [lib_constants.IP_VERSION_4, lib_constants.IP_VERSION_6]
PORT_RANGE_MIN = 1
PORT_RANGE_MAX = 65535
# TODO(bence romsics): move this to neutron_lib.constants
DHCPV6_CLIENT_PORT = 546
# Configuration values for accept_ra sysctl, copied from linux kernel
# networking (netdev) tree, file Documentation/networking/ip-sysctl.txt
#

View File

@ -33,6 +33,7 @@ from neutron.agent.linux import dhcp
from neutron.agent.linux import interface
from neutron.agent.metadata import driver as metadata_driver
from neutron.common import config as common_config
from neutron.common import constants as n_const
from neutron.common import utils
from neutron.conf.agent import common as config
from neutron.conf.agent import dhcp as dhcp_config
@ -1607,8 +1608,10 @@ class TestDeviceManager(base.BaseTestCase):
iptables_cls = iptables_cls_p.start()
self.iptables_inst = mock.Mock()
iptables_cls.return_value = self.iptables_inst
self.mangle_inst = mock.Mock()
self.iptables_inst.ipv4 = {'mangle': self.mangle_inst}
self.mangle_inst_v4 = mock.Mock()
self.iptables_inst.ipv4 = {'mangle': self.mangle_inst_v4}
self.mangle_inst_v6 = mock.Mock()
self.iptables_inst.ipv6 = {'mangle': self.mangle_inst_v6}
self.mock_ip_wrapper_p = mock.patch("neutron.agent.linux.ip_lib."
"IPWrapper")
@ -1682,12 +1685,19 @@ class TestDeviceManager(base.BaseTestCase):
self.mock_ipv6_enabled.return_value = False
self._test_setup_helper(False, ipv6_enabled=False)
def test_setup_calls_fill_dhcp_udp_checksums(self):
def test_setup_calls_fill_dhcp_udp_checksums_v4(self):
self._test_setup_helper(False)
rule = ('-p udp -m udp --dport %d -j CHECKSUM --checksum-fill'
% const.DHCP_RESPONSE_PORT)
expected = [mock.call.add_rule('POSTROUTING', rule)]
self.mangle_inst.assert_has_calls(expected)
self.mangle_inst_v4.assert_has_calls(expected)
def test_setup_calls_fill_dhcp_udp_checksums_v6(self):
self._test_setup_helper(False)
rule = ('-p udp -m udp --dport %d -j CHECKSUM --checksum-fill'
% n_const.DHCPV6_CLIENT_PORT)
expected = [mock.call.add_rule('POSTROUTING', rule)]
self.mangle_inst_v6.assert_has_calls(expected)
def test_setup_dhcp_port_doesnt_orphan_devices(self):
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice: