Support ip6tables for iptables pxe filter
Adds a configuration option [iptables]ip_version to specify the desired ip version for the iptables pxe filter, which can be set to 4 or 6. When set to 6, the iptables pxe filter will use ip6tables command to manage rules for the port 547 which is the port of DHCPv6 server side. The string type is used to make room for the future, when there is need to automatically determine ip version from the binding interface. Change-Id: I7de2be5950a23def3ec6490f2e6dfa3d5c42798a Story: 1756012 Task: 11411
This commit is contained in:
parent
054f300290
commit
f37eb0fc58
@ -34,6 +34,12 @@ _OPTS = [
|
|||||||
'which are not in desired state are going to be '
|
'which are not in desired state are going to be '
|
||||||
'blacklisted based on the list of neighbor MACs '
|
'blacklisted based on the list of neighbor MACs '
|
||||||
'on these interfaces.')),
|
'on these interfaces.')),
|
||||||
|
cfg.StrOpt('ip_version',
|
||||||
|
default='4',
|
||||||
|
choices=[('4', _('IPv4')),
|
||||||
|
('6', _('IPv6'))],
|
||||||
|
help=_('The IP version that will be used for iptables filter. '
|
||||||
|
'Defaults to 4.')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,8 +50,18 @@ class IptablesFilter(pxe_filter.BaseFilter):
|
|||||||
self.interface = CONF.iptables.dnsmasq_interface
|
self.interface = CONF.iptables.dnsmasq_interface
|
||||||
self.chain = CONF.iptables.firewall_chain
|
self.chain = CONF.iptables.firewall_chain
|
||||||
self.new_chain = self.chain + '_temp'
|
self.new_chain = self.chain + '_temp'
|
||||||
|
|
||||||
|
# Determine arguments used for pxe filtering, we only support 4 and 6
|
||||||
|
# at this time.
|
||||||
|
if CONF.iptables.ip_version == '4':
|
||||||
|
self._cmd_iptables = 'iptables'
|
||||||
|
self._dhcp_port = '67'
|
||||||
|
else:
|
||||||
|
self._cmd_iptables = 'ip6tables'
|
||||||
|
self._dhcp_port = '547'
|
||||||
|
|
||||||
self.base_command = ('sudo', 'ironic-inspector-rootwrap',
|
self.base_command = ('sudo', 'ironic-inspector-rootwrap',
|
||||||
CONF.rootwrap_config, 'iptables')
|
CONF.rootwrap_config, self._cmd_iptables)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
@ -137,9 +147,9 @@ class IptablesFilter(pxe_filter.BaseFilter):
|
|||||||
|
|
||||||
# Swap chains
|
# Swap chains
|
||||||
self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp',
|
self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp',
|
||||||
'--dport', '67', '-j', chain)
|
'--dport', self._dhcp_port, '-j', chain)
|
||||||
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
|
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
|
||||||
'--dport', '67', '-j', main_chain,
|
'--dport', self._dhcp_port, '-j', main_chain,
|
||||||
ignore=True)
|
ignore=True)
|
||||||
self._iptables('-F', main_chain, ignore=True)
|
self._iptables('-F', main_chain, ignore=True)
|
||||||
self._iptables('-X', main_chain, ignore=True)
|
self._iptables('-X', main_chain, ignore=True)
|
||||||
@ -163,7 +173,7 @@ class IptablesFilter(pxe_filter.BaseFilter):
|
|||||||
|
|
||||||
def _clean_up(self, chain):
|
def _clean_up(self, chain):
|
||||||
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
|
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
|
||||||
'--dport', '67', '-j', chain,
|
'--dport', self._dhcp_port, '-j', chain,
|
||||||
ignore=True)
|
ignore=True)
|
||||||
self._iptables('-F', chain, ignore=True)
|
self._iptables('-F', chain, ignore=True)
|
||||||
self._iptables('-X', chain, ignore=True)
|
self._iptables('-X', chain, ignore=True)
|
||||||
|
@ -114,20 +114,23 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter)
|
self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter)
|
||||||
self.check_fsm([pxe_filter.Events.initialize, pxe_filter.Events.reset])
|
self.check_fsm([pxe_filter.Events.initialize, pxe_filter.Events.reset])
|
||||||
|
|
||||||
def test__iptables_args(self):
|
def _test__iptables_args(self, expected_port):
|
||||||
|
self.driver = iptables.IptablesFilter()
|
||||||
|
self.mock_iptables = self.useFixture(
|
||||||
|
fixtures.MockPatchObject(self.driver, '_iptables')).mock
|
||||||
self.mock_should_enable_dhcp.return_value = True
|
self.mock_should_enable_dhcp.return_value = True
|
||||||
|
|
||||||
_iptables_expected_args = [
|
_iptables_expected_args = [
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-F', self.driver.new_chain),
|
('-F', self.driver.new_chain),
|
||||||
('-X', self.driver.new_chain),
|
('-X', self.driver.new_chain),
|
||||||
('-N', self.driver.new_chain),
|
('-N', self.driver.new_chain),
|
||||||
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
||||||
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.chain),
|
expected_port, '-j', self.driver.chain),
|
||||||
('-F', self.driver.chain),
|
('-F', self.driver.chain),
|
||||||
('-X', self.driver.chain),
|
('-X', self.driver.chain),
|
||||||
('-E', self.driver.new_chain, self.driver.chain)
|
('-E', self.driver.new_chain, self.driver.chain)
|
||||||
@ -142,6 +145,14 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
||||||
self.check_fsm([pxe_filter.Events.sync])
|
self.check_fsm([pxe_filter.Events.sync])
|
||||||
|
|
||||||
|
def test__iptables_args_ipv4(self):
|
||||||
|
CONF.set_override('ip_version', '4', 'iptables')
|
||||||
|
self._test__iptables_args('67')
|
||||||
|
|
||||||
|
def test__iptables_args_ipv6(self):
|
||||||
|
CONF.set_override('ip_version', '6', 'iptables')
|
||||||
|
self._test__iptables_args('547')
|
||||||
|
|
||||||
def test__iptables_kwargs(self):
|
def test__iptables_kwargs(self):
|
||||||
_iptables_expected_kwargs = [
|
_iptables_expected_kwargs = [
|
||||||
{'ignore': True},
|
{'ignore': True},
|
||||||
@ -163,13 +174,16 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.assertEqual(kwargs, call[1])
|
self.assertEqual(kwargs, call[1])
|
||||||
self.check_fsm([pxe_filter.Events.sync])
|
self.check_fsm([pxe_filter.Events.sync])
|
||||||
|
|
||||||
def test_sync_with_blacklist(self):
|
def _test_sync_with_blacklist(self, expected_port):
|
||||||
|
self.driver = iptables.IptablesFilter()
|
||||||
|
self.mock_iptables = self.useFixture(
|
||||||
|
fixtures.MockPatchObject(self.driver, '_iptables')).mock
|
||||||
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
|
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
|
||||||
self.mock_should_enable_dhcp.return_value = True
|
self.mock_should_enable_dhcp.return_value = True
|
||||||
|
|
||||||
_iptables_expected_args = [
|
_iptables_expected_args = [
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-F', self.driver.new_chain),
|
('-F', self.driver.new_chain),
|
||||||
('-X', self.driver.new_chain),
|
('-X', self.driver.new_chain),
|
||||||
('-N', self.driver.new_chain),
|
('-N', self.driver.new_chain),
|
||||||
@ -178,9 +192,9 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
|
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
|
||||||
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
||||||
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.chain),
|
expected_port, '-j', self.driver.chain),
|
||||||
('-F', self.driver.chain),
|
('-F', self.driver.chain),
|
||||||
('-X', self.driver.chain),
|
('-X', self.driver.chain),
|
||||||
('-E', self.driver.new_chain, self.driver.chain)
|
('-E', self.driver.new_chain, self.driver.chain)
|
||||||
@ -203,7 +217,18 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
||||||
self.assertFalse(self.mock_iptables.called)
|
self.assertFalse(self.mock_iptables.called)
|
||||||
|
|
||||||
def test__iptables_clean_cache_on_error(self):
|
def test_sync_with_blacklist_ipv4(self):
|
||||||
|
CONF.set_override('ip_version', '4', 'iptables')
|
||||||
|
self._test_sync_with_blacklist('67')
|
||||||
|
|
||||||
|
def test_sync_with_blacklist_ipv6(self):
|
||||||
|
CONF.set_override('ip_version', '6', 'iptables')
|
||||||
|
self._test_sync_with_blacklist('547')
|
||||||
|
|
||||||
|
def _test__iptables_clean_cache_on_error(self, expected_port):
|
||||||
|
self.driver = iptables.IptablesFilter()
|
||||||
|
self.mock_iptables = self.useFixture(
|
||||||
|
fixtures.MockPatchObject(self.driver, '_iptables')).mock
|
||||||
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
|
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
|
||||||
self.mock_should_enable_dhcp.return_value = True
|
self.mock_should_enable_dhcp.return_value = True
|
||||||
|
|
||||||
@ -217,7 +242,7 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
syncs_expected_args = [
|
syncs_expected_args = [
|
||||||
# driver reset
|
# driver reset
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-F', self.driver.new_chain),
|
('-F', self.driver.new_chain),
|
||||||
('-X', self.driver.new_chain),
|
('-X', self.driver.new_chain),
|
||||||
('-N', self.driver.new_chain),
|
('-N', self.driver.new_chain),
|
||||||
@ -226,9 +251,9 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
|
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
|
||||||
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
|
||||||
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.new_chain),
|
expected_port, '-j', self.driver.new_chain),
|
||||||
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
|
||||||
'67', '-j', self.driver.chain),
|
expected_port, '-j', self.driver.chain),
|
||||||
('-F', self.driver.chain),
|
('-F', self.driver.chain),
|
||||||
('-X', self.driver.chain),
|
('-X', self.driver.chain),
|
||||||
('-E', self.driver.new_chain, self.driver.chain)
|
('-E', self.driver.new_chain, self.driver.chain)
|
||||||
@ -247,6 +272,24 @@ class TestIptablesDriver(test_base.NodeTest):
|
|||||||
self.assertEqual(args, call[0], 'idx: %s' % idx)
|
self.assertEqual(args, call[0], 'idx: %s' % idx)
|
||||||
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
|
||||||
|
|
||||||
|
def test__iptables_clean_cache_on_error_ipv4(self):
|
||||||
|
CONF.set_override('ip_version', '4', 'iptables')
|
||||||
|
self._test__iptables_clean_cache_on_error('67')
|
||||||
|
|
||||||
|
def test__iptables_clean_cache_on_error_ipv6(self):
|
||||||
|
CONF.set_override('ip_version', '6', 'iptables')
|
||||||
|
self._test__iptables_clean_cache_on_error('547')
|
||||||
|
|
||||||
|
def test_iptables_command_ipv4(self):
|
||||||
|
CONF.set_override('ip_version', '4', 'iptables')
|
||||||
|
driver = iptables.IptablesFilter()
|
||||||
|
self.assertEqual(driver._cmd_iptables, 'iptables')
|
||||||
|
|
||||||
|
def test_iptables_command_ipv6(self):
|
||||||
|
CONF.set_override('ip_version', '6', 'iptables')
|
||||||
|
driver = iptables.IptablesFilter()
|
||||||
|
self.assertEqual(driver._cmd_iptables, 'ip6tables')
|
||||||
|
|
||||||
|
|
||||||
class Test_ShouldEnableDhcp(test_base.BaseTest):
|
class Test_ShouldEnableDhcp(test_base.BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds a configuration option ``[iptables]ip_version`` to specify the
|
||||||
|
desired ip version for the iptables pxe filter, possible values are ``4``
|
||||||
|
and ``6``, the default value is ``4``. When set to ``6``, the iptables
|
||||||
|
pxe filter will use ``ip6tables`` command to manage rules for the DHCPv6
|
||||||
|
port ``547``.
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
[Filters]
|
[Filters]
|
||||||
# ironic-inspector-rootwrap command filters for firewall manipulation
|
# ironic-inspector-rootwrap command filters for firewall manipulation
|
||||||
# ironic_inspector/firewall.py
|
# ironic_inspector/pxe_filter/iptables.py
|
||||||
iptables: CommandFilter, iptables, root
|
iptables: CommandFilter, iptables, root
|
||||||
|
ip6tables: CommandFilter, ip6tables, root
|
||||||
|
|
||||||
# ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service
|
# ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service
|
||||||
# ironic_inspector/pxe_filter/dnsmasq.py
|
# ironic_inspector/pxe_filter/dnsmasq.py
|
||||||
|
Loading…
Reference in New Issue
Block a user