summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaifeng Wang <kaifeng.w@gmail.com>2018-11-06 13:42:29 +0800
committerKaifeng Wang <kaifeng.w@gmail.com>2018-11-07 09:53:47 +0800
commitf37eb0fc587a24b3a29a695c2d2b708d2f7c32f2 (patch)
tree76291d599a54c9b68082eaf0c842017ca9b9dc56
parent054f300290c45035bb1cc1b222b2cc8cf26c3002 (diff)
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
Notes
Notes (review): Code-Review+2: Dmitry Tantsur <divius.inside@gmail.com> Code-Review+2: Julia Kreger <juliaashleykreger@gmail.com> Workflow+1: Julia Kreger <juliaashleykreger@gmail.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Tue, 27 Nov 2018 03:38:12 +0000 Reviewed-on: https://review.openstack.org/615728 Project: openstack/ironic-inspector Branch: refs/heads/master
-rw-r--r--ironic_inspector/conf/iptables.py6
-rw-r--r--ironic_inspector/pxe_filter/iptables.py18
-rw-r--r--ironic_inspector/test/unit/test_iptables.py67
-rw-r--r--releasenotes/notes/support-ip6tables-ce30f614de502adb.yaml8
-rw-r--r--rootwrap.d/ironic-inspector.filters3
5 files changed, 85 insertions, 17 deletions
diff --git a/ironic_inspector/conf/iptables.py b/ironic_inspector/conf/iptables.py
index 6b0c553..7ecf613 100644
--- a/ironic_inspector/conf/iptables.py
+++ b/ironic_inspector/conf/iptables.py
@@ -34,6 +34,12 @@ _OPTS = [
34 'which are not in desired state are going to be ' 34 'which are not in desired state are going to be '
35 'blacklisted based on the list of neighbor MACs ' 35 'blacklisted based on the list of neighbor MACs '
36 'on these interfaces.')), 36 'on these interfaces.')),
37 cfg.StrOpt('ip_version',
38 default='4',
39 choices=[('4', _('IPv4')),
40 ('6', _('IPv6'))],
41 help=_('The IP version that will be used for iptables filter. '
42 'Defaults to 4.')),
37] 43]
38 44
39 45
diff --git a/ironic_inspector/pxe_filter/iptables.py b/ironic_inspector/pxe_filter/iptables.py
index c4f1ad6..62480c6 100644
--- a/ironic_inspector/pxe_filter/iptables.py
+++ b/ironic_inspector/pxe_filter/iptables.py
@@ -50,8 +50,18 @@ class IptablesFilter(pxe_filter.BaseFilter):
50 self.interface = CONF.iptables.dnsmasq_interface 50 self.interface = CONF.iptables.dnsmasq_interface
51 self.chain = CONF.iptables.firewall_chain 51 self.chain = CONF.iptables.firewall_chain
52 self.new_chain = self.chain + '_temp' 52 self.new_chain = self.chain + '_temp'
53
54 # Determine arguments used for pxe filtering, we only support 4 and 6
55 # at this time.
56 if CONF.iptables.ip_version == '4':
57 self._cmd_iptables = 'iptables'
58 self._dhcp_port = '67'
59 else:
60 self._cmd_iptables = 'ip6tables'
61 self._dhcp_port = '547'
62
53 self.base_command = ('sudo', 'ironic-inspector-rootwrap', 63 self.base_command = ('sudo', 'ironic-inspector-rootwrap',
54 CONF.rootwrap_config, 'iptables') 64 CONF.rootwrap_config, self._cmd_iptables)
55 65
56 def reset(self): 66 def reset(self):
57 self.enabled = True 67 self.enabled = True
@@ -137,9 +147,9 @@ class IptablesFilter(pxe_filter.BaseFilter):
137 147
138 # Swap chains 148 # Swap chains
139 self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp', 149 self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp',
140 '--dport', '67', '-j', chain) 150 '--dport', self._dhcp_port, '-j', chain)
141 self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp', 151 self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
142 '--dport', '67', '-j', main_chain, 152 '--dport', self._dhcp_port, '-j', main_chain,
143 ignore=True) 153 ignore=True)
144 self._iptables('-F', main_chain, ignore=True) 154 self._iptables('-F', main_chain, ignore=True)
145 self._iptables('-X', main_chain, ignore=True) 155 self._iptables('-X', main_chain, ignore=True)
@@ -163,7 +173,7 @@ class IptablesFilter(pxe_filter.BaseFilter):
163 173
164 def _clean_up(self, chain): 174 def _clean_up(self, chain):
165 self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp', 175 self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
166 '--dport', '67', '-j', chain, 176 '--dport', self._dhcp_port, '-j', chain,
167 ignore=True) 177 ignore=True)
168 self._iptables('-F', chain, ignore=True) 178 self._iptables('-F', chain, ignore=True)
169 self._iptables('-X', chain, ignore=True) 179 self._iptables('-X', chain, ignore=True)
diff --git a/ironic_inspector/test/unit/test_iptables.py b/ironic_inspector/test/unit/test_iptables.py
index 3053ead..1e86190 100644
--- a/ironic_inspector/test/unit/test_iptables.py
+++ b/ironic_inspector/test/unit/test_iptables.py
@@ -114,20 +114,23 @@ class TestIptablesDriver(test_base.NodeTest):
114 self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter) 114 self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter)
115 self.check_fsm([pxe_filter.Events.initialize, pxe_filter.Events.reset]) 115 self.check_fsm([pxe_filter.Events.initialize, pxe_filter.Events.reset])
116 116
117 def test__iptables_args(self): 117 def _test__iptables_args(self, expected_port):
118 self.driver = iptables.IptablesFilter()
119 self.mock_iptables = self.useFixture(
120 fixtures.MockPatchObject(self.driver, '_iptables')).mock
118 self.mock_should_enable_dhcp.return_value = True 121 self.mock_should_enable_dhcp.return_value = True
119 122
120 _iptables_expected_args = [ 123 _iptables_expected_args = [
121 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 124 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
122 '67', '-j', self.driver.new_chain), 125 expected_port, '-j', self.driver.new_chain),
123 ('-F', self.driver.new_chain), 126 ('-F', self.driver.new_chain),
124 ('-X', self.driver.new_chain), 127 ('-X', self.driver.new_chain),
125 ('-N', self.driver.new_chain), 128 ('-N', self.driver.new_chain),
126 ('-A', self.driver.new_chain, '-j', 'ACCEPT'), 129 ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
127 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 130 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
128 '67', '-j', self.driver.new_chain), 131 expected_port, '-j', self.driver.new_chain),
129 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 132 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
130 '67', '-j', self.driver.chain), 133 expected_port, '-j', self.driver.chain),
131 ('-F', self.driver.chain), 134 ('-F', self.driver.chain),
132 ('-X', self.driver.chain), 135 ('-X', self.driver.chain),
133 ('-E', self.driver.new_chain, self.driver.chain) 136 ('-E', self.driver.new_chain, self.driver.chain)
@@ -142,6 +145,14 @@ class TestIptablesDriver(test_base.NodeTest):
142 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic) 145 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
143 self.check_fsm([pxe_filter.Events.sync]) 146 self.check_fsm([pxe_filter.Events.sync])
144 147
148 def test__iptables_args_ipv4(self):
149 CONF.set_override('ip_version', '4', 'iptables')
150 self._test__iptables_args('67')
151
152 def test__iptables_args_ipv6(self):
153 CONF.set_override('ip_version', '6', 'iptables')
154 self._test__iptables_args('547')
155
145 def test__iptables_kwargs(self): 156 def test__iptables_kwargs(self):
146 _iptables_expected_kwargs = [ 157 _iptables_expected_kwargs = [
147 {'ignore': True}, 158 {'ignore': True},
@@ -163,13 +174,16 @@ class TestIptablesDriver(test_base.NodeTest):
163 self.assertEqual(kwargs, call[1]) 174 self.assertEqual(kwargs, call[1])
164 self.check_fsm([pxe_filter.Events.sync]) 175 self.check_fsm([pxe_filter.Events.sync])
165 176
166 def test_sync_with_blacklist(self): 177 def _test_sync_with_blacklist(self, expected_port):
178 self.driver = iptables.IptablesFilter()
179 self.mock_iptables = self.useFixture(
180 fixtures.MockPatchObject(self.driver, '_iptables')).mock
167 self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF'] 181 self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
168 self.mock_should_enable_dhcp.return_value = True 182 self.mock_should_enable_dhcp.return_value = True
169 183
170 _iptables_expected_args = [ 184 _iptables_expected_args = [
171 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 185 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
172 '67', '-j', self.driver.new_chain), 186 expected_port, '-j', self.driver.new_chain),
173 ('-F', self.driver.new_chain), 187 ('-F', self.driver.new_chain),
174 ('-X', self.driver.new_chain), 188 ('-X', self.driver.new_chain),
175 ('-N', self.driver.new_chain), 189 ('-N', self.driver.new_chain),
@@ -178,9 +192,9 @@ class TestIptablesDriver(test_base.NodeTest):
178 self.mock__get_blacklist.return_value[0], '-j', 'DROP'), 192 self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
179 ('-A', self.driver.new_chain, '-j', 'ACCEPT'), 193 ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
180 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 194 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
181 '67', '-j', self.driver.new_chain), 195 expected_port, '-j', self.driver.new_chain),
182 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 196 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
183 '67', '-j', self.driver.chain), 197 expected_port, '-j', self.driver.chain),
184 ('-F', self.driver.chain), 198 ('-F', self.driver.chain),
185 ('-X', self.driver.chain), 199 ('-X', self.driver.chain),
186 ('-E', self.driver.new_chain, self.driver.chain) 200 ('-E', self.driver.new_chain, self.driver.chain)
@@ -203,7 +217,18 @@ class TestIptablesDriver(test_base.NodeTest):
203 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic) 217 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
204 self.assertFalse(self.mock_iptables.called) 218 self.assertFalse(self.mock_iptables.called)
205 219
206 def test__iptables_clean_cache_on_error(self): 220 def test_sync_with_blacklist_ipv4(self):
221 CONF.set_override('ip_version', '4', 'iptables')
222 self._test_sync_with_blacklist('67')
223
224 def test_sync_with_blacklist_ipv6(self):
225 CONF.set_override('ip_version', '6', 'iptables')
226 self._test_sync_with_blacklist('547')
227
228 def _test__iptables_clean_cache_on_error(self, expected_port):
229 self.driver = iptables.IptablesFilter()
230 self.mock_iptables = self.useFixture(
231 fixtures.MockPatchObject(self.driver, '_iptables')).mock
207 self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF'] 232 self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
208 self.mock_should_enable_dhcp.return_value = True 233 self.mock_should_enable_dhcp.return_value = True
209 234
@@ -217,7 +242,7 @@ class TestIptablesDriver(test_base.NodeTest):
217 syncs_expected_args = [ 242 syncs_expected_args = [
218 # driver reset 243 # driver reset
219 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 244 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
220 '67', '-j', self.driver.new_chain), 245 expected_port, '-j', self.driver.new_chain),
221 ('-F', self.driver.new_chain), 246 ('-F', self.driver.new_chain),
222 ('-X', self.driver.new_chain), 247 ('-X', self.driver.new_chain),
223 ('-N', self.driver.new_chain), 248 ('-N', self.driver.new_chain),
@@ -226,9 +251,9 @@ class TestIptablesDriver(test_base.NodeTest):
226 self.mock__get_blacklist.return_value[0], '-j', 'DROP'), 251 self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
227 ('-A', self.driver.new_chain, '-j', 'ACCEPT'), 252 ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
228 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 253 ('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
229 '67', '-j', self.driver.new_chain), 254 expected_port, '-j', self.driver.new_chain),
230 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport', 255 ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
231 '67', '-j', self.driver.chain), 256 expected_port, '-j', self.driver.chain),
232 ('-F', self.driver.chain), 257 ('-F', self.driver.chain),
233 ('-X', self.driver.chain), 258 ('-X', self.driver.chain),
234 ('-E', self.driver.new_chain, self.driver.chain) 259 ('-E', self.driver.new_chain, self.driver.chain)
@@ -247,6 +272,24 @@ class TestIptablesDriver(test_base.NodeTest):
247 self.assertEqual(args, call[0], 'idx: %s' % idx) 272 self.assertEqual(args, call[0], 'idx: %s' % idx)
248 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic) 273 self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
249 274
275 def test__iptables_clean_cache_on_error_ipv4(self):
276 CONF.set_override('ip_version', '4', 'iptables')
277 self._test__iptables_clean_cache_on_error('67')
278
279 def test__iptables_clean_cache_on_error_ipv6(self):
280 CONF.set_override('ip_version', '6', 'iptables')
281 self._test__iptables_clean_cache_on_error('547')
282
283 def test_iptables_command_ipv4(self):
284 CONF.set_override('ip_version', '4', 'iptables')
285 driver = iptables.IptablesFilter()
286 self.assertEqual(driver._cmd_iptables, 'iptables')
287
288 def test_iptables_command_ipv6(self):
289 CONF.set_override('ip_version', '6', 'iptables')
290 driver = iptables.IptablesFilter()
291 self.assertEqual(driver._cmd_iptables, 'ip6tables')
292
250 293
251class Test_ShouldEnableDhcp(test_base.BaseTest): 294class Test_ShouldEnableDhcp(test_base.BaseTest):
252 def setUp(self): 295 def setUp(self):
diff --git a/releasenotes/notes/support-ip6tables-ce30f614de502adb.yaml b/releasenotes/notes/support-ip6tables-ce30f614de502adb.yaml
new file mode 100644
index 0000000..33235b6
--- /dev/null
+++ b/releasenotes/notes/support-ip6tables-ce30f614de502adb.yaml
@@ -0,0 +1,8 @@
1---
2features:
3 - |
4 Adds a configuration option ``[iptables]ip_version`` to specify the
5 desired ip version for the iptables pxe filter, possible values are ``4``
6 and ``6``, the default value is ``4``. When set to ``6``, the iptables
7 pxe filter will use ``ip6tables`` command to manage rules for the DHCPv6
8 port ``547``.
diff --git a/rootwrap.d/ironic-inspector.filters b/rootwrap.d/ironic-inspector.filters
index 352dd84..4a38b51 100644
--- a/rootwrap.d/ironic-inspector.filters
+++ b/rootwrap.d/ironic-inspector.filters
@@ -2,8 +2,9 @@
2 2
3[Filters] 3[Filters]
4# ironic-inspector-rootwrap command filters for firewall manipulation 4# ironic-inspector-rootwrap command filters for firewall manipulation
5# ironic_inspector/firewall.py 5# ironic_inspector/pxe_filter/iptables.py
6iptables: CommandFilter, iptables, root 6iptables: CommandFilter, iptables, root
7ip6tables: CommandFilter, ip6tables, root
7 8
8# ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service 9# ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service
9# ironic_inspector/pxe_filter/dnsmasq.py 10# ironic_inspector/pxe_filter/dnsmasq.py