From f5419d90791f0e258801b453c239c187302a3554 Mon Sep 17 00:00:00 2001 From: Darragh O'Reilly Date: Tue, 3 Feb 2015 17:03:23 +0000 Subject: [PATCH] Always fill UDP checksums in DHCP replies In some cases the UDP checksums in packets from DHCP servers are incorrect. This is a problem for some DHCP clients that ignore packets with bad checksums. This patch inserts an iptables rule to ensure DHCP servers always send packets with correct checksums. Change-Id: I130fe0f2389bdc42eb8c858ea35dd840abecc2e7 Closes-Bug: 1244589 --- neutron/agent/linux/dhcp.py | 11 +++++++++++ neutron/tests/unit/test_dhcp_agent.py | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index 2d97f3bc761..457d9190880 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -24,6 +24,7 @@ from oslo_utils import importutils import six from neutron.agent.linux import ip_lib +from neutron.agent.linux import iptables_manager from neutron.agent.linux import utils from neutron.common import constants from neutron.common import exceptions @@ -925,6 +926,7 @@ class DeviceManager(object): interface_name, port.mac_address, namespace=network.namespace) + self.fill_dhcp_udp_checksums(namespace=network.namespace) ip_cidrs = [] for fixed_ip in port.fixed_ips: subnet = fixed_ip.subnet @@ -961,3 +963,12 @@ class DeviceManager(object): self.plugin.release_dhcp_port(network.id, self.get_device_id(network)) + + def fill_dhcp_udp_checksums(self, namespace): + """Ensure DHCP reply packets always have correct UDP checksums.""" + iptables_mgr = iptables_manager.IptablesManager(use_ipv6=False, + namespace=namespace) + ipv4_rule = ('-p udp --dport %d -j CHECKSUM --checksum-fill' + % constants.DHCP_RESPONSE_PORT) + iptables_mgr.ipv4['mangle'].add_rule('POSTROUTING', ipv4_rule) + iptables_mgr.apply() diff --git a/neutron/tests/unit/test_dhcp_agent.py b/neutron/tests/unit/test_dhcp_agent.py index 5e100e188b9..b8402def66a 100644 --- a/neutron/tests/unit/test_dhcp_agent.py +++ b/neutron/tests/unit/test_dhcp_agent.py @@ -1173,6 +1173,14 @@ class TestDeviceManager(base.BaseTestCase): driver_cls.return_value = self.mock_driver iproute_cls.return_value = self.mock_iproute + iptables_cls_p = mock.patch( + 'neutron.agent.linux.iptables_manager.IptablesManager') + 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} + def _test_setup_helper(self, device_is_ready, net=None, port=None): net = net or fake_network port = port or fake_port1 @@ -1224,6 +1232,13 @@ class TestDeviceManager(base.BaseTestCase): cfg.CONF.set_override('enable_metadata_network', True) self._test_setup_helper(False) + def test_setup_calls_fill_dhcp_udp_checksums(self): + self._test_setup_helper(False) + rule = ('-p 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) + def test_setup_ipv6(self): self._test_setup_helper(True, net=fake_network_ipv6, port=fake_ipv6_port)