iptables-ruby 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ require 'common'
2
+
3
+ class TestConfiguration < Test::Unit::TestCase
4
+ def setup
5
+ @test_config = IPTables::Configuration.new()
6
+ end
7
+
8
+ def test_initialize
9
+ assert_nothing_raised( RuntimeError ) { IPTables::Configuration.new() }
10
+ end
11
+
12
+ def test_parse_files
13
+ assert_raise( RuntimeError ) { IPTables::Configuration.new('foobar') }
14
+ # don't know how to test reading .json files
15
+ # without being able to test reading json, can not complete testing
16
+ #assert_nothing_raised( RuntimeError ) { IPTables::Configuration.new('test/test_config.json') }
17
+ end
18
+
19
+ def test_policy
20
+ assert_raise( RuntimeError ) { @test_config.policy }
21
+ assert_equal({}, @test_config.policy({}))
22
+ end
23
+
24
+ def test_policy6
25
+ assert_raise( RuntimeError ) { @test_config.policy6 }
26
+ assert_equal({}, @test_config.policy6({}))
27
+ end
28
+
29
+ def test_interpolations
30
+ assert_raise( RuntimeError ) { @test_config.interpolations }
31
+ end
32
+
33
+ def test_primitives
34
+ assert_raise( RuntimeError ) { @test_config.primitives }
35
+ end
36
+
37
+ def test_rules
38
+ assert_raise( RuntimeError ) { @test_config.rules }
39
+ assert_equal({}, @test_config.rules({}))
40
+ end
41
+
42
+ def test_services
43
+ assert_raise( RuntimeError ) { @test_config.services }
44
+ end
45
+
46
+ def test_macros
47
+ assert_raise( RuntimeError ) { @test_config.macros }
48
+ end
49
+
50
+ def test_converge_firewall
51
+ assert_raise( RuntimeError ) { @test_config.converge_firewall() }
52
+
53
+ test_policy = IPTables::Tables.new({
54
+ 'table1' => {
55
+ 'chain1' => {
56
+ 'policy' => 'ACCEPT',
57
+ 'rules' => [
58
+ '-j ACCEPT'
59
+ ]
60
+ }
61
+ }
62
+ }, @test_config)
63
+ @test_config.policy(test_policy)
64
+
65
+ test_rules = IPTables::Tables.new({
66
+ 'table1' => { 'chain1' => { 'policy' => 'DROP' } }
67
+ }, @test_config)
68
+ @test_config.rules(test_policy)
69
+
70
+ assert_instance_of(IPTables::Tables, @test_config.converge_firewall)
71
+ end
72
+ end
@@ -0,0 +1,116 @@
1
+ require 'common'
2
+
3
+ class TestMacros < Test::Unit::TestCase
4
+ def test_initialize
5
+ assert_equal({}, IPTables::Macros.new({}).named)
6
+ assert_instance_of(IPTables::Macro, IPTables::Macros.new({'test_macro' => {}}).named['test_macro'])
7
+ end
8
+ end
9
+
10
+ class TestMacro < Test::Unit::TestCase
11
+ def test_initialize
12
+ assert_raise( RuntimeError ) { IPTables::Macro.new('test_macro', 1) }
13
+
14
+ assert_equal('test_macro', IPTables::Macro.new('test_macro', {}).name)
15
+ assert_equal([], IPTables::Macro.new('test_macro', []).children)
16
+ assert_equal([{}], IPTables::Macro.new('test_macro', {}).children)
17
+ assert_equal([{'raw' => ''}], IPTables::Macro.new('test_macro', '').children)
18
+ assert_equal([{'raw' => ''}], IPTables::Macro.new('test_macro', [{'raw' => ''}]).children)
19
+ end
20
+ end
21
+
22
+ class TestServices < Test::Unit::TestCase
23
+ def test_initialize
24
+ assert_equal({}, IPTables::Services.new({}).named)
25
+ assert_instance_of(IPTables::Service, IPTables::Services.new({'test_service' => 1}).named['test_service'])
26
+ end
27
+ end
28
+
29
+ class TestService < Test::Unit::TestCase
30
+ def test_initialize
31
+ assert_raise( RuntimeError ) { IPTables::Service.new('test_service', 1.0) }
32
+ assert_raise( RuntimeError ) { IPTables::Service.new('test_service', []) }
33
+ assert_raise( RuntimeError ) { IPTables::Service.new('test_service', {}) }
34
+
35
+ assert_equal('test_service', IPTables::Service.new('test_service', 1).name)
36
+ end
37
+
38
+ def test_handle_string
39
+ assert_equal([{"comment"=>"_ test_service"}, {"raw"=>"-j ACCEPT"}], IPTables::Service.new('test_service', '-j ACCEPT').children)
40
+ end
41
+
42
+ def test_handle_array
43
+ assert_equal([{"comment"=>"_ test_service"}, {"raw"=>"-j ACCEPT"}], IPTables::Service.new('test_service', [{'raw' => '-j ACCEPT'}]).children)
44
+ end
45
+
46
+ def test_handle_hash
47
+ assert_equal([{"raw"=>"-j ACCEPT", "service_name"=>"test_service"}], IPTables::Service.new('test_service', {'raw' => '-j ACCEPT'}).children)
48
+ end
49
+
50
+ def test_handle_integer
51
+ assert_equal(
52
+ [
53
+ {"comment"=>"_ Port 1 - test_service"},
54
+ {"raw"=> "-p tcp -m tcp --sport 1024:65535 --dport 1 -m state --state NEW,ESTABLISHED -j ACCEPT"}
55
+ ],
56
+ IPTables::Service.new('test_service', 1).children
57
+ )
58
+ end
59
+ end
60
+
61
+ class TestInterpolations < Test::Unit::TestCase
62
+ def setup
63
+ @new = IPTables::Interpolations.new({})
64
+ end
65
+
66
+ def test_initialize
67
+ assert_equal({}, @new.named)
68
+ end
69
+
70
+ def test_add
71
+ @new.add('test_interpolation')
72
+ assert_instance_of(IPTables::Interpolation, @new.named['test_interpolation'])
73
+ end
74
+
75
+ def test_children
76
+ @new.add('test_interpolation')
77
+ assert_equal([{"raw"=>"test_interpolation"}], @new.children('test_interpolation'))
78
+ assert_equal([{"raw"=>"test_interpolation"}], @new.children(['test_interpolation']))
79
+ end
80
+ end
81
+
82
+ class TestInterpolation < Test::Unit::TestCase
83
+ def setup
84
+ @config = IPTables::Configuration.new
85
+ @config.primitives(
86
+ IPTables::Primitives.new({
87
+ 'branch' => { 'leaf1' => 'leaf1_value' },
88
+ 'leaf2' => 'leaf2_value',
89
+ 'array1' => [ 'array_value1', 'array_value2' ]
90
+ })
91
+ )
92
+ @config.interpolations(
93
+ IPTables::Interpolations.new( @config.primitives )
94
+ )
95
+ end
96
+
97
+ def test_add_child
98
+ assert_raise( RuntimeError ) { IPTables::Interpolation.new(@config.interpolations, '<% missing %>') }
99
+ #assert_raise( RuntimeError ) { IPTables::Interpolation.new(@config.interpolations, '<% branch %>') }
100
+ end
101
+
102
+ def test_children
103
+ assert_equal(
104
+ 'junk leaf1_value',
105
+ IPTables::Interpolation.new(@config.interpolations, 'junk <% branch.leaf1 %>').children
106
+ )
107
+ assert_equal(
108
+ 'leaf2_value stuff',
109
+ IPTables::Interpolation.new(@config.interpolations, '<% leaf2 %> stuff').children
110
+ )
111
+ assert_equal(
112
+ ["before array_value1 after", "before array_value2 after"],
113
+ IPTables::Interpolation.new(@config.interpolations, 'before <% array1 %> after').children
114
+ )
115
+ end
116
+ end
@@ -0,0 +1,35 @@
1
+ require 'common'
2
+
3
+ class TestPrimitives < Test::Unit::TestCase
4
+ def setup
5
+ test_data = {
6
+ 'first' => {
7
+ 'second' => 'blah'
8
+ }
9
+ }
10
+ @primitives = IPTables::Primitives.new(test_data)
11
+ end
12
+
13
+ def test_initialize
14
+ assert_raise( RuntimeError ) { IPTables::Primitives.new(1) }
15
+ assert_raise( RuntimeError ) { IPTables::Primitives.new({'test_primitive', 1}) }
16
+
17
+ assert_equal({}, IPTables::Primitives.new({}).children)
18
+ assert_equal({'test_primitive' => []}, IPTables::Primitives.new({'test_primitive' => []}).children)
19
+
20
+ primitives = IPTables::Primitives.new({'test_primitive' => {}})
21
+ assert_kind_of(IPTables::Primitives, primitives.children['test_primitive'])
22
+ end
23
+
24
+ def test_substitute
25
+ assert_raise( RuntimeError, 'a missing substitution is an error' ) { @primitives.substitute('missing') }
26
+ assert_raise( RuntimeError, 'a partial substitution is an error' ) { @primitives.substitute('first') }
27
+ assert_equal('blah', @primitives.substitute('first.second'))
28
+ end
29
+
30
+ def test_has_primitive
31
+ assert(@primitives.has_primitive?('first.second'), 'An existing primitive should say it exists')
32
+ assert_equal(false, @primitives.has_primitive?('missing'), 'A missing primitive should say it does not exist')
33
+ assert_equal(false, @primitives.has_primitive?('first'), 'A partial primitive should say it does not exist')
34
+ end
35
+ end
data/test/tc_tables.rb ADDED
@@ -0,0 +1,652 @@
1
+ require 'common'
2
+
3
+ class TestTables < Test::Unit::TestCase
4
+ def test_initialize
5
+ assert_raise( RuntimeError ) { IPTables::Tables.new(1) }
6
+
7
+ test_iptables = IPTables::Tables.new({
8
+ 'table1' => {},
9
+ 'table2' => nil
10
+ })
11
+ assert_kind_of(IPTables::Table, test_iptables.tables['table1'])
12
+ assert_nil(test_iptables.tables['table2'])
13
+ end
14
+
15
+ def test_null_table_as_array
16
+ test_iptables1 = IPTables::Tables.new( {
17
+ 'nat' => nil,
18
+ })
19
+ assert_equal(
20
+ [],
21
+ test_iptables1.as_array,
22
+ 'null table should produce no policy and empty ruleset'
23
+ )
24
+ end
25
+
26
+ def test_as_array_without_comments
27
+ config = IPTables::Configuration.new()
28
+ tables = IPTables::Tables.new({
29
+ 'filter' => {
30
+ 'INPUT' => {
31
+ 'policy' => 'ACCEPT',
32
+ 'rules' => [
33
+ { 'comment' => 'foobar' }
34
+ ]
35
+ }
36
+ }
37
+ }, config)
38
+ assert_equal(
39
+ [
40
+ "*filter",
41
+ ":INPUT ACCEPT",
42
+ "COMMIT"
43
+ ],
44
+ tables.as_array(comments = false),
45
+ 'if comments are excluded, they should not appear in output'
46
+ )
47
+ end
48
+
49
+ def test_ignore_comments_in_policy_fw
50
+ config = IPTables::Configuration.new
51
+ config.primitives(
52
+ IPTables::Primitives.new({
53
+ 'branch' => { 'leaf1' => 'leaf1_value' },
54
+ 'leaf2' => 'leaf2_value',
55
+ })
56
+ )
57
+ config.interpolations(
58
+ IPTables::Interpolations.new( config.primitives )
59
+ )
60
+ config.services(
61
+ IPTables::Services.new({
62
+ 'service1' => 1111,
63
+ })
64
+ )
65
+ config.macros(
66
+ IPTables::Macros.new({
67
+ 'macro1' => [
68
+ { 'comment' => 'A comment in a macro' }
69
+ ]
70
+ })
71
+ )
72
+ config.policy(
73
+ IPTables::Tables.new({
74
+ 'filter' => {
75
+ 'INPUT' => {
76
+ 'policy' => 'ACCEPT',
77
+ 'rules' => [
78
+ { 'comment' => 'foobar' },
79
+ '-j ACCEPT',
80
+ { 'node_addition_points' => [ 'INPUT' ] },
81
+ { 'macro' => 'macro1' },
82
+ { 'service' => 'service1' },
83
+ ]
84
+ }
85
+ }
86
+ }, config)
87
+ )
88
+ config.rules(
89
+ IPTables::Tables.new({
90
+ 'filter' => {
91
+ 'INPUT' => {
92
+ 'additions' => [
93
+ { 'comment' => 'a comment from an addition' },
94
+ {
95
+ 'service_name' => 'a test service',
96
+ 'service_tcp' => 2222
97
+ },
98
+ ]
99
+ }
100
+ }
101
+ }, config)
102
+ )
103
+ converged_fw = config.converge_firewall
104
+ assert_equal(
105
+ [
106
+ '*filter',
107
+ ':INPUT ACCEPT',
108
+ '-A INPUT -j ACCEPT',
109
+ '-A INPUT -p tcp -m tcp --sport 1024:65535 --dport 2222 -m state --state NEW,ESTABLISHED -j ACCEPT',
110
+ '-A INPUT -p tcp -m tcp --sport 1024:65535 --dport 1111 -m state --state NEW,ESTABLISHED -j ACCEPT',
111
+ 'COMMIT'
112
+ ],
113
+ converged_fw.as_array(false),
114
+ 'when excluding comments from a converged firewall, should see no comments'
115
+ )
116
+ end
117
+
118
+ def test_two_tables_as_array
119
+ test_iptables1 = IPTables::Tables.new( {
120
+ 'nat' => {
121
+ 'INPUT' => {
122
+ 'policy' => 'ACCEPT'
123
+ }
124
+ },
125
+ 'filter' => {
126
+ 'INPUT' => {
127
+ 'policy' => 'ACCEPT'
128
+ }
129
+ },
130
+ })
131
+ assert_equal(
132
+ [
133
+ "*filter",
134
+ ":INPUT ACCEPT",
135
+ "COMMIT",
136
+ "*nat",
137
+ ":INPUT ACCEPT",
138
+ "COMMIT"
139
+ ],
140
+ test_iptables1.as_array,
141
+ 'two tables should produce consistent array output'
142
+ )
143
+ end
144
+
145
+ def test_table_only_with_policy_as_array
146
+ test_iptables1 = IPTables::Tables.new( {
147
+ 'nat' => {
148
+ 'INPUT' => {
149
+ 'policy' => 'ACCEPT'
150
+ }
151
+ },
152
+ })
153
+ assert_equal(
154
+ [
155
+ "*nat",
156
+ ":INPUT ACCEPT",
157
+ "COMMIT"
158
+ ],
159
+ test_iptables1.as_array,
160
+ 'null table to array should produce an empty array'
161
+ )
162
+ end
163
+
164
+ def test_merge_table_to_null_table
165
+ test_iptables1 = IPTables::Tables.new( {
166
+ 'table1' => nil,
167
+ })
168
+ test_iptables2 = IPTables::Tables.new( {
169
+ 'table1' => {
170
+ 'INPUT' => {
171
+ 'policy' => 'ACCEPT'
172
+ }
173
+ },
174
+ })
175
+ test_iptables1.merge(test_iptables2)
176
+ assert_kind_of(IPTables::Table, test_iptables1.tables['table1'], 'after merge, table1 should be a Table')
177
+ assert_equal(
178
+ [
179
+ "*table1",
180
+ ":INPUT ACCEPT",
181
+ "COMMIT"
182
+ ],
183
+ test_iptables1.as_array,
184
+ 'after merge, table1 should include a complete ruleset'
185
+ )
186
+ end
187
+
188
+ def test_custom_service_additions
189
+ config = IPTables::Configuration.new()
190
+ policy_table = IPTables::Tables.new({
191
+ 'filter' => {
192
+ 'INPUT' => {
193
+ 'policy' => 'ACCEPT',
194
+ 'rules' => [
195
+ {
196
+ 'node_addition_points' => [ 'INPUT' ]
197
+ },
198
+ ]
199
+ }
200
+ }
201
+ }, config)
202
+ rules_table = IPTables::Tables.new({
203
+ 'filter' => {
204
+ 'INPUT' => {
205
+ 'additions' => [
206
+ {
207
+ 'service_name' => 'svc1',
208
+ 'service_tcp' => 2222
209
+ },
210
+ {
211
+ 'service_name' => 'svc2',
212
+ 'service_udp' => 2223
213
+ },
214
+ {
215
+ 'service_name' => 'svc3',
216
+ 'service_tcp' => 2224,
217
+ 'service_udp' => 2225
218
+ }
219
+ ]
220
+ }
221
+ }
222
+ }, config)
223
+ policy_table.merge(rules_table)
224
+ assert_equal(
225
+ [
226
+ "*filter",
227
+ ":INPUT ACCEPT",
228
+ '-A INPUT -m comment --comment "_ Port 2222 - svc1"',
229
+ '-A INPUT -p tcp -m tcp --sport 1024:65535 --dport 2222 -m state --state NEW,ESTABLISHED -j ACCEPT',
230
+ '-A INPUT -m comment --comment "_ Port 2223 - svc2"',
231
+ '-A INPUT -p udp -m udp --sport 1024:65535 --dport 2223 -m state --state NEW,ESTABLISHED -j ACCEPT',
232
+ '-A INPUT -m comment --comment "_ svc3"',
233
+ '-A INPUT -p tcp -m tcp --sport 1024:65535 --dport 2224 -m state --state NEW,ESTABLISHED -j ACCEPT',
234
+ '-A INPUT -p udp -m udp --sport 1024:65535 --dport 2225 -m state --state NEW,ESTABLISHED -j ACCEPT',
235
+ "COMMIT"
236
+ ],
237
+ policy_table.as_array,
238
+ 'adding custom services on a node_addition_point should produce known results'
239
+ )
240
+ end
241
+
242
+ def test_merge
243
+ test_iptables1 = IPTables::Tables.new(
244
+ <<-EOS.dedent
245
+ *table1
246
+ *table2
247
+ COMMIT
248
+ EOS
249
+ )
250
+ test_iptables2 = IPTables::Tables.new( {
251
+ 'table1' => {},
252
+ 'table2' => false,
253
+ 'table3' => nil,
254
+ 'table4' => {}
255
+ })
256
+ test_iptables1.merge(test_iptables2)
257
+ assert_kind_of(IPTables::Table, test_iptables1.tables['table1'], 'after merge, table1 should still be a Table')
258
+ assert_nil(test_iptables1.tables['table2'], 'after merge, should have no table2')
259
+ assert_nil(test_iptables1.tables['table3'], 'after merge, should still have no table3')
260
+ assert_kind_of(IPTables::Table, test_iptables1.tables['table4'], 'after merge, table4 should be a new Table')
261
+
262
+ # a huge merge test, because I am lazy
263
+ config = IPTables::Configuration.new()
264
+ policy_table = IPTables::Tables.new({
265
+ 'filter' => {
266
+ 'INPUT' => {
267
+ 'policy' => 'ACCEPT',
268
+ 'rules' => [
269
+ '-J INPUT_rule1',
270
+ {
271
+ 'node_addition_points' => [ 'INPUT', 'chain_INOUT' ]
272
+ },
273
+ '-J INPUT_rule3'
274
+ ]
275
+ },
276
+ 'OUTPUT' => {
277
+ 'policy' => 'ACCEPT',
278
+ 'rules' => [
279
+ '-J OUTPUT_rule1',
280
+ {
281
+ 'node_addition_points' => [ 'OUTPUT', 'chain_INOUT' ]
282
+ },
283
+ '-J OUTPUT_rule3'
284
+ ]
285
+ }
286
+ }
287
+ }, config)
288
+ rules_table = IPTables::Tables.new({
289
+ 'filter' => {
290
+ 'INPUT' => {
291
+ 'policy' => 'DROP',
292
+ 'additions' => [
293
+ '-J INPUT_addition'
294
+ ]
295
+ },
296
+ 'FORWARD' => {
297
+ 'policy' => 'REJECT',
298
+ 'rules' => [
299
+ '-J FORWARD_rule1'
300
+ ]
301
+ },
302
+ 'chain_INOUT' => {
303
+ 'additions' => [
304
+ '-J chain_INOUT_addition'
305
+ ]
306
+ },
307
+ 'nonexistent' => {
308
+ 'additions' => [
309
+ '-J nonexistent_addition'
310
+ ]
311
+ }
312
+ }
313
+ }, config)
314
+ policy_table.merge(rules_table)
315
+ assert_equal(
316
+ [
317
+ "*filter",
318
+ ":INPUT DROP",
319
+ ":FORWARD REJECT",
320
+ ":OUTPUT ACCEPT",
321
+ "-A INPUT -J INPUT_rule1",
322
+ "-A INPUT -J INPUT_addition",
323
+ "-A INPUT -J chain_INOUT_addition",
324
+ "-A INPUT -J INPUT_rule3",
325
+ "-A FORWARD -J FORWARD_rule1",
326
+ "-A OUTPUT -J OUTPUT_rule1",
327
+ "-A OUTPUT -J chain_INOUT_addition",
328
+ "-A OUTPUT -J OUTPUT_rule3",
329
+ "COMMIT"
330
+ ],
331
+ policy_table.as_array
332
+ )
333
+ end
334
+
335
+ def test_get_node_additions
336
+ # not testing this directly here?
337
+ end
338
+
339
+ def test_parse
340
+ assert_raise( RuntimeError ) { IPTables::Tables.new('garbage') }
341
+ assert_raise( RuntimeError, 'should not allow empty iptables parsed rules' ) { IPTables::Tables.new('') }
342
+ end
343
+ end
344
+
345
+ class TestTable < Test::Unit::TestCase
346
+ def test_initialize
347
+ test_iptables = IPTables::Tables.new({
348
+ 'table1' => {
349
+ 'INPUT' => {
350
+ 'rules' => [
351
+ '-j ACCEPT'
352
+ ]
353
+ }
354
+ }
355
+ })
356
+ table1 = test_iptables.tables['table1']
357
+ assert_kind_of(IPTables::Tables, table1.my_iptables)
358
+ assert_kind_of(IPTables::Chain, table1.chains['INPUT'])
359
+ assert_equal('table1', table1.name)
360
+
361
+ assert_raise( RuntimeError ) {
362
+ IPTables::Tables.new({
363
+ 'table1' => {
364
+ 'INPUT' => 1
365
+ }
366
+ })
367
+ }
368
+ end
369
+
370
+ def test_path
371
+ test_iptables = IPTables::Tables.new({
372
+ 'table1' => {
373
+ 'INPUT' => {
374
+ 'rules' => [
375
+ '-j ACCEPT'
376
+ ]
377
+ }
378
+ }
379
+ })
380
+ table1 = test_iptables.tables['table1']
381
+ assert_equal('table1', table1.path)
382
+ end
383
+
384
+ def test_merge
385
+ test_iptables1 = IPTables::Tables.new(
386
+ <<-EOS.dedent
387
+ *table1
388
+ :chain1 ACCEPT [0:0]
389
+ :chain2 ACCEPT [0:0]
390
+ -A chain1 -j ACCEPT
391
+ -A chain2 -j ACCEPT
392
+ COMMIT
393
+ EOS
394
+ )
395
+ table1 = test_iptables1.tables['table1']
396
+
397
+ test_iptables2 = IPTables::Tables.new({
398
+ 'table1' => {
399
+ 'chain1' => {},
400
+ 'chain2' => false,
401
+ 'chain3' => nil,
402
+ 'chain4' => {},
403
+ }
404
+ })
405
+ table2 = test_iptables2.tables['table1']
406
+
407
+ table1.merge(table2)
408
+ assert_kind_of(IPTables::Chain, table1.chains['chain1'])
409
+ assert_nil(table1.chains['chain2'], 'after merge, should have no chain2')
410
+ assert_nil(table1.chains['chain3'], 'after merge, should have no chain3')
411
+ assert_kind_of(IPTables::Chain, table1.chains['chain4'])
412
+ end
413
+ end
414
+
415
+ class TestChain < Test::Unit::TestCase
416
+ def setup
417
+ @test_iptables = IPTables::Tables.new(
418
+ <<-EOS.dedent
419
+ *table1
420
+ :chain1 ACCEPT [0:0]
421
+ -A chain1 -m comment --comment "BEGIN: in-bound traffic"
422
+ -A chain1 -j ACCEPT
423
+ COMMIT
424
+ EOS
425
+ )
426
+ @chain1 = @test_iptables.tables['table1'].chains['chain1']
427
+ end
428
+
429
+ def test_output_policy
430
+ assert_equal('ACCEPT', @chain1.output_policy)
431
+ end
432
+
433
+ def test_as_array
434
+ assert_equal(
435
+ [
436
+ '-A chain1 -m comment --comment "BEGIN: in-bound traffic"',
437
+ '-A chain1 -j ACCEPT'
438
+ ],
439
+ @chain1.as_array,
440
+ 'chain as array should produce known output'
441
+ )
442
+ end
443
+
444
+ def test_all_as_array
445
+ assert_equal(
446
+ [
447
+ ':chain1 ACCEPT',
448
+ '-A chain1 -m comment --comment "BEGIN: in-bound traffic"',
449
+ '-A chain1 -j ACCEPT'
450
+ ],
451
+ @chain1.all_as_array,
452
+ 'chain as array including its policy should produce known output'
453
+ )
454
+ end
455
+
456
+ def test_as_array_without_comments
457
+ assert_equal(
458
+ @chain1.rules[0].type,
459
+ 'comment',
460
+ 'a chain rule that is known to be a comment should have type comment'
461
+ )
462
+ assert_equal(
463
+ [ '-A chain1 -j ACCEPT' ],
464
+ @chain1.as_array(comments = false),
465
+ 'chain as array without comments should produce known output'
466
+ )
467
+ end
468
+
469
+ def test_path
470
+ assert_equal('table1.chain1', @chain1.path)
471
+ end
472
+
473
+ def test_complete?
474
+ assert(
475
+ IPTables::Chain.new(
476
+ 'test_chain',
477
+ { 'rules' => [ '-j ACCEPT' ] },
478
+ @test_iptables
479
+ ).complete?,
480
+ 'chain with rules should say it is complete'
481
+ )
482
+ assert(
483
+ IPTables::Chain.new( 'test_chain', {}, @test_iptables).complete?,
484
+ 'chain without any rules or additions should say it is complete'
485
+ )
486
+ assert_equal(
487
+ false,
488
+ IPTables::Chain.new( 'test_chain', { 'additions' => [] }, @test_iptables).complete?,
489
+ 'chain with only additions should not say it is complete'
490
+ )
491
+ end
492
+ end
493
+
494
+ class TestRule < Test::Unit::TestCase
495
+ def setup
496
+ config = IPTables::Configuration.new
497
+ config.primitives(
498
+ IPTables::Primitives.new({
499
+ 'branch' => { 'leaf1' => 'leaf1_value' },
500
+ 'leaf2' => 'leaf2_value',
501
+ })
502
+ )
503
+ config.interpolations(
504
+ IPTables::Interpolations.new( config.primitives )
505
+ )
506
+ config.services(
507
+ IPTables::Services.new({
508
+ 'service1' => 1111,
509
+ })
510
+ )
511
+ config.macros(
512
+ IPTables::Macros.new({
513
+ 'macro1' => '-j macro1',
514
+ })
515
+ )
516
+ @test_iptables = IPTables::Tables.new({
517
+ 'table1' => {
518
+ 'chain1' => {
519
+ 'policy' => 'ACCEPT',
520
+ 'rules' => [
521
+ '-j ACCEPT'
522
+ ]
523
+ }
524
+ }
525
+ }, config)
526
+ @chain1 = @test_iptables.tables['table1'].chains['chain1']
527
+ end
528
+
529
+ def test_initialize
530
+ assert_raise( RuntimeError ) { IPTables::Rule.new( 1, @chain1 ) }
531
+ assert_equal(0, @chain1.rules[0].position)
532
+ assert_equal(
533
+ ["-A chain1 -j ACCEPT"],
534
+ IPTables::Rule.new( {'raw' => '-j ACCEPT'}, @chain1 ).as_array
535
+ )
536
+ assert_equal(
537
+ [
538
+ "-A chain1 -m comment --comment \"_ Port 1337 - foo\"",
539
+ "-A chain1 -p tcp -m tcp --sport 1024:65535 --dport 1337 -m state --state NEW,ESTABLISHED -j ACCEPT"
540
+ ],
541
+ IPTables::Rule.new( {'service_name' => 'foo', 'service_tcp' => 1337}, @chain1 ).as_array
542
+ )
543
+ assert_equal(
544
+ [
545
+ "-A chain1 -m comment --comment \"_ Port 1337 - foo\"",
546
+ "-A chain1 -p tcp -m tcp --sport 1024:65535 --dport 1337 -m state --state NEW,ESTABLISHED -j ACCEPT",
547
+ "-A chain1 -p udp -m udp --sport 1024:65535 --dport 1337 -m state --state NEW,ESTABLISHED -j ACCEPT"
548
+ ],
549
+ IPTables::Rule.new( {'service_name' => 'foo', 'service_tcp' => 1337, 'service_udp' => 1337}, @chain1 ).as_array
550
+ )
551
+ assert_raise( RuntimeError ) {
552
+ IPTables::Rule.new( {'service_name' => 'foo', 'service_tcp' => 1337, 'service_udp' => 1337, 'fake' => 1}, @chain1 ).as_array
553
+ }
554
+ assert_raise( RuntimeError ) { IPTables::Rule.new( {'bad' => 1}, @chain1 ) }
555
+ end
556
+
557
+ def test_handle_comment
558
+ rule = IPTables::Rule.new( {'comment' => 'a comment'}, @chain1 )
559
+ assert_equal(
560
+ {'comment' => 'a comment'},
561
+ rule.rule_hash,
562
+ 'comment attributes should be handled as comments'
563
+ )
564
+ assert_equal(
565
+ rule.type,
566
+ 'comment',
567
+ 'comment attributes should have their type set as "comment"'
568
+ )
569
+ end
570
+
571
+ def test_parse_comment
572
+ rule = IPTables::Rule.new( '-m comment --comment "BEGIN: in-bound traffic"', @chain1 )
573
+ assert_equal(
574
+ {'comment' => 'BEGIN: in-bound traffic'},
575
+ rule.rule_hash,
576
+ 'parsed comments should have their rule_hash set properly'
577
+ )
578
+ assert_equal(
579
+ rule.type,
580
+ 'comment',
581
+ 'parsed comments should have their type set as "comment"'
582
+ )
583
+ assert_equal(
584
+ [],
585
+ rule.as_array(comments = false),
586
+ 'parsed comments should not display when displayed with comments turned off'
587
+ )
588
+ end
589
+
590
+ def test_handle_node_addition_points
591
+ rule = IPTables::Rule.new( {'node_addition_points' => ['chain1']}, @chain1 )
592
+ assert_equal( [], rule.as_array )
593
+ end
594
+
595
+ def test_handle_interpolated
596
+ assert_equal(
597
+ ["-A chain1 -j leaf1_value"],
598
+ IPTables::Rule.new( {'interpolated' => '-j <% branch.leaf1 %>'}, @chain1 ).as_array
599
+ )
600
+ end
601
+
602
+ def test_handle_macro
603
+ assert_equal(
604
+ ["-A chain1 -j macro1"],
605
+ IPTables::Rule.new( {'macro' => 'macro1'}, @chain1 ).as_array
606
+ )
607
+ end
608
+
609
+ def test_handle_service
610
+ assert_equal(
611
+ [
612
+ "-A chain1 -m comment --comment \"_ Port 1111 - service1\"",
613
+ "-A chain1 -p tcp -m tcp --sport 1024:65535 --dport 1111 -m state --state NEW,ESTABLISHED -j ACCEPT"
614
+ ],
615
+ IPTables::Rule.new( {'service' => 'service1'}, @chain1 ).as_array
616
+ )
617
+ end
618
+
619
+ def test_handle_requires_primitive
620
+ assert_equal(
621
+ [],
622
+ IPTables::Rule.new(
623
+ {
624
+ 'raw' => '-j ACCEPT',
625
+ 'requires_primitive' => 'nonexistent'
626
+ },
627
+ @chain1
628
+ ).as_array
629
+ )
630
+ assert_equal(
631
+ ['-A chain1 -j ACCEPT'],
632
+ IPTables::Rule.new(
633
+ {
634
+ 'raw' => '-j ACCEPT',
635
+ 'requires_primitive' => 'leaf2'
636
+ },
637
+ @chain1
638
+ ).as_array
639
+ )
640
+ end
641
+
642
+ def test_as_array
643
+ assert_equal(
644
+ ["-A chain1 -p tcp -m limit --limit 1/sec --limit-burst 2 -j ULOG --ulog-prefix \"chain1:\""],
645
+ IPTables::Rule.new( {'ulog' => '-p tcp'}, @chain1 ).as_array
646
+ )
647
+ end
648
+
649
+ def test_path
650
+ assert_equal('table1.chain1.0', @chain1.rules[0].path)
651
+ end
652
+ end