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.
@@ -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