iptables-ruby 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/CHANGELOG +23 -0
- data/Gemfile +6 -0
- data/Generate.md +278 -0
- data/LICENSE +20 -0
- data/README.md +140 -0
- data/Rakefile +44 -0
- data/bin/check_firewall.rb +220 -0
- data/examples/policy/macros.json +92 -0
- data/examples/policy/policy.json +208 -0
- data/examples/policy/policy6.json +8 -0
- data/examples/policy/primitives.json +40 -0
- data/examples/policy/rules.json +30 -0
- data/examples/policy/services.json +81 -0
- data/lib/iptables.rb +5 -0
- data/lib/iptables/configuration.rb +116 -0
- data/lib/iptables/expansions.rb +189 -0
- data/lib/iptables/logger.rb +5 -0
- data/lib/iptables/primitives.rb +51 -0
- data/lib/iptables/tables.rb +851 -0
- data/test/common.rb +22 -0
- data/test/tc_all.rb +7 -0
- data/test/tc_comparison.rb +751 -0
- data/test/tc_configuration.rb +72 -0
- data/test/tc_expansions.rb +116 -0
- data/test/tc_primitives.rb +35 -0
- data/test/tc_tables.rb +652 -0
- metadata +94 -0
data/test/common.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# this setup code is required by all tests
|
2
|
+
require 'rubygems'
|
3
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?('/../lib')
|
4
|
+
require 'iptables'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
# inspired by https://github.com/cespare/ruby-dedent
|
8
|
+
class String
|
9
|
+
def dedent
|
10
|
+
lines = split "\n"
|
11
|
+
return self if lines.empty?
|
12
|
+
# first indented line determines indent level
|
13
|
+
indentation = nil
|
14
|
+
lines.each{ |line|
|
15
|
+
next unless line =~ /^(\s+)/
|
16
|
+
indentation = $1
|
17
|
+
break
|
18
|
+
}
|
19
|
+
return self if indentation.nil?
|
20
|
+
lines.map { |line| line.sub(/^#{indentation}/, "") }.join "\n"
|
21
|
+
end
|
22
|
+
end
|
data/test/tc_all.rb
ADDED
@@ -0,0 +1,751 @@
|
|
1
|
+
require 'common'
|
2
|
+
|
3
|
+
class TestTablesComparison < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@iptables_table1 =
|
6
|
+
<<-EOS.dedent
|
7
|
+
*table1
|
8
|
+
:chain1 ACCEPT [0:0]
|
9
|
+
:chain2 ACCEPT [0:0]
|
10
|
+
-A chain1 -m comment --comment "comment1"
|
11
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
12
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
13
|
+
-A chain2 -m comment --comment "comment2"
|
14
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
15
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
16
|
+
COMMIT
|
17
|
+
EOS
|
18
|
+
@iptables_text =
|
19
|
+
"#{@iptables_table1}\n"+
|
20
|
+
<<-EOS.dedent
|
21
|
+
*table2
|
22
|
+
:chain3 ACCEPT [0:0]
|
23
|
+
:chain4 ACCEPT [0:0]
|
24
|
+
-A chain3 -m comment --comment "comment3"
|
25
|
+
-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT
|
26
|
+
-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT
|
27
|
+
-A chain4 -m comment --comment "comment4"
|
28
|
+
-A chain4 -p tcp -m tcp --dport 7 -j ACCEPT
|
29
|
+
-A chain4 -p tcp -m tcp --dport 8 -j ACCEPT
|
30
|
+
COMMIT
|
31
|
+
EOS
|
32
|
+
@iptables1 = IPTables::Tables.new( @iptables_text )
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_invalid
|
36
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Tables object as first parameter' ) {
|
37
|
+
IPTables::TablesComparison.new(nil, @iptables1)
|
38
|
+
}
|
39
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Tables object as second parameter' ) {
|
40
|
+
IPTables::TablesComparison.new(@iptables1, nil)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_equal
|
45
|
+
iptables2 = IPTables::Tables.new( @iptables_text )
|
46
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
47
|
+
|
48
|
+
assert(
|
49
|
+
comparison.equal?,
|
50
|
+
'Set of tables with same contents should evaluate as equal.'
|
51
|
+
)
|
52
|
+
assert_equal(
|
53
|
+
[],
|
54
|
+
comparison.as_array,
|
55
|
+
'Array output of tables with same contents should evaluate as empty.'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_missing_table
|
60
|
+
iptables2 = IPTables::Tables.new(
|
61
|
+
<<-EOS.dedent
|
62
|
+
*table1
|
63
|
+
:chain1 ACCEPT [0:0]
|
64
|
+
-A chain1 -m comment --comment "comment1"
|
65
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
66
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
67
|
+
:chain2 ACCEPT [0:0]
|
68
|
+
-A chain2 -m comment --comment "comment2"
|
69
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
70
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
71
|
+
COMMIT
|
72
|
+
EOS
|
73
|
+
)
|
74
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
75
|
+
|
76
|
+
assert_equal(
|
77
|
+
false,
|
78
|
+
comparison.equal?,
|
79
|
+
'Set of tables with one missing a table should evaluate as unequal.'
|
80
|
+
)
|
81
|
+
assert_equal(
|
82
|
+
comparison.as_array,
|
83
|
+
[
|
84
|
+
"Missing table: table2",
|
85
|
+
":chain3 ACCEPT",
|
86
|
+
":chain4 ACCEPT",
|
87
|
+
"-A chain3 -m comment --comment \"comment3\"",
|
88
|
+
"-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT",
|
89
|
+
"-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT",
|
90
|
+
"-A chain4 -m comment --comment \"comment4\"",
|
91
|
+
"-A chain4 -p tcp -m tcp --dport 7 -j ACCEPT",
|
92
|
+
"-A chain4 -p tcp -m tcp --dport 8 -j ACCEPT"
|
93
|
+
],
|
94
|
+
'Array output of tables with one missing a table should evaluate to known values.'
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_nil_existing_policy_table
|
99
|
+
iptables2 = IPTables::Tables.new({
|
100
|
+
'table1' => {
|
101
|
+
'chain1' => {
|
102
|
+
'policy' => 'ACCEPT',
|
103
|
+
'rules' => [
|
104
|
+
'-m comment --comment "comment1"',
|
105
|
+
'-p tcp -m tcp --dport 1 -j ACCEPT',
|
106
|
+
'-p tcp -m tcp --dport 2 -j ACCEPT',
|
107
|
+
]
|
108
|
+
},
|
109
|
+
'chain2' => {
|
110
|
+
'policy' => 'ACCEPT',
|
111
|
+
'rules' => [
|
112
|
+
'-m comment --comment "comment2"',
|
113
|
+
'-p tcp -m tcp --dport 3 -j ACCEPT',
|
114
|
+
'-p tcp -m tcp --dport 4 -j ACCEPT',
|
115
|
+
]
|
116
|
+
},
|
117
|
+
},
|
118
|
+
'table2' => nil
|
119
|
+
})
|
120
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
121
|
+
|
122
|
+
assert(
|
123
|
+
comparison.equal?,
|
124
|
+
'Set of tables which match except one is nil and one is a table should evaluate as equal.'
|
125
|
+
)
|
126
|
+
assert_equal(
|
127
|
+
[],
|
128
|
+
comparison.as_array,
|
129
|
+
'Array output of tables which match except one one is nil and one is a table should evaluate as empty.'
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_nil_missing_policy_table
|
134
|
+
iptables1 = IPTables::Tables.new( @iptables_table1 )
|
135
|
+
iptables2 = IPTables::Tables.new({
|
136
|
+
'table1' => {
|
137
|
+
'chain1' => {
|
138
|
+
'policy' => 'ACCEPT',
|
139
|
+
'rules' => [
|
140
|
+
'-m comment --comment "comment1"',
|
141
|
+
'-p tcp -m tcp --dport 1 -j ACCEPT',
|
142
|
+
'-p tcp -m tcp --dport 2 -j ACCEPT',
|
143
|
+
]
|
144
|
+
},
|
145
|
+
'chain2' => {
|
146
|
+
'policy' => 'ACCEPT',
|
147
|
+
'rules' => [
|
148
|
+
'-m comment --comment "comment2"',
|
149
|
+
'-p tcp -m tcp --dport 3 -j ACCEPT',
|
150
|
+
'-p tcp -m tcp --dport 4 -j ACCEPT',
|
151
|
+
]
|
152
|
+
},
|
153
|
+
},
|
154
|
+
'table2' => nil
|
155
|
+
})
|
156
|
+
comparison = IPTables::TablesComparison.new(iptables1, iptables2)
|
157
|
+
|
158
|
+
assert(
|
159
|
+
comparison.equal?,
|
160
|
+
'Set of tables which match except one is nil and one is missing should evaluate as equal.'
|
161
|
+
)
|
162
|
+
assert_equal(
|
163
|
+
[],
|
164
|
+
comparison.as_array,
|
165
|
+
'Array output of tables which match except one is nil and one is missing should evaluate as empty.'
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_additional_table
|
170
|
+
iptables2 = IPTables::Tables.new(
|
171
|
+
<<-EOS.dedent
|
172
|
+
*table1
|
173
|
+
:chain1 ACCEPT [0:0]
|
174
|
+
-A chain1 -m comment --comment "comment1"
|
175
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
176
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
177
|
+
:chain2 ACCEPT [0:0]
|
178
|
+
-A chain2 -m comment --comment "comment2"
|
179
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
180
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
181
|
+
COMMIT
|
182
|
+
*table2
|
183
|
+
:chain3 ACCEPT [0:0]
|
184
|
+
-A chain3 -m comment --comment "comment3"
|
185
|
+
-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT
|
186
|
+
-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT
|
187
|
+
:chain4 ACCEPT [0:0]
|
188
|
+
-A chain4 -m comment --comment "comment4"
|
189
|
+
-A chain4 -p tcp -m tcp --dport 7 -j ACCEPT
|
190
|
+
-A chain4 -p tcp -m tcp --dport 8 -j ACCEPT
|
191
|
+
COMMIT
|
192
|
+
*table3
|
193
|
+
:chain5 ACCEPT [0:0]
|
194
|
+
-A chain5 -m comment --comment "comment5"
|
195
|
+
-A chain5 -p tcp -m tcp --dport 9 -j ACCEPT
|
196
|
+
-A chain5 -p tcp -m tcp --dport 10 -j ACCEPT
|
197
|
+
:chain6 ACCEPT [0:0]
|
198
|
+
-A chain6 -m comment --comment "comment6"
|
199
|
+
-A chain6 -p tcp -m tcp --dport 11 -j ACCEPT
|
200
|
+
-A chain6 -p tcp -m tcp --dport 12 -j ACCEPT
|
201
|
+
COMMIT
|
202
|
+
EOS
|
203
|
+
)
|
204
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
205
|
+
|
206
|
+
assert_equal(
|
207
|
+
false,
|
208
|
+
comparison.equal?,
|
209
|
+
'Set of tables with one having an additional table should evaluate as unequal.'
|
210
|
+
)
|
211
|
+
assert_equal(
|
212
|
+
comparison.as_array,
|
213
|
+
[
|
214
|
+
"New table: table3",
|
215
|
+
":chain5 ACCEPT",
|
216
|
+
":chain6 ACCEPT",
|
217
|
+
"-A chain5 -m comment --comment \"comment5\"",
|
218
|
+
"-A chain5 -p tcp -m tcp --dport 9 -j ACCEPT",
|
219
|
+
"-A chain5 -p tcp -m tcp --dport 10 -j ACCEPT",
|
220
|
+
"-A chain6 -m comment --comment \"comment6\"",
|
221
|
+
"-A chain6 -p tcp -m tcp --dport 11 -j ACCEPT",
|
222
|
+
"-A chain6 -p tcp -m tcp --dport 12 -j ACCEPT"
|
223
|
+
],
|
224
|
+
'Array output of tables with one having an additional table should evaluate to known values.'
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_differing_table
|
229
|
+
iptables2 = IPTables::Tables.new(
|
230
|
+
<<-EOS.dedent
|
231
|
+
*table1
|
232
|
+
:chain1 ACCEPT [0:0]
|
233
|
+
-A chain1 -m comment --comment "comment1"
|
234
|
+
-A chain1 -p tcp -m tcp --dport 11 -j ACCEPT
|
235
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
236
|
+
:chain2 ACCEPT [0:0]
|
237
|
+
-A chain2 -m comment --comment "comment2"
|
238
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
239
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
240
|
+
COMMIT
|
241
|
+
*table2
|
242
|
+
:chain3 ACCEPT [0:0]
|
243
|
+
-A chain3 -m comment --comment "comment3"
|
244
|
+
-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT
|
245
|
+
-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT
|
246
|
+
:chain4 ACCEPT [0:0]
|
247
|
+
-A chain4 -m comment --comment "comment4"
|
248
|
+
-A chain4 -p tcp -m tcp --dport 7 -j ACCEPT
|
249
|
+
-A chain4 -p tcp -m tcp --dport 8 -j ACCEPT
|
250
|
+
COMMIT
|
251
|
+
EOS
|
252
|
+
)
|
253
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
254
|
+
|
255
|
+
assert_equal(
|
256
|
+
false,
|
257
|
+
comparison.equal?,
|
258
|
+
'Set of tables with one having a differing rule should evaluate as unequal.'
|
259
|
+
)
|
260
|
+
assert_equal(
|
261
|
+
comparison.as_array,
|
262
|
+
[
|
263
|
+
"Changed table: table1",
|
264
|
+
"Changed chain: chain1",
|
265
|
+
"-1: -A chain1 -p tcp -m tcp --dport 1 -j ACCEPT",
|
266
|
+
"+1: -A chain1 -p tcp -m tcp --dport 11 -j ACCEPT"
|
267
|
+
],
|
268
|
+
'Array output of tables with one having a differing rule should evaluate to known values.'
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_differing_chain_comments
|
273
|
+
iptables2 = IPTables::Tables.new(
|
274
|
+
<<-EOS.dedent
|
275
|
+
*table1
|
276
|
+
:chain1 ACCEPT [0:0]
|
277
|
+
-A chain1 -m comment --comment "changed comment1"
|
278
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
279
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
280
|
+
:chain2 ACCEPT [0:0]
|
281
|
+
-A chain2 -m comment --comment "comment2"
|
282
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
283
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
284
|
+
COMMIT
|
285
|
+
*table2
|
286
|
+
:chain3 ACCEPT [0:0]
|
287
|
+
-A chain3 -m comment --comment "comment3"
|
288
|
+
-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT
|
289
|
+
-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT
|
290
|
+
:chain4 ACCEPT [0:0]
|
291
|
+
-A chain4 -m comment --comment "comment4"
|
292
|
+
-A chain4 -p tcp -m tcp --dport 7 -j ACCEPT
|
293
|
+
-A chain4 -p tcp -m tcp --dport 8 -j ACCEPT
|
294
|
+
COMMIT
|
295
|
+
EOS
|
296
|
+
)
|
297
|
+
comparison = IPTables::TablesComparison.new(@iptables1, iptables2)
|
298
|
+
|
299
|
+
comparison.ignore_comments
|
300
|
+
assert(
|
301
|
+
comparison.equal?,
|
302
|
+
'Set of tables that differ only by comments should evaluate as equal when ignoring comments.'
|
303
|
+
)
|
304
|
+
assert_equal(
|
305
|
+
comparison.as_array,
|
306
|
+
[],
|
307
|
+
'Array output of tables that differ only by comments should evaluate as empty when ignoring comments.'
|
308
|
+
)
|
309
|
+
|
310
|
+
comparison.include_comments
|
311
|
+
assert_equal(
|
312
|
+
false,
|
313
|
+
comparison.equal?,
|
314
|
+
'Set of tables that differ only by comments should evaluate as unequal when including comments.'
|
315
|
+
)
|
316
|
+
assert_equal(
|
317
|
+
comparison.as_array,
|
318
|
+
[
|
319
|
+
"Changed table: table1",
|
320
|
+
"Changed chain: chain1",
|
321
|
+
"-0: -A chain1 -m comment --comment \"comment1\"",
|
322
|
+
"+0: -A chain1 -m comment --comment \"changed comment1\""
|
323
|
+
],
|
324
|
+
'Array output of tables that differ only by comments should evaluate to known values when ignoring comments.'
|
325
|
+
)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
class TestTableComparison < Test::Unit::TestCase
|
330
|
+
def setup
|
331
|
+
@test_iptables =
|
332
|
+
<<-EOS.dedent
|
333
|
+
*table1
|
334
|
+
:chain1 ACCEPT [0:0]
|
335
|
+
-A chain1 -m comment --comment "comment1"
|
336
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
337
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
338
|
+
:chain2 ACCEPT [0:0]
|
339
|
+
-A chain2 -m comment --comment "comment2"
|
340
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
341
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
342
|
+
COMMIT
|
343
|
+
EOS
|
344
|
+
@table1 = IPTables::Tables.new( @test_iptables ).tables['table1']
|
345
|
+
end
|
346
|
+
|
347
|
+
def test_invalid
|
348
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Table object as first parameter' ) {
|
349
|
+
IPTables::TableComparison.new(nil, @table1)
|
350
|
+
}
|
351
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Table object as second parameter' ) {
|
352
|
+
IPTables::TableComparison.new(@table1, nil)
|
353
|
+
}
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_equal
|
357
|
+
test_iptables2 = IPTables::Tables.new( @test_iptables )
|
358
|
+
table2 = test_iptables2.tables['table1']
|
359
|
+
comparison = IPTables::TableComparison.new(@table1, table2)
|
360
|
+
|
361
|
+
assert(
|
362
|
+
comparison.equal?,
|
363
|
+
'Tables with same chains should evaluate as equal.'
|
364
|
+
)
|
365
|
+
|
366
|
+
assert_equal(
|
367
|
+
[],
|
368
|
+
comparison.as_array,
|
369
|
+
'When compared as array, tables with identical chains should return empty array.'
|
370
|
+
)
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_unequal_name
|
374
|
+
test_iptables2 = IPTables::Tables.new(
|
375
|
+
<<-EOS.dedent
|
376
|
+
*table2
|
377
|
+
:chain1 ACCEPT [0:0]
|
378
|
+
-A chain1 -m comment --comment "comment1"
|
379
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
380
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
381
|
+
:chain2 ACCEPT [0:0]
|
382
|
+
-A chain2 -m comment --comment "comment2"
|
383
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
384
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
385
|
+
COMMIT
|
386
|
+
EOS
|
387
|
+
)
|
388
|
+
table2 = test_iptables2.tables['table2']
|
389
|
+
assert_raise( RuntimeError, 'compared table names should match' ) {
|
390
|
+
IPTables::TableComparison.new(@table1, table2)
|
391
|
+
}
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_missing_chain
|
395
|
+
test_iptables2 = IPTables::Tables.new(
|
396
|
+
<<-EOS.dedent
|
397
|
+
*table1
|
398
|
+
:chain1 ACCEPT [0:0]
|
399
|
+
-A chain1 -m comment --comment "comment1"
|
400
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
401
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
402
|
+
COMMIT
|
403
|
+
EOS
|
404
|
+
)
|
405
|
+
table2 = test_iptables2.tables['table1']
|
406
|
+
comparison = IPTables::TableComparison.new(@table1, table2)
|
407
|
+
|
408
|
+
assert_equal(
|
409
|
+
false,
|
410
|
+
comparison.equal?,
|
411
|
+
'Tables with missing chains should evaluate as unequal.'
|
412
|
+
)
|
413
|
+
|
414
|
+
assert_equal(
|
415
|
+
[ 'chain2' ],
|
416
|
+
comparison.missing,
|
417
|
+
'Two compared tables with one chain missing should show this.'
|
418
|
+
)
|
419
|
+
|
420
|
+
assert_equal(
|
421
|
+
[
|
422
|
+
'Changed table: table1',
|
423
|
+
'Missing chain:',
|
424
|
+
':chain2 ACCEPT',
|
425
|
+
'-A chain2 -m comment --comment "comment2"',
|
426
|
+
'-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT',
|
427
|
+
'-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT'
|
428
|
+
],
|
429
|
+
comparison.as_array,
|
430
|
+
'When compared as array, two compared tables with one chain missing should show this.'
|
431
|
+
)
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_additional_chain
|
435
|
+
test_iptables2 = IPTables::Tables.new(
|
436
|
+
<<-EOS.dedent
|
437
|
+
*table1
|
438
|
+
:chain1 ACCEPT [0:0]
|
439
|
+
-A chain1 -m comment --comment "comment1"
|
440
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
441
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
442
|
+
:chain2 ACCEPT [0:0]
|
443
|
+
-A chain2 -m comment --comment "comment2"
|
444
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
445
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
446
|
+
:chain3 ACCEPT [0:0]
|
447
|
+
-A chain3 -m comment --comment "comment3"
|
448
|
+
-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT
|
449
|
+
-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT
|
450
|
+
COMMIT
|
451
|
+
EOS
|
452
|
+
)
|
453
|
+
table2 = test_iptables2.tables['table1']
|
454
|
+
comparison = IPTables::TableComparison.new(@table1, table2)
|
455
|
+
|
456
|
+
assert_equal(
|
457
|
+
false,
|
458
|
+
comparison.equal?,
|
459
|
+
'Tables with additional chains should evaluate as unequal.'
|
460
|
+
)
|
461
|
+
|
462
|
+
assert_equal(
|
463
|
+
[ 'chain3' ],
|
464
|
+
comparison.new,
|
465
|
+
'Two compared tables with one additional chain should show this.'
|
466
|
+
)
|
467
|
+
|
468
|
+
assert_equal(
|
469
|
+
[
|
470
|
+
'Changed table: table1',
|
471
|
+
'New chain:',
|
472
|
+
':chain3 ACCEPT',
|
473
|
+
'-A chain3 -m comment --comment "comment3"',
|
474
|
+
'-A chain3 -p tcp -m tcp --dport 5 -j ACCEPT',
|
475
|
+
'-A chain3 -p tcp -m tcp --dport 6 -j ACCEPT'
|
476
|
+
],
|
477
|
+
comparison.as_array,
|
478
|
+
'When compared as array, two compared tables with one additional chain should show this.'
|
479
|
+
)
|
480
|
+
end
|
481
|
+
|
482
|
+
def test_differing_chain
|
483
|
+
test_iptables2 = IPTables::Tables.new(
|
484
|
+
<<-EOS.dedent
|
485
|
+
*table1
|
486
|
+
:chain1 ACCEPT [0:0]
|
487
|
+
-A chain1 -m comment --comment "comment1"
|
488
|
+
-A chain1 -p tcp -m tcp --dport 11 -j ACCEPT
|
489
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
490
|
+
:chain2 ACCEPT [0:0]
|
491
|
+
-A chain2 -m comment --comment "comment2"
|
492
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
493
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
494
|
+
COMMIT
|
495
|
+
EOS
|
496
|
+
)
|
497
|
+
table2 = test_iptables2.tables['table1']
|
498
|
+
comparison = IPTables::TableComparison.new(@table1, table2)
|
499
|
+
|
500
|
+
assert_equal(
|
501
|
+
false,
|
502
|
+
comparison.equal?,
|
503
|
+
'Tables with additional chains should evaluate as unequal.'
|
504
|
+
)
|
505
|
+
|
506
|
+
assert_equal(
|
507
|
+
[
|
508
|
+
'Changed table: table1',
|
509
|
+
'Changed chain: chain1',
|
510
|
+
'-1: -A chain1 -p tcp -m tcp --dport 1 -j ACCEPT',
|
511
|
+
'+1: -A chain1 -p tcp -m tcp --dport 11 -j ACCEPT'
|
512
|
+
],
|
513
|
+
comparison.as_array,
|
514
|
+
'When compared as array, two compared tables with one changed chain rule should show this.'
|
515
|
+
)
|
516
|
+
end
|
517
|
+
|
518
|
+
def test_differing_chain_comments
|
519
|
+
test_iptables2 = IPTables::Tables.new(
|
520
|
+
<<-EOS.dedent
|
521
|
+
*table1
|
522
|
+
:chain1 ACCEPT [0:0]
|
523
|
+
-A chain1 -m comment --comment "comment1"
|
524
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
525
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
526
|
+
:chain2 ACCEPT [0:0]
|
527
|
+
-A chain2 -m comment --comment "changed comment2"
|
528
|
+
-A chain2 -p tcp -m tcp --dport 3 -j ACCEPT
|
529
|
+
-A chain2 -p tcp -m tcp --dport 4 -j ACCEPT
|
530
|
+
COMMIT
|
531
|
+
EOS
|
532
|
+
)
|
533
|
+
table2 = test_iptables2.tables['table1']
|
534
|
+
comparison = IPTables::TableComparison.new(@table1, table2)
|
535
|
+
|
536
|
+
comparison.ignore_comments
|
537
|
+
assert(
|
538
|
+
comparison.equal?,
|
539
|
+
'Tables with chains that differ only by comments should evaluate as equal when ignoring comments.'
|
540
|
+
)
|
541
|
+
|
542
|
+
comparison.include_comments
|
543
|
+
assert_equal(
|
544
|
+
false,
|
545
|
+
comparison.equal?,
|
546
|
+
'Tables with chains that differ only by comments should evaluate as unequal when including comments.'
|
547
|
+
)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
class TestChainComparison < Test::Unit::TestCase
|
552
|
+
def setup
|
553
|
+
@iptables_text =
|
554
|
+
<<-EOS.dedent
|
555
|
+
*table1
|
556
|
+
:chain1 ACCEPT [0:0]
|
557
|
+
-A chain1 -m comment --comment "comment1"
|
558
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
559
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
560
|
+
COMMIT
|
561
|
+
EOS
|
562
|
+
@table1_chain = IPTables::Tables.new(@iptables_text).tables['table1'].chains['chain1']
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_invalid
|
566
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Chain object as first parameter' ) {
|
567
|
+
IPTables::ChainComparison.new(nil, @table1_chain)
|
568
|
+
}
|
569
|
+
assert_raise( RuntimeError, 'should require valid IPTables::Chain object as second parameter' ) {
|
570
|
+
IPTables::ChainComparison.new(@table1_chain, nil)
|
571
|
+
}
|
572
|
+
end
|
573
|
+
|
574
|
+
def test_equal
|
575
|
+
test_iptables2 = IPTables::Tables.new(@iptables_text)
|
576
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain1']
|
577
|
+
comparison = IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
578
|
+
|
579
|
+
assert(
|
580
|
+
comparison.equal?,
|
581
|
+
'Chains with same rules and policies should evaluate as equal.'
|
582
|
+
)
|
583
|
+
|
584
|
+
assert_equal(
|
585
|
+
[],
|
586
|
+
comparison.as_array,
|
587
|
+
'When compared as array, chains with same rules and policies should return empty array.'
|
588
|
+
)
|
589
|
+
end
|
590
|
+
|
591
|
+
def test_unequal_names
|
592
|
+
test_iptables2 = IPTables::Tables.new(
|
593
|
+
<<-EOS.dedent
|
594
|
+
*table1
|
595
|
+
:chain2 ACCEPT [0:0]
|
596
|
+
-A chain2 -m comment --comment "comment1"
|
597
|
+
-A chain2 -p tcp -m tcp --dport 1 -j ACCEPT
|
598
|
+
-A chain2 -p tcp -m tcp --dport 2 -j ACCEPT
|
599
|
+
COMMIT
|
600
|
+
EOS
|
601
|
+
)
|
602
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain2']
|
603
|
+
assert_raise( RuntimeError, 'first and second chain should have same name' ) {
|
604
|
+
IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
605
|
+
}
|
606
|
+
end
|
607
|
+
|
608
|
+
def test_unequal_comments
|
609
|
+
test_iptables2 = IPTables::Tables.new(
|
610
|
+
<<-EOS.dedent
|
611
|
+
*table1
|
612
|
+
:chain1 ACCEPT [0:0]
|
613
|
+
-A chain1 -m comment --comment "differing comment1"
|
614
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
615
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
616
|
+
COMMIT
|
617
|
+
EOS
|
618
|
+
)
|
619
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain1']
|
620
|
+
comparison = IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
621
|
+
|
622
|
+
comparison.ignore_comments
|
623
|
+
assert(
|
624
|
+
comparison.equal?,
|
625
|
+
'When ignoring comments, chains with same rules/policies but differing comments should evaluate as equal.'
|
626
|
+
)
|
627
|
+
|
628
|
+
comparison.include_comments
|
629
|
+
assert_equal(
|
630
|
+
false,
|
631
|
+
comparison.equal?,
|
632
|
+
'When including comments, chains with same rules/policies but differing comments should evaluate as unequal.'
|
633
|
+
)
|
634
|
+
assert_equal(
|
635
|
+
{0=>'-A chain1 -m comment --comment "comment1"'},
|
636
|
+
comparison.missing,
|
637
|
+
'When including comments, chains with same rules/policies but differing comments should have one missing rule.'
|
638
|
+
)
|
639
|
+
assert_equal(
|
640
|
+
{0=>'-A chain1 -m comment --comment "differing comment1"'},
|
641
|
+
comparison.new,
|
642
|
+
'When including comments, chains with same rules/policies but differing comments should have one new rule.'
|
643
|
+
)
|
644
|
+
|
645
|
+
assert_equal(
|
646
|
+
[
|
647
|
+
'Changed chain: chain1',
|
648
|
+
'-0: -A chain1 -m comment --comment "comment1"',
|
649
|
+
'+0: -A chain1 -m comment --comment "differing comment1"',
|
650
|
+
],
|
651
|
+
comparison.as_array,
|
652
|
+
'When compared as array, chains with changed rules should show this.'
|
653
|
+
)
|
654
|
+
end
|
655
|
+
|
656
|
+
def test_missing_rules
|
657
|
+
test_iptables2 = IPTables::Tables.new(
|
658
|
+
<<-EOS.dedent
|
659
|
+
*table1
|
660
|
+
:chain1 ACCEPT [0:0]
|
661
|
+
-A chain1 -m comment --comment "comment1"
|
662
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
663
|
+
COMMIT
|
664
|
+
EOS
|
665
|
+
)
|
666
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain1']
|
667
|
+
comparison = IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
668
|
+
|
669
|
+
assert_equal(
|
670
|
+
{
|
671
|
+
2=>"-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT"
|
672
|
+
},
|
673
|
+
comparison.missing,
|
674
|
+
'Chains with missing rules should show this.'
|
675
|
+
)
|
676
|
+
|
677
|
+
assert_equal(
|
678
|
+
[
|
679
|
+
'Changed chain: chain1',
|
680
|
+
'-2: -A chain1 -p tcp -m tcp --dport 2 -j ACCEPT'
|
681
|
+
],
|
682
|
+
comparison.as_array,
|
683
|
+
'When compared as array, chains with missing rules should show this.'
|
684
|
+
)
|
685
|
+
end
|
686
|
+
|
687
|
+
def test_additional_rules
|
688
|
+
test_iptables2 = IPTables::Tables.new(
|
689
|
+
<<-EOS.dedent
|
690
|
+
*table1
|
691
|
+
:chain1 ACCEPT [0:0]
|
692
|
+
-A chain1 -m comment --comment "comment1"
|
693
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
694
|
+
-A chain1 -p tcp -m tcp --dport 11 -j ACCEPT
|
695
|
+
-A chain1 -p tcp -m tcp --dport 12 -j ACCEPT
|
696
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
697
|
+
COMMIT
|
698
|
+
EOS
|
699
|
+
)
|
700
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain1']
|
701
|
+
comparison = IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
702
|
+
|
703
|
+
assert_equal(
|
704
|
+
{
|
705
|
+
2=>"-A chain1 -p tcp -m tcp --dport 11 -j ACCEPT",
|
706
|
+
3=>"-A chain1 -p tcp -m tcp --dport 12 -j ACCEPT"
|
707
|
+
},
|
708
|
+
comparison.new,
|
709
|
+
'Chains with additional rules should show this.'
|
710
|
+
)
|
711
|
+
|
712
|
+
assert_equal(
|
713
|
+
[
|
714
|
+
'Changed chain: chain1',
|
715
|
+
'+2: -A chain1 -p tcp -m tcp --dport 11 -j ACCEPT',
|
716
|
+
'+3: -A chain1 -p tcp -m tcp --dport 12 -j ACCEPT'
|
717
|
+
],
|
718
|
+
comparison.as_array,
|
719
|
+
'When compared as array, chains with additional rules should show this.'
|
720
|
+
)
|
721
|
+
end
|
722
|
+
|
723
|
+
def test_new_policy
|
724
|
+
test_iptables2 = IPTables::Tables.new(
|
725
|
+
<<-EOS.dedent
|
726
|
+
*table1
|
727
|
+
:chain1 REJECT [0:0]
|
728
|
+
-A chain1 -m comment --comment "comment1"
|
729
|
+
-A chain1 -p tcp -m tcp --dport 1 -j ACCEPT
|
730
|
+
-A chain1 -p tcp -m tcp --dport 2 -j ACCEPT
|
731
|
+
COMMIT
|
732
|
+
EOS
|
733
|
+
)
|
734
|
+
table2_chain = test_iptables2.tables['table1'].chains['chain1']
|
735
|
+
comparison = IPTables::ChainComparison.new(@table1_chain, table2_chain)
|
736
|
+
|
737
|
+
assert(
|
738
|
+
comparison.new_policy?,
|
739
|
+
'When compared, chains with new policy should show this.'
|
740
|
+
)
|
741
|
+
|
742
|
+
assert_equal(
|
743
|
+
[
|
744
|
+
'Changed chain: chain1',
|
745
|
+
'New policy: REJECT'
|
746
|
+
],
|
747
|
+
comparison.as_array,
|
748
|
+
'When compared as array, chains with new policy should show this.'
|
749
|
+
)
|
750
|
+
end
|
751
|
+
end
|