summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-11-27 03:38:12 +0000
committerGerrit Code Review <review@openstack.org>2018-11-27 03:38:12 +0000
commit7e63503ebec8b31b0b47925126b4cc39707a7633 (patch)
tree6a67c8bbfbd8a0697d9faa64a0ae2d6e9ac8bceb
parentf8ae2c494a42181efc04dc14cbfc4e3cea46fc60 (diff)
parentf37eb0fc587a24b3a29a695c2d2b708d2f7c32f2 (diff)
Merge "Support ip6tables for iptables pxe filter"
-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