Browse Source

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
Kaifeng Wang 5 months ago
parent
commit
f37eb0fc58

+ 6
- 0
ironic_inspector/conf/iptables.py View File

@@ -34,6 +34,12 @@ _OPTS = [
34 34
                        'which are not in desired state are going to be '
35 35
                        'blacklisted based on the list of neighbor MACs '
36 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
 

+ 14
- 4
ironic_inspector/pxe_filter/iptables.py View File

@@ -50,8 +50,18 @@ class IptablesFilter(pxe_filter.BaseFilter):
50 50
         self.interface = CONF.iptables.dnsmasq_interface
51 51
         self.chain = CONF.iptables.firewall_chain
52 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 63
         self.base_command = ('sudo', 'ironic-inspector-rootwrap',
54
-                             CONF.rootwrap_config, 'iptables')
64
+                             CONF.rootwrap_config, self._cmd_iptables)
55 65
 
56 66
     def reset(self):
57 67
         self.enabled = True
@@ -137,9 +147,9 @@ class IptablesFilter(pxe_filter.BaseFilter):
137 147
 
138 148
         # Swap chains
139 149
         self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp',
140
-                       '--dport', '67', '-j', chain)
150
+                       '--dport', self._dhcp_port, '-j', chain)
141 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 153
                        ignore=True)
144 154
         self._iptables('-F', main_chain, ignore=True)
145 155
         self._iptables('-X', main_chain, ignore=True)
@@ -163,7 +173,7 @@ class IptablesFilter(pxe_filter.BaseFilter):
163 173
 
164 174
     def _clean_up(self, chain):
165 175
         self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
166
-                       '--dport', '67', '-j', chain,
176
+                       '--dport', self._dhcp_port, '-j', chain,
167 177
                        ignore=True)
168 178
         self._iptables('-F', chain, ignore=True)
169 179
         self._iptables('-X', chain, ignore=True)

+ 55
- 12
ironic_inspector/test/unit/test_iptables.py View File

@@ -114,20 +114,23 @@ class TestIptablesDriver(test_base.NodeTest):
114 114
         self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter)
115 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 121
         self.mock_should_enable_dhcp.return_value = True
119 122
 
120 123
         _iptables_expected_args = [
121 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 126
             ('-F', self.driver.new_chain),
124 127
             ('-X', self.driver.new_chain),
125 128
             ('-N', self.driver.new_chain),
126 129
             ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
127 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 132
             ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
130
-             '67', '-j', self.driver.chain),
133
+             expected_port, '-j', self.driver.chain),
131 134
             ('-F', self.driver.chain),
132 135
             ('-X', self.driver.chain),
133 136
             ('-E', self.driver.new_chain, self.driver.chain)
@@ -142,6 +145,14 @@ class TestIptablesDriver(test_base.NodeTest):
142 145
         self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
143 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 156
     def test__iptables_kwargs(self):
146 157
         _iptables_expected_kwargs = [
147 158
             {'ignore': True},
@@ -163,13 +174,16 @@ class TestIptablesDriver(test_base.NodeTest):
163 174
             self.assertEqual(kwargs, call[1])
164 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 181
         self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
168 182
         self.mock_should_enable_dhcp.return_value = True
169 183
 
170 184
         _iptables_expected_args = [
171 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 187
             ('-F', self.driver.new_chain),
174 188
             ('-X', self.driver.new_chain),
175 189
             ('-N', self.driver.new_chain),
@@ -178,9 +192,9 @@ class TestIptablesDriver(test_base.NodeTest):
178 192
              self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
179 193
             ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
180 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 196
             ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
183
-             '67', '-j', self.driver.chain),
197
+             expected_port, '-j', self.driver.chain),
184 198
             ('-F', self.driver.chain),
185 199
             ('-X', self.driver.chain),
186 200
             ('-E', self.driver.new_chain, self.driver.chain)
@@ -203,7 +217,18 @@ class TestIptablesDriver(test_base.NodeTest):
203 217
         self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
204 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 232
         self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
208 233
         self.mock_should_enable_dhcp.return_value = True
209 234
 
@@ -217,7 +242,7 @@ class TestIptablesDriver(test_base.NodeTest):
217 242
         syncs_expected_args = [
218 243
             # driver reset
219 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 246
             ('-F', self.driver.new_chain),
222 247
             ('-X', self.driver.new_chain),
223 248
             ('-N', self.driver.new_chain),
@@ -226,9 +251,9 @@ class TestIptablesDriver(test_base.NodeTest):
226 251
              self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
227 252
             ('-A', self.driver.new_chain, '-j', 'ACCEPT'),
228 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 255
             ('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
231
-             '67', '-j', self.driver.chain),
256
+             expected_port, '-j', self.driver.chain),
232 257
             ('-F', self.driver.chain),
233 258
             ('-X', self.driver.chain),
234 259
             ('-E', self.driver.new_chain, self.driver.chain)
@@ -247,6 +272,24 @@ class TestIptablesDriver(test_base.NodeTest):
247 272
             self.assertEqual(args, call[0], 'idx: %s' % idx)
248 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
 
251 294
 class Test_ShouldEnableDhcp(test_base.BaseTest):
252 295
     def setUp(self):

+ 8
- 0
releasenotes/notes/support-ip6tables-ce30f614de502adb.yaml View File

@@ -0,0 +1,8 @@
1
+---
2
+features:
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``.

+ 2
- 1
rootwrap.d/ironic-inspector.filters View File

@@ -2,8 +2,9 @@
2 2
 
3 3
 [Filters]
4 4
 # ironic-inspector-rootwrap command filters for firewall manipulation
5
-# ironic_inspector/firewall.py
5
+# ironic_inspector/pxe_filter/iptables.py
6 6
 iptables: CommandFilter, iptables, root
7
+ip6tables: CommandFilter, ip6tables, root
7 8
 
8 9
 # ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service
9 10
 # ironic_inspector/pxe_filter/dnsmasq.py

Loading…
Cancel
Save