ipscriptables 0.0.1
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 +15 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +10 -0
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +43 -0
- data/Gemfile +13 -0
- data/LICENSE +20 -0
- data/README.md +54 -0
- data/Rakefile +22 -0
- data/bin/ipscriptables +6 -0
- data/cookbook/.gitignore +2 -0
- data/cookbook/.kitchen.yml +28 -0
- data/cookbook/Berksfile +6 -0
- data/cookbook/README.md +53 -0
- data/cookbook/attributes/default.rb +3 -0
- data/cookbook/chefignore +96 -0
- data/cookbook/libraries/default.rb +35 -0
- data/cookbook/metadata.rb +9 -0
- data/cookbook/providers/rules.rb +21 -0
- data/cookbook/recipes/default.rb +10 -0
- data/cookbook/recipes/load.rb +8 -0
- data/cookbook/resources/rules.rb +17 -0
- data/cookbook/test/cookbooks/ipscriptables-test/#metadata.rb# +8 -0
- data/cookbook/test/cookbooks/ipscriptables-test/metadata.rb +11 -0
- data/cookbook/test/cookbooks/ipscriptables-test/recipes/default.rb +23 -0
- data/cookbook/test/cookbooks/ipscriptables-test/recipes/prepare.rb +5 -0
- data/cookbook/test/data/.gitignore +1 -0
- data/cookbook/test/integration/default/bats/default.bats +9 -0
- data/doc/iptables-switches.txt +342 -0
- data/ipscriptables.gemspec +38 -0
- data/lib/ipscriptables.rb +14 -0
- data/lib/ipscriptables/chain.rb +83 -0
- data/lib/ipscriptables/cli.rb +19 -0
- data/lib/ipscriptables/helpers.rb +39 -0
- data/lib/ipscriptables/pretty_print.rb +58 -0
- data/lib/ipscriptables/rule.rb +95 -0
- data/lib/ipscriptables/ruleset.rb +103 -0
- data/lib/ipscriptables/ruleset/class_methods.rb +67 -0
- data/lib/ipscriptables/runtime.rb +97 -0
- data/lib/ipscriptables/table.rb +77 -0
- data/lib/ipscriptables/version.rb +5 -0
- data/spec/fixtures/clyhq.txt +40 -0
- data/spec/fixtures/docker-plus.txt +31 -0
- data/spec/fixtures/drumknott.txt +67 -0
- data/spec/fixtures/falcor.txt +39 -0
- data/spec/fixtures/ghq.txt +102 -0
- data/spec/fixtures/ip6tables-empty.txt +7 -0
- data/spec/fixtures/only-docker-c.txt +23 -0
- data/spec/fixtures/only-docker.txt +23 -0
- data/spec/fixtures/only_docker.rb +22 -0
- data/spec/fixtures/runtime.rb +7 -0
- data/spec/fixtures/runtime2.rb +16 -0
- data/spec/ipscriptables/dsl_spec.rb +74 -0
- data/spec/ipscriptables/helpers_spec.rb +58 -0
- data/spec/ipscriptables/rule_spec.rb +41 -0
- data/spec/ipscriptables/ruleset/class_methods_spec.rb +52 -0
- data/spec/ipscriptables/ruleset_spec.rb +199 -0
- data/spec/ipscriptables/runtime_spec.rb +227 -0
- data/spec/ipscriptables/table_spec.rb +32 -0
- data/spec/ipscriptables/version_spec.rb +12 -0
- data/spec/spec_helper.rb +60 -0
- metadata +350 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generated by iptables-save v1.4.12 on Wed Feb 19 13:37:35 2014
|
2
|
+
*filter
|
3
|
+
:INPUT ACCEPT [211:14626]
|
4
|
+
:FORWARD ACCEPT [0:0]
|
5
|
+
:OUTPUT ACCEPT [122:11280]
|
6
|
+
[1:2] -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
7
|
+
[1:2] -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
|
8
|
+
[1:2] -A FORWARD -i docker0 -o docker0 -j ACCEPT
|
9
|
+
COMMIT
|
10
|
+
# Completed on Wed Feb 19 13:37:35 2014
|
11
|
+
# Generated by iptables-save v1.4.12 on Wed Feb 19 13:37:35 2014
|
12
|
+
*nat
|
13
|
+
:PREROUTING ACCEPT [5:1208]
|
14
|
+
:INPUT ACCEPT [5:1208]
|
15
|
+
:OUTPUT ACCEPT [42:3215]
|
16
|
+
:POSTROUTING ACCEPT [42:3215]
|
17
|
+
:DOCKER - [0:0]
|
18
|
+
[1:2] -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
|
19
|
+
[1:2] -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
|
20
|
+
[1:2] -A POSTROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE
|
21
|
+
[1:2] -A POSTROUTING -s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE
|
22
|
+
COMMIT
|
23
|
+
# Completed on Wed Feb 19 13:37:35 2014
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generated by iptables-save v1.4.12 on Wed Feb 19 13:37:35 2014
|
2
|
+
*filter
|
3
|
+
:INPUT ACCEPT [211:14626]
|
4
|
+
:FORWARD ACCEPT [0:0]
|
5
|
+
:OUTPUT ACCEPT [122:11280]
|
6
|
+
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
7
|
+
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
|
8
|
+
-A FORWARD -i docker0 -o docker0 -j ACCEPT
|
9
|
+
COMMIT
|
10
|
+
# Completed on Wed Feb 19 13:37:35 2014
|
11
|
+
# Generated by iptables-save v1.4.12 on Wed Feb 19 13:37:35 2014
|
12
|
+
*nat
|
13
|
+
:PREROUTING ACCEPT [5:1208]
|
14
|
+
:INPUT ACCEPT [5:1208]
|
15
|
+
:OUTPUT ACCEPT [42:3215]
|
16
|
+
:POSTROUTING ACCEPT [42:3215]
|
17
|
+
:DOCKER - [0:0]
|
18
|
+
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
|
19
|
+
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
|
20
|
+
-A POSTROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE
|
21
|
+
-A POSTROUTING -s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE
|
22
|
+
COMMIT
|
23
|
+
# Completed on Wed Feb 19 13:37:35 2014
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
table :filter do
|
4
|
+
chain :FORWARD do
|
5
|
+
rule '-o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT'
|
6
|
+
rule '-i docker0 ! -o docker0 -j ACCEPT'
|
7
|
+
rule '-i docker0 -o docker0 -j ACCEPT'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
table :nat do
|
12
|
+
chain :PREROUTING do
|
13
|
+
rule '-m addrtype --dst-type LOCAL -j DOCKER'
|
14
|
+
end
|
15
|
+
chain :OUTPUT do
|
16
|
+
rule '! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER'
|
17
|
+
end
|
18
|
+
chain :POSTROUTING do
|
19
|
+
rule '-s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE'
|
20
|
+
rule '-s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE'
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
iptables do
|
4
|
+
table :nat do
|
5
|
+
chain :PREROUTING do
|
6
|
+
rule '-m addrtype --dst-type LOCAL -j DOCKER'
|
7
|
+
end
|
8
|
+
chain :OUTPUT do
|
9
|
+
rule '! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER'
|
10
|
+
end
|
11
|
+
chain :POSTROUTING do
|
12
|
+
rule '-s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE'
|
13
|
+
rule '-s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module IPScriptables
|
5
|
+
describe 'Chain#rule' do
|
6
|
+
THREE_PORTS_RULES = <<EOF
|
7
|
+
*filter
|
8
|
+
:INPUT ACCEPT [0:0]
|
9
|
+
:FORWARD ACCEPT [0:0]
|
10
|
+
:OUTPUT ACCEPT [0:0]
|
11
|
+
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
|
12
|
+
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
|
13
|
+
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
|
14
|
+
-A INPUT -j REJECT --reject-with icmp-port-unreachable
|
15
|
+
COMMIT
|
16
|
+
EOF
|
17
|
+
|
18
|
+
def expect_three_ports_from(&block)
|
19
|
+
rs = Ruleset.new do
|
20
|
+
table :filter do
|
21
|
+
chain :INPUT do
|
22
|
+
instance_eval(&block)
|
23
|
+
rule '-j REJECT --reject-with icmp-port-unreachable'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
expect { rs.render == THREE_PORTS_RULES }
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'allows to describe rulesets' do
|
31
|
+
expect_three_ports_from do
|
32
|
+
rule '-p tcp -m tcp --dport 22 -j ACCEPT'
|
33
|
+
rule '-p tcp -m tcp --dport 80 -j ACCEPT'
|
34
|
+
rule '-p tcp -m tcp --dport 443 -j ACCEPT'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'Allows nesting for DRY' do
|
39
|
+
expect_three_ports_from do
|
40
|
+
rule '-p tcp -m tcp' do
|
41
|
+
rule '--dport 22 -j ACCEPT'
|
42
|
+
rule '--dport 80 -j ACCEPT'
|
43
|
+
rule '--dport 443 -j ACCEPT'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'accepts iterable of elements for iteration' do
|
49
|
+
expect_three_ports_from do
|
50
|
+
rule [
|
51
|
+
'-p tcp -m tcp --dport 22 -j ACCEPT',
|
52
|
+
'-p tcp -m tcp --dport 80 -j ACCEPT',
|
53
|
+
'-p tcp -m tcp --dport 443 -j ACCEPT'
|
54
|
+
]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'accepts multiple of arguments and processes them as if nested' do
|
59
|
+
expect_three_ports_from do
|
60
|
+
rule '-p tcp -m tcp --dport', [22, 80, 443], '-j ACCEPT'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'understands parameters provided as hashes' do
|
65
|
+
expect_three_ports_from do
|
66
|
+
rule p: :tcp, m: :tcp, dport: [22, 80, 443], j: :ACCEPT
|
67
|
+
end
|
68
|
+
|
69
|
+
expect_three_ports_from do
|
70
|
+
rule '-p' => :tcp, '-m' => :tcp, '--dport' => [22, 80, 443], '-j' => :ACCEPT # rubocop:disable LineLength
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module IPScriptables
|
5
|
+
describe 'Helpers.run_command' do
|
6
|
+
def mock_status(success = true)
|
7
|
+
rv = mock('Process::Status')
|
8
|
+
rv.expects(:success?).at_least(0).returns(success)
|
9
|
+
rv
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'runs external command and returns its stdout' do
|
13
|
+
Helpers.expects('systemu').with(%w(echo foo))
|
14
|
+
.returns([mock_status, "foo\n", ''])
|
15
|
+
expect { Helpers.run_command('echo', 'foo') == "foo\n" }
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'raises RuntimError on failure status' do
|
19
|
+
Helpers.expects('systemu').with(%w(false))
|
20
|
+
.returns([mock_status(false), '', ''])
|
21
|
+
expect { rescuing { Helpers.run_command('false') }.is_a?(RuntimeError) }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'prints command\'s stderr on stderr' do
|
25
|
+
Helpers.expects('systemu').with(%w(cmd))
|
26
|
+
.returns([mock_status, "bar\n", "foo\n"])
|
27
|
+
out, err = capture_io { @res = Helpers.run_command('cmd') }
|
28
|
+
expect { out == '' }
|
29
|
+
expect { err == "cmd: foo\n" }
|
30
|
+
expect { @res == "bar\n" }
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'prints stdout on stderr in case of failure' do
|
34
|
+
Helpers.expects('systemu').with(%w(cmd))
|
35
|
+
.returns([mock_status(false), "foo\n", ''])
|
36
|
+
out, err = capture_io do
|
37
|
+
@rescued = rescuing { Helpers.run_command('cmd') }
|
38
|
+
end
|
39
|
+
expect { out == '' }
|
40
|
+
expect { err == "cmd: foo\n" }
|
41
|
+
expect { @rescued.is_a?(RuntimeError) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'Helpers.ohai' do
|
46
|
+
before { fauxhai! }
|
47
|
+
|
48
|
+
it 'returns a configured instance of Ohai' do
|
49
|
+
expect { Helpers.ohai['hostname'] == 'Fauxhai' }
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'caches the ohai instance for better performance' do
|
53
|
+
ohai1 = Helpers.ohai
|
54
|
+
ohai2 = Helpers.ohai
|
55
|
+
expect { ohai1.object_id == ohai2.object_id }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module IPScriptables
|
5
|
+
describe 'Rule' do
|
6
|
+
let(:chain) do
|
7
|
+
ch = mock(Chain.name)
|
8
|
+
ch.expects(:original).at_least_once.returns(nil)
|
9
|
+
ch.expects(:opts).at_least(0).returns({})
|
10
|
+
ch
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:rule) do
|
14
|
+
Rule.new(chain, '-s 1.1.1.1/32 -p tcp -m tcp -m multiport --dports 4949,5666 -j ACCEPT') # rubocop:disable LineLength
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows accessing individual switches by dict access' do
|
18
|
+
expect { rule['--dports'] == '4949,5666' }
|
19
|
+
expect { rule['dports'] == '4949,5666' }
|
20
|
+
expect { rule[:dports] == '4949,5666' }
|
21
|
+
expect { rule[:destination_ports] == '4949,5666' }
|
22
|
+
expect { rule[:j] == 'ACCEPT' }
|
23
|
+
expect { rule[:jump] == 'ACCEPT' }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'rolls multiple options into arrays' do
|
27
|
+
expect { rule[:m] == %w(tcp multiport) }
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'has convenience aliases' do
|
31
|
+
expect { rule.match == %w(tcp multiport) }
|
32
|
+
expect { rule.proto == 'tcp' }
|
33
|
+
expect { rule.target == 'ACCEPT' }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can be also matched by regexp' do
|
37
|
+
expect { rule =~ /multiport/ }
|
38
|
+
deny { rule =~ /udp/ }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module IPScriptables
|
5
|
+
describe 'Ruleset.from_file, .from_s' do
|
6
|
+
Dir[fixture('**/*.txt')].each do |fixture|
|
7
|
+
it "parses #{File.basename(fixture)} and renders it back" do
|
8
|
+
fixture_text = File.open(fixture).lines.grep(/^[^#]/).join
|
9
|
+
expect { Ruleset.from_file(fixture).render == fixture_text }
|
10
|
+
expect { Ruleset.from_s(File.read(fixture)).render == fixture_text }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'fails on invalid input' do
|
15
|
+
expect { rescuing { Ruleset.from_s('Invalid!') }.is_a?(RuntimeError) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'Ruleset.from_command' do
|
20
|
+
let(:fixture_content) { File.read(fixture('ghq.txt')) }
|
21
|
+
let(:fixture_text) { fixture_content.lines.grep(/^[^#]/).join }
|
22
|
+
|
23
|
+
it 'executes external command and parses its output as ruleset' do
|
24
|
+
Helpers.expects(:run_command)
|
25
|
+
.with('a', 'command', 'with', 'arguments')
|
26
|
+
.returns(fixture_content)
|
27
|
+
rs = Ruleset.from_command('a', 'command', 'with', 'arguments')
|
28
|
+
expect { rs.render == fixture_text }
|
29
|
+
expect { rs.command == %w(a command with arguments) }
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'has a convenience alias .from_iptables' do
|
33
|
+
Helpers.expects(:run_command)
|
34
|
+
.with('iptables-save', '-c')
|
35
|
+
.returns(fixture_content)
|
36
|
+
rs = Ruleset.from_iptables
|
37
|
+
expect { rs.render == fixture_text }
|
38
|
+
expect { rs.command == %w(iptables-save -c) }
|
39
|
+
expect { rs.family == :inet }
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'has a convenience alias .from_ip6tables' do
|
43
|
+
Helpers.expects(:run_command)
|
44
|
+
.with('ip6tables-save', '-c')
|
45
|
+
.returns(fixture_content)
|
46
|
+
rs = Ruleset.from_ip6tables
|
47
|
+
expect { rs.render == fixture_text }
|
48
|
+
expect { rs.command == %w(ip6tables-save -c) }
|
49
|
+
expect { rs.family == :inet6 }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# rubocop:disable LineLength
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module IPScriptables
|
6
|
+
describe 'Ruleset#method_missing' do
|
7
|
+
let(:rs) { Ruleset.new(foo: 23) }
|
8
|
+
it 'forwards calls to ruleset\'s options' do
|
9
|
+
expect { rs.foo == 23 }
|
10
|
+
expect { rs.respond_to? :foo }
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'rejects methods that are not in options' do
|
14
|
+
expect { rescuing { rs.bar }.is_a?(NoMethodError) }
|
15
|
+
deny { rs.respond_to? :bar }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'Ruleset#bud' do
|
20
|
+
let(:drumknott) { Ruleset.from_file(fixture('drumknott.txt')) }
|
21
|
+
let(:ghq) { Ruleset.from_file(fixture('ghq.txt')) }
|
22
|
+
|
23
|
+
it 'creates a child ruleset with identical tables and chains, but no rules' do
|
24
|
+
expected_rules = <<-EOF
|
25
|
+
*mangle
|
26
|
+
:PREROUTING ACCEPT [9070264:2761485141]
|
27
|
+
:INPUT ACCEPT [5794:541194]
|
28
|
+
:FORWARD ACCEPT [9064470:2760943947]
|
29
|
+
:OUTPUT ACCEPT [4447:1027385]
|
30
|
+
:POSTROUTING ACCEPT [9068917:2761971332]
|
31
|
+
COMMIT
|
32
|
+
*nat
|
33
|
+
:PREROUTING ACCEPT [936831:58138468]
|
34
|
+
:INPUT ACCEPT [383149:28442596]
|
35
|
+
:OUTPUT ACCEPT [188115:19311882]
|
36
|
+
:POSTROUTING ACCEPT [88176135:5298607741]
|
37
|
+
:DOCKER - [0:0]
|
38
|
+
COMMIT
|
39
|
+
*filter
|
40
|
+
:INPUT ACCEPT [419:18560]
|
41
|
+
:FORWARD ACCEPT [5802508472:1613710597740]
|
42
|
+
:OUTPUT ACCEPT [2072879:485657573]
|
43
|
+
:FWR - [0:0]
|
44
|
+
COMMIT
|
45
|
+
EOF
|
46
|
+
child = drumknott.bud
|
47
|
+
expect { child.render == expected_rules }
|
48
|
+
expect { child.original == drumknott }
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'allows chain inheritance' do
|
52
|
+
child = drumknott.bud do
|
53
|
+
inherit :nat, :DOCKER
|
54
|
+
end
|
55
|
+
expected_rules = <<-EOF
|
56
|
+
*mangle
|
57
|
+
:PREROUTING ACCEPT [9070264:2761485141]
|
58
|
+
:INPUT ACCEPT [5794:541194]
|
59
|
+
:FORWARD ACCEPT [9064470:2760943947]
|
60
|
+
:OUTPUT ACCEPT [4447:1027385]
|
61
|
+
:POSTROUTING ACCEPT [9068917:2761971332]
|
62
|
+
COMMIT
|
63
|
+
*nat
|
64
|
+
:PREROUTING ACCEPT [936831:58138468]
|
65
|
+
:INPUT ACCEPT [383149:28442596]
|
66
|
+
:OUTPUT ACCEPT [188115:19311882]
|
67
|
+
:POSTROUTING ACCEPT [88176135:5298607741]
|
68
|
+
:DOCKER - [0:0]
|
69
|
+
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 6379 -j DNAT --to-destination 172.17.0.2:6379
|
70
|
+
COMMIT
|
71
|
+
*filter
|
72
|
+
:INPUT ACCEPT [419:18560]
|
73
|
+
:FORWARD ACCEPT [5802508472:1613710597740]
|
74
|
+
:OUTPUT ACCEPT [2072879:485657573]
|
75
|
+
:FWR - [0:0]
|
76
|
+
COMMIT
|
77
|
+
EOF
|
78
|
+
expect { child.render == expected_rules }
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'allows filtering inherited chains' do
|
82
|
+
child = drumknott.bud do
|
83
|
+
inherit(:filter, :FWR) { |rule| !rule[:source] }
|
84
|
+
end
|
85
|
+
expected_rules = <<-EOF
|
86
|
+
*mangle
|
87
|
+
:PREROUTING ACCEPT [9070264:2761485141]
|
88
|
+
:INPUT ACCEPT [5794:541194]
|
89
|
+
:FORWARD ACCEPT [9064470:2760943947]
|
90
|
+
:OUTPUT ACCEPT [4447:1027385]
|
91
|
+
:POSTROUTING ACCEPT [9068917:2761971332]
|
92
|
+
COMMIT
|
93
|
+
*nat
|
94
|
+
:PREROUTING ACCEPT [936831:58138468]
|
95
|
+
:INPUT ACCEPT [383149:28442596]
|
96
|
+
:OUTPUT ACCEPT [188115:19311882]
|
97
|
+
:POSTROUTING ACCEPT [88176135:5298607741]
|
98
|
+
:DOCKER - [0:0]
|
99
|
+
COMMIT
|
100
|
+
*filter
|
101
|
+
:INPUT ACCEPT [419:18560]
|
102
|
+
:FORWARD ACCEPT [5802508472:1613710597740]
|
103
|
+
:OUTPUT ACCEPT [2072879:485657573]
|
104
|
+
:FWR - [0:0]
|
105
|
+
-A FWR -i lo -j ACCEPT
|
106
|
+
-A FWR -m state --state RELATED,ESTABLISHED -j ACCEPT
|
107
|
+
-A FWR -p icmp -j ACCEPT
|
108
|
+
-A FWR -i docker+ -j ACCEPT
|
109
|
+
-A FWR -p tcp -m tcp --dport 22 -j ACCEPT
|
110
|
+
-A FWR -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable
|
111
|
+
-A FWR -p udp -j REJECT --reject-with icmp-port-unreachable
|
112
|
+
COMMIT
|
113
|
+
EOF
|
114
|
+
expect { child.render == expected_rules }
|
115
|
+
expect { drumknott.render =~ /^-A FWR -s 1\.1\.1\.1/ }
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'copies original\'s chain with counters' do
|
119
|
+
child = ghq.bud do
|
120
|
+
inherit(:nat, :DOCKER)
|
121
|
+
table :filter do
|
122
|
+
chain :INPUT do
|
123
|
+
rule '-j FWR'
|
124
|
+
end
|
125
|
+
chain :FWR do
|
126
|
+
rule '-i lo -j ACCEPT'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
expected_rules = <<-EOF
|
132
|
+
*nat
|
133
|
+
:PREROUTING ACCEPT [732601:44001989]
|
134
|
+
:INPUT ACCEPT [376018:22538408]
|
135
|
+
:OUTPUT ACCEPT [3131507:229597576]
|
136
|
+
:POSTROUTING ACCEPT [20476198:1943580383]
|
137
|
+
:DOCKER - [0:0]
|
138
|
+
[2:120] -A DOCKER ! -i docker0 -p tcp -m tcp --dport 2003 -j DNAT --to-destination 172.17.0.4:2003
|
139
|
+
[0:0] -A DOCKER ! -i docker0 -p tcp -m tcp --dport 2004 -j DNAT --to-destination 172.17.0.4:2004
|
140
|
+
[0:0] -A DOCKER ! -i docker0 -p tcp -m tcp --dport 49153 -j DNAT --to-destination 172.17.0.8:9000
|
141
|
+
[95:5580] -A DOCKER ! -i docker0 -p tcp -m tcp --dport 5000 -j DNAT --to-destination 172.17.0.5:5000
|
142
|
+
[0:0] -A DOCKER -d 127.0.0.1/32 ! -i docker0 -p tcp -m tcp --dport 49154 -j DNAT --to-destination 172.17.0.9:8080
|
143
|
+
[17011603:1693997647] -A DOCKER ! -i docker0 -p udp -m udp --dport 8125 -j DNAT --to-destination 172.17.0.10:8125
|
144
|
+
[0:0] -A DOCKER -d 127.0.0.1/32 ! -i docker0 -p tcp -m tcp --dport 49155 -j DNAT --to-destination 172.17.0.10:8126
|
145
|
+
COMMIT
|
146
|
+
*filter
|
147
|
+
:INPUT ACCEPT [1602:65593]
|
148
|
+
:FORWARD ACCEPT [79892700:14079015733]
|
149
|
+
:OUTPUT ACCEPT [173177551:46244981637]
|
150
|
+
:FWR - [0:0]
|
151
|
+
[162824485:36484450187] -A INPUT -j FWR
|
152
|
+
[104747465:21902005069] -A FWR -i lo -j ACCEPT
|
153
|
+
COMMIT
|
154
|
+
EOF
|
155
|
+
|
156
|
+
expect { child.render == expected_rules }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'Ruleset#diff' do
|
161
|
+
it 'returns a Diffy::Diff from the original ruleset' do
|
162
|
+
child = Ruleset.from_file(fixture('only-docker.txt')).bud
|
163
|
+
|
164
|
+
expect { child.diff.to_s.each_line.grep(/^\S/).length == 7 }
|
165
|
+
|
166
|
+
child.dsl_eval do
|
167
|
+
inherit :filter, :FORWARD
|
168
|
+
end
|
169
|
+
|
170
|
+
expect { child.diff.to_s.each_line.grep(/^\S/).length == 4 }
|
171
|
+
|
172
|
+
child.dsl_eval do
|
173
|
+
table :nat do
|
174
|
+
chain :PREROUTING do
|
175
|
+
rule '-m addrtype --dst-type LOCAL -j DOCKER'
|
176
|
+
end
|
177
|
+
chain :OUTPUT do
|
178
|
+
rule '! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER'
|
179
|
+
end
|
180
|
+
chain :POSTROUTING do
|
181
|
+
rule '-s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE'
|
182
|
+
rule '-s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
expect { child.diff.to_s.empty? }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe 'Ruleset#load_file' do
|
192
|
+
it 'Loads a ruleset from file' do
|
193
|
+
child = Ruleset.from_file(fixture('only-docker.txt')).bud
|
194
|
+
deny { child.diff.to_s.empty? }
|
195
|
+
child.load_file fixture('only_docker.rb')
|
196
|
+
expect { child.diff.to_s.empty? }
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|