Added puppetlabs-firewall (required by puppetlabs-postgresql), updated the other modules.

This commit is contained in:
Ciaby 2014-07-11 14:51:15 -05:00
parent 5f4b7a3b72
commit dee66abcdd
137 changed files with 11118 additions and 419 deletions

View file

@ -0,0 +1,77 @@
require 'spec_helper_acceptance'
describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
describe 'reset' do
it 'deletes all rules' do
shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush')
end
end
describe 'when unmanaged rules exist' do
it 'applies with 8.0.0.1 first' do
pp = <<-EOS
class { '::firewall': }
firewall { '101 test source changes':
proto => tcp,
port => '101',
action => accept,
source => '8.0.0.1',
}
firewall { '100 test source static':
proto => tcp,
port => '100',
action => accept,
source => '8.0.0.2',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'adds a unmanaged rule without a comment' do
shell('iptables -A INPUT -t filter -s 8.0.0.3/32 -p tcp -m multiport --ports 102 -j ACCEPT')
expect(shell('iptables-save').stdout).to match(/-A INPUT -s 8\.0\.0\.3(\/32)? -p tcp -m multiport --ports 102 -j ACCEPT/)
end
it 'contains the changable 8.0.0.1 rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.1(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT/)
end
end
it 'contains the static 8.0.0.2 rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT/)
end
end
it 'changes to 8.0.0.4 second' do
pp = <<-EOS
class { '::firewall': }
firewall { '101 test source changes':
proto => tcp,
port => '101',
action => accept,
source => '8.0.0.4',
}
EOS
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/Notice: \/Stage\[main\]\/Main\/Firewall\[101 test source changes\]\/source: source changed '8\.0\.0\.1\/32' to '8\.0\.0\.4\/32'/)
end
it 'does not contain the old changing 8.0.0.1 rule' do
shell('iptables-save') do |r|
expect(r.stdout).to_not match(/8\.0\.0\.1/)
end
end
it 'contains the staic 8.0.0.2 rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT/)
end
end
it 'contains the changing new 8.0.0.4 rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.4(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT/)
end
end
end
end

View file

@ -0,0 +1,27 @@
require 'spec_helper_acceptance'
describe "firewall class:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
it 'should run successfully' do
pp = "class { 'firewall': }"
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
end
it 'ensure => stopped:' do
pp = "class { 'firewall': ensure => stopped }"
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
end
it 'ensure => running:' do
pp = "class { 'firewall': ensure => running }"
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
end
end

View file

@ -0,0 +1,55 @@
require 'spec_helper_acceptance'
describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
describe 'connlimit_above' do
context '10' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '500 - test':
proto => tcp,
dport => '22',
connlimit_above => '10',
action => reject,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'should contain the rule' do
shell('iptables-save') do |r|
#connlimit-saddr is added in Ubuntu 14.04.
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "500 - test" -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
end
end
end
end
describe 'connlimit_mask' do
context '24' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '501 - test':
proto => tcp,
dport => '22',
connlimit_above => '10',
connlimit_mask => '24',
action => reject,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'should contain the rule' do
shell('iptables-save') do |r|
#connlimit-saddr is added in Ubuntu 14.04.
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "501 - test" -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
end
end
end
end
end

View file

@ -0,0 +1,27 @@
require 'spec_helper_acceptance'
describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
describe 'connmark' do
context '50' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '502 - test':
proto => 'all',
connmark => '0x1',
action => reject,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -m comment --comment "502 - test" -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,125 @@
require 'spec_helper_acceptance'
describe 'puppet resource firewallchain command:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before :all do
iptables_flush_all_tables
end
describe 'ensure' do
context 'present' do
it 'applies cleanly' do
pp = <<-EOS
firewallchain { 'MY_CHAIN:filter:IPv4':
ensure => present,
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
it 'finds the chain' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/MY_CHAIN/)
end
end
end
context 'absent' do
it 'applies cleanly' do
pp = <<-EOS
firewallchain { 'MY_CHAIN:filter:IPv4':
ensure => absent,
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
it 'fails to find the chain' do
shell('iptables-save') do |r|
expect(r.stdout).to_not match(/MY_CHAIN/)
end
end
end
end
# XXX purge => false is not yet implemented
#context 'adding a firewall rule to a chain:' do
# it 'applies cleanly' do
# pp = <<-EOS
# firewallchain { 'MY_CHAIN:filter:IPv4':
# ensure => present,
# }
# firewall { '100 my rule':
# chain => 'MY_CHAIN',
# action => 'accept',
# proto => 'tcp',
# dport => 5000,
# }
# EOS
# # Run it twice and test for idempotency
# apply_manifest(pp, :catch_failures => true)
# apply_manifest(pp, :catch_changes => true)
# end
#end
#context 'not purge firewallchain chains:' do
# it 'does not purge the rule' do
# pp = <<-EOS
# firewallchain { 'MY_CHAIN:filter:IPv4':
# ensure => present,
# purge => false,
# before => Resources['firewall'],
# }
# resources { 'firewall':
# purge => true,
# }
# EOS
# # Run it twice and test for idempotency
# apply_manifest(pp, :catch_failures => true) do |r|
# expect(r.stdout).to_not match(/removed/)
# expect(r.stderr).to eq('')
# end
# apply_manifest(pp, :catch_changes => true)
# end
# it 'still has the rule' do
# pp = <<-EOS
# firewall { '100 my rule':
# chain => 'MY_CHAIN',
# action => 'accept',
# proto => 'tcp',
# dport => 5000,
# }
# EOS
# # Run it twice and test for idempotency
# apply_manifest(pp, :catch_changes => true)
# end
#end
describe 'policy' do
after :all do
shell('iptables -t filter -P FORWARD ACCEPT')
end
context 'DROP' do
it 'applies cleanly' do
pp = <<-EOS
firewallchain { 'FORWARD:filter:IPv4':
policy => 'drop',
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
it 'finds the chain' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/FORWARD DROP/)
end
end
end
end
end

View file

@ -0,0 +1,114 @@
require 'spec_helper_acceptance'
if default['platform'] =~ /el-5/
describe "firewall ip6tables doesn't work on 1.3.5 because --comment is missing", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before :all do
ip6tables_flush_all_tables
end
it "can't use ip6tables" do
pp = <<-EOS
class { '::firewall': }
firewall { '599 - test':
ensure => present,
proto => 'tcp',
provider => 'ip6tables',
}
EOS
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/ip6tables provider is not supported/)
end
end
else
describe 'firewall ishasmorefrags/islastfrag/isfirstfrag properties', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before :all do
ip6tables_flush_all_tables
end
shared_examples "is idempotent" do |values, line_match|
it "changes the values to #{values}" do
pp = <<-EOS
class { '::firewall': }
firewall { '599 - test':
ensure => present,
proto => 'tcp',
provider => 'ip6tables',
#{values}
}
EOS
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
shared_examples "doesn't change" do |values, line_match|
it "doesn't change the values to #{values}" do
pp = <<-EOS
class { '::firewall': }
firewall { '599 - test':
ensure => present,
proto => 'tcp',
provider => 'ip6tables',
#{values}
}
EOS
apply_manifest(pp, :catch_changes => true)
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
describe 'adding a rule' do
context 'when unset' do
before :all do
ip6tables_flush_all_tables
end
it_behaves_like 'is idempotent', '', /-A INPUT -p tcp -m comment --comment "599 - test"/
end
context 'when set to true' do
before :all do
ip6tables_flush_all_tables
end
it_behaves_like "is idempotent", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
end
context 'when set to false' do
before :all do
ip6tables_flush_all_tables
end
it_behaves_like "is idempotent", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
end
end
describe 'editing a rule' do
context 'when unset or false' do
before :each do
ip6tables_flush_all_tables
shell('ip6tables -A INPUT -p tcp -m comment --comment "599 - test"')
end
context 'and current value is false' do
it_behaves_like "doesn't change", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
end
context 'and current value is true' do
it_behaves_like "is idempotent", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
end
end
context 'when set to true' do
before :each do
ip6tables_flush_all_tables
shell('ip6tables -A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"')
end
context 'and current value is false' do
it_behaves_like "is idempotent", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
end
context 'and current value is true' do
it_behaves_like "doesn't change", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
end
end
end
end
end

View file

@ -0,0 +1,92 @@
require 'spec_helper_acceptance'
describe 'firewall isfragment property', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before :all do
iptables_flush_all_tables
end
shared_examples "is idempotent" do |value, line_match|
it "changes the value to #{value}" do
pp = <<-EOS
class { '::firewall': }
firewall { '597 - test':
ensure => present,
proto => 'tcp',
#{value}
}
EOS
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
shell('iptables-save') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
shared_examples "doesn't change" do |value, line_match|
it "doesn't change the value to #{value}" do
pp = <<-EOS
class { '::firewall': }
firewall { '597 - test':
ensure => present,
proto => 'tcp',
#{value}
}
EOS
apply_manifest(pp, :catch_changes => true)
shell('iptables-save') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
describe 'adding a rule' do
context 'when unset' do
before :all do
iptables_flush_all_tables
end
it_behaves_like 'is idempotent', '', /-A INPUT -p tcp -m comment --comment "597 - test"/
end
context 'when set to true' do
before :all do
iptables_flush_all_tables
end
it_behaves_like 'is idempotent', 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
end
context 'when set to false' do
before :all do
iptables_flush_all_tables
end
it_behaves_like "is idempotent", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
end
end
describe 'editing a rule' do
context 'when unset or false' do
before :each do
iptables_flush_all_tables
shell('iptables -A INPUT -p tcp -m comment --comment "597 - test"')
end
context 'and current value is false' do
it_behaves_like "doesn't change", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
end
context 'and current value is true' do
it_behaves_like "is idempotent", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
end
end
context 'when set to true' do
before :each do
iptables_flush_all_tables
shell('iptables -A INPUT -p tcp -f -m comment --comment "597 - test"')
end
context 'and current value is false' do
it_behaves_like "is idempotent", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
end
context 'and current value is true' do
it_behaves_like "doesn't change", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
end
end
end
end

View file

@ -0,0 +1,12 @@
HOSTS:
centos-59-x64:
roles:
- master
- database
- console
platform: el-5-x86_64
box : centos-59-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: pe

View file

@ -0,0 +1,10 @@
HOSTS:
centos-59-x64:
roles:
- master
platform: el-5-x86_64
box : centos-59-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,10 @@
HOSTS:
centos-64-x64:
roles:
- master
platform: el-6-x86_64
box : centos-64-x64-fusion503-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-fusion503-nocm.box
hypervisor : fusion
CONFIG:
type: foss

View file

@ -0,0 +1,12 @@
HOSTS:
centos-64-x64:
roles:
- master
- database
- dashboard
platform: el-6-x86_64
box : centos-64-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: pe

View file

@ -0,0 +1,10 @@
HOSTS:
centos-64-x64:
roles:
- master
platform: el-6-x86_64
box : centos-64-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,10 @@
HOSTS:
debian-607-x64:
roles:
- master
platform: debian-6-amd64
box : debian-607-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
debian-70rc1-x64:
roles:
- master
platform: debian-7-amd64
box : debian-70rc1-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
centos-64-x64:
roles:
- master
platform: el-6-x86_64
box : centos-64-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,10 @@
HOSTS:
fedora-18-x64:
roles:
- master
platform: fedora-18-x86_64
box : fedora-18-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
sles-11sp1-x64:
roles:
- master
platform: sles-11-x86_64
box : sles-11sp1-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
ubuntu-server-10044-x64:
roles:
- master
platform: ubuntu-10.04-amd64
box : ubuntu-server-10044-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
ubuntu-server-12042-x64:
roles:
- master
platform: ubuntu-12.04-amd64
box : ubuntu-server-12042-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,9 @@
HOSTS:
ubuntu-server-1404-x64:
roles:
- master
platform: ubuntu-14.04-64
box: puppetlabs/ubuntu-14.04-64-nocm
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,154 @@
require 'spec_helper_acceptance'
describe "param based tests:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
# Takes a hash and converts it into a firewall resource
def pp(params)
name = params.delete('name') || '100 test'
pm = <<-EOS
firewall { '#{name}':
EOS
params.each do |k,v|
pm += <<-EOS
#{k} => #{v},
EOS
end
pm += <<-EOS
}
EOS
pm
end
it 'test various params', :unless => (default['platform'].match(/el-5/) || fact('operatingsystem') == 'SLES') do
iptables_flush_all_tables
ppm = pp({
'table' => "'raw'",
'socket' => 'true',
'chain' => "'PREROUTING'",
'jump' => 'LOG',
'log_level' => 'debug',
})
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
end
it 'test log rule' do
iptables_flush_all_tables
ppm = pp({
'name' => '998 log all',
'proto' => 'all',
'jump' => 'LOG',
'log_level' => 'debug',
})
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
end
it 'test log rule - changing names' do
iptables_flush_all_tables
ppm1 = pp({
'name' => '004 log all INVALID packets',
'chain' => 'INPUT',
'proto' => 'all',
'ctstate' => 'INVALID',
'jump' => 'LOG',
'log_level' => '3',
'log_prefix' => '"IPTABLES dropped invalid: "',
})
ppm2 = pp({
'name' => '003 log all INVALID packets',
'chain' => 'INPUT',
'proto' => 'all',
'ctstate' => 'INVALID',
'jump' => 'LOG',
'log_level' => '3',
'log_prefix' => '"IPTABLES dropped invalid: "',
})
expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2)
ppm = <<-EOS + "\n" + ppm2
resources { 'firewall':
purge => true,
}
EOS
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
end
it 'test chain - changing names' do
iptables_flush_all_tables
ppm1 = pp({
'name' => '004 with a chain',
'chain' => 'INPUT',
'proto' => 'all',
})
ppm2 = pp({
'name' => '004 with a chain',
'chain' => 'OUTPUT',
'proto' => 'all',
})
apply_manifest(ppm1, :expect_changes => true)
ppm = <<-EOS + "\n" + ppm2
resources { 'firewall':
purge => true,
}
EOS
expect(apply_manifest(ppm2, :expect_failures => true).stderr).to match(/is not supported/)
end
it 'test log rule - idempotent' do
iptables_flush_all_tables
ppm1 = pp({
'name' => '004 log all INVALID packets',
'chain' => 'INPUT',
'proto' => 'all',
'ctstate' => 'INVALID',
'jump' => 'LOG',
'log_level' => '3',
'log_prefix' => '"IPTABLES dropped invalid: "',
})
expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2)
expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to be_zero
end
it 'test src_range rule' do
iptables_flush_all_tables
ppm = pp({
'name' => '997 block src ip range',
'chain' => 'INPUT',
'proto' => 'all',
'action' => 'drop',
'src_range' => '"10.0.0.1-10.0.0.10"',
})
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
end
it 'test dst_range rule' do
iptables_flush_all_tables
ppm = pp({
'name' => '998 block dst ip range',
'chain' => 'INPUT',
'proto' => 'all',
'action' => 'drop',
'dst_range' => '"10.0.0.2-10.0.0.20"',
})
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
end
end

View file

@ -0,0 +1,124 @@
require 'spec_helper_acceptance'
describe "purge tests:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context('resources purge') do
before(:all) do
iptables_flush_all_tables
shell('iptables -A INPUT -s 1.2.1.2')
shell('iptables -A INPUT -s 1.2.1.2')
end
it 'make sure duplicate existing rules get purged' do
pp = <<-EOS
class { 'firewall': }
resources { 'firewall':
purge => true,
}
EOS
apply_manifest(pp, :expect_changes => true)
end
it 'saves' do
shell('iptables-save') do |r|
expect(r.stdout).to_not match(/1\.2\.1\.2/)
expect(r.stderr).to eq("")
end
end
end
context('chain purge') do
before(:each) do
iptables_flush_all_tables
shell('iptables -A INPUT -p tcp -s 1.2.1.1')
shell('iptables -A INPUT -p udp -s 1.2.1.1')
shell('iptables -A OUTPUT -s 1.2.1.2 -m comment --comment "010 output-1.2.1.2"')
end
it 'purges only the specified chain' do
pp = <<-EOS
class { 'firewall': }
firewallchain { 'INPUT:filter:IPv4':
purge => true,
}
EOS
apply_manifest(pp, :expect_changes => true)
shell('iptables-save') do |r|
expect(r.stdout).to match(/010 output-1\.2\.1\.2/)
expect(r.stdout).to_not match(/1\.2\.1\.1/)
expect(r.stderr).to eq("")
end
end
it 'ignores managed rules' do
pp = <<-EOS
class { 'firewall': }
firewallchain { 'OUTPUT:filter:IPv4':
purge => true,
}
firewall { '010 output-1.2.1.2':
chain => 'OUTPUT',
proto => 'all',
source => '1.2.1.2',
}
EOS
apply_manifest(pp, :catch_changes => true)
end
it 'ignores specified rules' do
pp = <<-EOS
class { 'firewall': }
firewallchain { 'INPUT:filter:IPv4':
purge => true,
ignore => [
'-s 1\.2\.1\.1',
],
}
EOS
apply_manifest(pp, :catch_changes => true)
end
it 'adds managed rules with ignored rules' do
pp = <<-EOS
class { 'firewall': }
firewallchain { 'INPUT:filter:IPv4':
purge => true,
ignore => [
'-s 1\.2\.1\.1',
],
}
firewall { '014 input-1.2.1.6':
chain => 'INPUT',
proto => 'all',
source => '1.2.1.6',
}
-> firewall { '013 input-1.2.1.5':
chain => 'INPUT',
proto => 'all',
source => '1.2.1.5',
}
-> firewall { '012 input-1.2.1.4':
chain => 'INPUT',
proto => 'all',
source => '1.2.1.4',
}
-> firewall { '011 input-1.2.1.3':
chain => 'INPUT',
proto => 'all',
source => '1.2.1.3',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(shell('iptables-save').stdout).to match(/-A INPUT -s 1\.2\.1\.1(\/32)? -p tcp\s?\n-A INPUT -s 1\.2\.1\.1(\/32)? -p udp/)
end
end
end

View file

@ -0,0 +1,92 @@
require 'spec_helper_acceptance'
# Here we want to test the the resource commands ability to work with different
# existing ruleset scenarios. This will give the parsing capabilities of the
# code a good work out.
describe 'puppet resource firewall command:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'make sure it returns no errors when executed on a clean machine' do
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, some boxes come with rules, that is normal
# don't check stderr, puppet throws deprecation warnings
end
end
end
context 'flush iptables and make sure it returns nothing afterwards' do
before(:all) do
iptables_flush_all_tables
end
# No rules, means no output thanks. And no errors as well.
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
r.stdout.should == "\n"
end
end
end
context 'accepts rules without comments' do
before(:all) do
iptables_flush_all_tables
shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80')
end
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, testing preexisting rules, output is normal
# don't check stderr, puppet throws deprecation warnings
end
end
end
context 'accepts rules with invalid comments' do
before(:all) do
iptables_flush_all_tables
shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80 -m comment --comment "http"')
end
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, testing preexisting rules, output is normal
# don't check stderr, puppet throws deprecation warnings
end
end
end
context 'accepts rules with negation' do
before :all do
iptables_flush_all_tables
shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535')
shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535')
shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE')
end
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, testing preexisting rules, output is normal
# don't check stderr, puppet throws deprecation warnings
end
end
end
context 'accepts rules with match extension tcp flag' do
before :all do
iptables_flush_all_tables
shell('iptables -t mangle -A PREROUTING -d 1.2.3.4 -p tcp -m tcp -m multiport --dports 80,443,8140 -j MARK --set-mark 42')
end
it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, testing preexisting rules, output is normal
# don't check stderr, puppet throws deprecation warnings
end
end
end
end

View file

@ -0,0 +1,252 @@
require 'spec_helper_acceptance'
describe 'complex ruleset 1', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before :all do
iptables_flush_all_tables
end
after :all do
shell('iptables -t filter -P INPUT ACCEPT')
shell('iptables -t filter -P FORWARD ACCEPT')
shell('iptables -t filter -P OUTPUT ACCEPT')
shell('iptables -t filter --flush')
end
it 'applies cleanly' do
pp = <<-EOS
firewall { '090 forward allow local':
chain => 'FORWARD',
proto => 'all',
source => '10.0.0.0/8',
destination => '10.0.0.0/8',
action => 'accept',
}
firewall { '100 forward standard allow tcp':
chain => 'FORWARD',
source => '10.0.0.0/8',
destination => '!10.0.0.0/8',
proto => 'tcp',
state => 'NEW',
port => [80,443,21,20,22,53,123,43,873,25,465],
action => 'accept',
}
firewall { '100 forward standard allow udp':
chain => 'FORWARD',
source => '10.0.0.0/8',
destination => '!10.0.0.0/8',
proto => 'udp',
port => [53,123],
action => 'accept',
}
firewall { '100 forward standard allow icmp':
chain => 'FORWARD',
source => '10.0.0.0/8',
destination => '!10.0.0.0/8',
proto => 'icmp',
action => 'accept',
}
firewall { '090 ignore ipsec':
table => 'nat',
chain => 'POSTROUTING',
outiface => 'eth0',
ipsec_policy => 'ipsec',
ipsec_dir => 'out',
action => 'accept',
}
firewall { '093 ignore 10.0.0.0/8':
table => 'nat',
chain => 'POSTROUTING',
outiface => 'eth0',
destination => '10.0.0.0/8',
action => 'accept',
}
firewall { '093 ignore 172.16.0.0/12':
table => 'nat',
chain => 'POSTROUTING',
outiface => 'eth0',
destination => '172.16.0.0/12',
action => 'accept',
}
firewall { '093 ignore 192.168.0.0/16':
table => 'nat',
chain => 'POSTROUTING',
outiface => 'eth0',
destination => '192.168.0.0/16',
action => 'accept',
}
firewall { '100 masq outbound':
table => 'nat',
chain => 'POSTROUTING',
outiface => 'eth0',
jump => 'MASQUERADE',
}
firewall { '101 redirect port 1':
table => 'nat',
chain => 'PREROUTING',
iniface => 'eth0',
proto => 'tcp',
dport => '1',
toports => '22',
jump => 'REDIRECT',
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
end
it 'contains appropriate rules' do
shell('iptables-save') do |r|
[
/INPUT ACCEPT/,
/FORWARD ACCEPT/,
/OUTPUT ACCEPT/,
/-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) -d 10.0.0.0\/(8|255\.0\.0\.0) -m comment --comment \"090 forward allow local\" -j ACCEPT/,
/-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"100 forward standard allow icmp\" -j ACCEPT/,
/-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p tcp -m multiport --ports 80,443,21,20,22,53,123,43,873,25,465 -m comment --comment \"100 forward standard allow tcp\" -m state --state NEW -j ACCEPT/,
/-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p udp -m multiport --ports 53,123 -m comment --comment \"100 forward standard allow udp\" -j ACCEPT/
].each do |line|
expect(r.stdout).to match(line)
end
end
end
end
describe 'complex ruleset 2' do
after :all do
shell('iptables -t filter -P INPUT ACCEPT')
shell('iptables -t filter -P FORWARD ACCEPT')
shell('iptables -t filter -P OUTPUT ACCEPT')
shell('iptables -t filter --flush')
expect(shell('iptables -t filter -X LOCAL_INPUT').stderr).to eq("")
expect(shell('iptables -t filter -X LOCAL_INPUT_PRE').stderr).to eq("")
end
it 'applies cleanly' do
pp = <<-EOS
class { '::firewall': }
Firewall {
proto => 'all',
stage => 'pre',
}
Firewallchain {
stage => 'pre',
purge => 'true',
ignore => [
'--comment "[^"]*(?i:ignore)[^"]*"',
],
}
firewall { '010 INPUT allow established and related':
proto => 'all',
state => ['ESTABLISHED', 'RELATED'],
action => 'accept',
before => Firewallchain['INPUT:filter:IPv4'],
}
firewall { '012 accept loopback':
iniface => 'lo',
action => 'accept',
before => Firewallchain['INPUT:filter:IPv4'],
}
firewall { '020 ssh':
proto => 'tcp',
dport => '22',
state => 'NEW',
action => 'accept',
before => Firewallchain['INPUT:filter:IPv4'],
}
firewall { '013 icmp echo-request':
proto => 'icmp',
icmp => 'echo-request',
action => 'accept',
source => '10.0.0.0/8',
}
firewall { '013 icmp destination-unreachable':
proto => 'icmp',
icmp => 'destination-unreachable',
action => 'accept',
}
firewall { '013 icmp time-exceeded':
proto => 'icmp',
icmp => 'time-exceeded',
action => 'accept',
}
firewall { '999 reject':
action => 'reject',
reject => 'icmp-host-prohibited',
}
firewallchain { 'LOCAL_INPUT_PRE:filter:IPv4': }
firewall { '001 LOCAL_INPUT_PRE':
jump => 'LOCAL_INPUT_PRE',
require => Firewallchain['LOCAL_INPUT_PRE:filter:IPv4'],
}
firewallchain { 'LOCAL_INPUT:filter:IPv4': }
firewall { '900 LOCAL_INPUT':
jump => 'LOCAL_INPUT',
require => Firewallchain['LOCAL_INPUT:filter:IPv4'],
}
firewallchain { 'INPUT:filter:IPv4':
policy => 'drop',
ignore => [
'-j fail2ban-ssh',
'--comment "[^"]*(?i:ignore)[^"]*"',
],
}
firewall { '010 allow established and related':
chain => 'FORWARD',
proto => 'all',
state => ['ESTABLISHED','RELATED'],
action => 'accept',
before => Firewallchain['FORWARD:filter:IPv4'],
}
firewallchain { 'FORWARD:filter:IPv4':
policy => 'drop',
}
firewallchain { 'OUTPUT:filter:IPv4': }
# purge unknown rules from mangle table
firewallchain { ['PREROUTING:mangle:IPv4', 'INPUT:mangle:IPv4', 'FORWARD:mangle:IPv4', 'OUTPUT:mangle:IPv4', 'POSTROUTING:mangle:IPv4']: }
# and the nat table
firewallchain { ['PREROUTING:nat:IPv4', 'INPUT:nat:IPv4', 'OUTPUT:nat:IPv4', 'POSTROUTING:nat:IPv4']: }
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
it 'contains appropriate rules' do
shell('iptables-save') do |r|
[
/INPUT DROP/,
/FORWARD DROP/,
/OUTPUT ACCEPT/,
/LOCAL_INPUT/,
/LOCAL_INPUT_PRE/,
/-A INPUT -m comment --comment \"001 LOCAL_INPUT_PRE\" -j LOCAL_INPUT_PRE/,
/-A INPUT -m comment --comment \"010 INPUT allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/,
/-A INPUT -i lo -m comment --comment \"012 accept loopback\" -j ACCEPT/,
/-A INPUT -p icmp -m comment --comment \"013 icmp destination-unreachable\" -m icmp --icmp-type 3 -j ACCEPT/,
/-A INPUT -s 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"013 icmp echo-request\" -m icmp --icmp-type 8 -j ACCEPT/,
/-A INPUT -p icmp -m comment --comment \"013 icmp time-exceeded\" -m icmp --icmp-type 11 -j ACCEPT/,
/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"020 ssh\" -m state --state NEW -j ACCEPT/,
/-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT/,
/-A INPUT -m comment --comment \"999 reject\" -j REJECT --reject-with icmp-host-prohibited/,
/-A FORWARD -m comment --comment \"010 allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/
].each do |line|
expect(r.stdout).to match(line)
end
end
end
end

View file

@ -0,0 +1,97 @@
require 'spec_helper_acceptance'
# RHEL5 does not support -m socket
describe 'firewall socket property', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) || default['platform'] =~ /el-5/ || fact('operatingsystem') == 'SLES') do
before :all do
iptables_flush_all_tables
end
shared_examples "is idempotent" do |value, line_match|
it "changes the value to #{value}" do
pp = <<-EOS
class { '::firewall': }
firewall { '598 - test':
ensure => present,
proto => 'tcp',
chain => 'PREROUTING',
table => 'raw',
#{value}
}
EOS
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
shell('iptables-save -t raw') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
shared_examples "doesn't change" do |value, line_match|
it "doesn't change the value to #{value}" do
pp = <<-EOS
class { '::firewall': }
firewall { '598 - test':
ensure => present,
proto => 'tcp',
chain => 'PREROUTING',
table => 'raw',
#{value}
}
EOS
apply_manifest(pp, :catch_changes => true)
shell('iptables-save -t raw') do |r|
expect(r.stdout).to match(/#{line_match}/)
end
end
end
describe 'adding a rule' do
context 'when unset' do
before :all do
iptables_flush_all_tables
end
it_behaves_like 'is idempotent', '', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
end
context 'when set to true' do
before :all do
iptables_flush_all_tables
end
it_behaves_like 'is idempotent', 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
end
context 'when set to false' do
before :all do
iptables_flush_all_tables
end
it_behaves_like "is idempotent", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
end
end
describe 'editing a rule' do
context 'when unset or false' do
before :each do
iptables_flush_all_tables
shell('iptables -t raw -A PREROUTING -p tcp -m comment --comment "598 - test"')
end
context 'and current value is false' do
it_behaves_like "doesn't change", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
end
context 'and current value is true' do
it_behaves_like "is idempotent", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
end
end
context 'when set to true' do
before :each do
iptables_flush_all_tables
shell('iptables -t raw -A PREROUTING -p tcp -m socket -m comment --comment "598 - test"')
end
context 'and current value is false' do
it_behaves_like "is idempotent", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
end
context 'and current value is true' do
it_behaves_like "doesn't change", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
end
end
end
end

View file

@ -0,0 +1,55 @@
require 'spec_helper_acceptance'
# Some tests for the standard recommended usage
describe 'standard usage tests:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
it 'applies twice' do
pp = <<-EOS
class my_fw::pre {
Firewall {
require => undef,
}
# Default firewall rules
firewall { '000 accept all icmp':
proto => 'icmp',
action => 'accept',
}->
firewall { '001 accept all to lo interface':
proto => 'all',
iniface => 'lo',
action => 'accept',
}->
firewall { '002 accept related established rules':
proto => 'all',
ctstate => ['RELATED', 'ESTABLISHED'],
action => 'accept',
}
}
class my_fw::post {
firewall { '999 drop all':
proto => 'all',
action => 'drop',
before => undef,
}
}
resources { "firewall":
purge => true
}
Firewall {
before => Class['my_fw::post'],
require => Class['my_fw::pre'],
}
class { ['my_fw::pre', 'my_fw::post']: }
class { 'firewall': }
firewall { '500 open up port 22':
action => 'accept',
proto => 'tcp',
dport => 22,
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
end
end

View file

@ -0,0 +1,10 @@
require 'spec_helper_acceptance'
describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
it 'should fail' do
pp = <<-EOS
class { 'firewall': }
EOS
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/not currently supported/i)
end
end

View file

@ -0,0 +1,107 @@
# These hashes allow us to iterate across a series of test data
# creating rspec examples for each parameter to ensure the input :line
# extrapolates to the desired value for the parameter in question. And
# vice-versa
# This hash is for testing a line conversion to a hash of parameters
# which will be used to create a resource.
ARGS_TO_HASH6 = {
'source_destination_ipv6_no_cidr' => {
:line => '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"',
:table => 'filter',
:provider => 'ip6tables',
:params => {
:source => '2001:db8:85a3::8a2e:370:7334/128',
:destination => '2001:db8:85a3::8a2e:370:7334/128',
},
},
'source_destination_ipv6_netmask' => {
:line => '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"',
:table => 'filter',
:provider => 'ip6tables',
:params => {
:source => '2001:db8:1234::/48',
:destination => '2001:db8:4321::/48',
},
},
}
# This hash is for testing converting a hash to an argument line.
HASH_TO_ARGS6 = {
'zero_prefixlen_ipv6' => {
:params => {
:name => '100 zero prefix length ipv6',
:table => 'filter',
:provider => 'ip6tables',
:source => '::/0',
:destination => '::/0',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'],
},
'source_destination_ipv4_no_cidr' => {
:params => {
:name => '000 source destination ipv4 no cidr',
:table => 'filter',
:provider => 'ip6tables',
:source => '1.1.1.1',
:destination => '2.2.2.2',
},
:args => ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'],
},
'source_destination_ipv6_no_cidr' => {
:params => {
:name => '000 source destination ipv6 no cidr',
:table => 'filter',
:provider => 'ip6tables',
:source => '2001:db8:1234::',
:destination => '2001:db8:4321::',
},
:args => ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'],
},
'source_destination_ipv6_netmask' => {
:params => {
:name => '000 source destination ipv6 netmask',
:table => 'filter',
:provider => 'ip6tables',
:source => '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
:destination => '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
},
:args => ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'],
},
'frag_ishasmorefrags' => {
:params => {
:name => "100 has more fragments",
:ishasmorefrags => true,
:provider => 'ip6tables',
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fragmore", "-m", "comment", "--comment", "100 has more fragments"],
},
'frag_islastfrag' => {
:params => {
:name => "100 last fragment",
:islastfrag => true,
:provider => 'ip6tables',
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fraglast", "-m", "comment", "--comment", "100 last fragment"],
},
'frag_isfirstfrags' => {
:params => {
:name => "100 first fragment",
:isfirstfrag => true,
:provider => 'ip6tables',
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fragfirst", "-m", "comment", "--comment", "100 first fragment"],
},
'hop_limit' => {
:params => {
:name => "100 hop limit",
:hop_limit => 255,
:provider => 'ip6tables',
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 hop limit", "-m", "hl", "--hl-eq", 255],
},
}

View file

@ -0,0 +1,934 @@
# These hashes allow us to iterate across a series of test data
# creating rspec examples for each parameter to ensure the input :line
# extrapolates to the desired value for the parameter in question. And
# vice-versa
# This hash is for testing a line conversion to a hash of parameters
# which will be used to create a resource.
ARGS_TO_HASH = {
'dport_and_sport' => {
:line => '-A nova-compute-FORWARD -s 0.0.0.0/32 -d 255.255.255.255/32 -p udp -m udp --sport 68 --dport 67 -j ACCEPT',
:table => 'filter',
:params => {
:action => 'accept',
:chain => 'nova-compute-FORWARD',
:source => '0.0.0.0/32',
:destination => '255.255.255.255/32',
:sport => ['68'],
:dport => ['67'],
:proto => 'udp',
},
},
'long_rule_1' => {
:line => '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -m comment --comment "000 allow foo" -j ACCEPT',
:table => 'filter',
:compare_all => true,
:params => {
:action => "accept",
:chain => "INPUT",
:destination => "1.1.1.1/32",
:dport => ["7061","7062"],
:ensure => :present,
:line => '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -m comment --comment "000 allow foo" -j ACCEPT',
:name => "000 allow foo",
:proto => "tcp",
:provider => "iptables",
:source => "1.1.1.1/32",
:sport => ["7061","7062"],
:table => "filter",
},
},
'action_drop_1' => {
:line => '-A INPUT -m comment --comment "000 allow foo" -j DROP',
:table => 'filter',
:params => {
:jump => nil,
:action => "drop",
},
},
'action_reject_1' => {
:line => '-A INPUT -m comment --comment "000 allow foo" -j REJECT',
:table => 'filter',
:params => {
:jump => nil,
:action => "reject",
},
},
'action_nil_1' => {
:line => '-A INPUT -m comment --comment "000 allow foo"',
:table => 'filter',
:params => {
:jump => nil,
:action => nil,
},
},
'jump_custom_chain_1' => {
:line => '-A INPUT -m comment --comment "000 allow foo" -j custom_chain',
:table => 'filter',
:params => {
:jump => "custom_chain",
:action => nil,
},
},
'source_destination_ipv4_no_cidr' => {
:line => '-A INPUT -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 source destination ipv4 no cidr"',
:table => 'filter',
:params => {
:source => '1.1.1.1/32',
:destination => '2.2.2.2/32',
},
},
'source_destination_ipv6_no_cidr' => {
:line => '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"',
:table => 'filter',
:params => {
:source => '2001:db8:85a3::8a2e:370:7334/128',
:destination => '2001:db8:85a3::8a2e:370:7334/128',
},
},
'source_destination_ipv4_netmask' => {
:line => '-A INPUT -s 1.1.1.0/255.255.255.0 -d 2.2.0.0/255.255.0.0 -m comment --comment "000 source destination ipv4 netmask"',
:table => 'filter',
:params => {
:source => '1.1.1.0/24',
:destination => '2.2.0.0/16',
},
},
'source_destination_ipv6_netmask' => {
:line => '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"',
:table => 'filter',
:params => {
:source => '2001:db8:1234::/48',
:destination => '2001:db8:4321::/48',
},
},
'source_destination_negate_source' => {
:line => '-A INPUT ! -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 negated source address"',
:table => 'filter',
:params => {
:source => '! 1.1.1.1/32',
:destination => '2.2.2.2/32',
},
},
'source_destination_negate_destination' => {
:line => '-A INPUT -s 1.1.1.1 ! -d 2.2.2.2 -m comment --comment "000 negated destination address"',
:table => 'filter',
:params => {
:source => '1.1.1.1/32',
:destination => '! 2.2.2.2/32',
},
},
'source_destination_negate_destination_alternative' => {
:line => '-A INPUT -s 1.1.1.1 -d ! 2.2.2.2 -m comment --comment "000 negated destination address alternative"',
:table => 'filter',
:params => {
:source => '1.1.1.1/32',
:destination => '! 2.2.2.2/32',
},
},
'dport_range_1' => {
:line => '-A INPUT -m multiport --dports 1:1024 -m comment --comment "000 allow foo"',
:table => 'filter',
:params => {
:dport => ["1-1024"],
},
},
'dport_range_2' => {
:line => '-A INPUT -m multiport --dports 15,512:1024 -m comment --comment "000 allow foo"',
:table => 'filter',
:params => {
:dport => ["15","512-1024"],
},
},
'sport_range_1' => {
:line => '-A INPUT -m multiport --sports 1:1024 -m comment --comment "000 allow foo"',
:table => 'filter',
:params => {
:sport => ["1-1024"],
},
},
'sport_range_2' => {
:line => '-A INPUT -m multiport --sports 15,512:1024 -m comment --comment "000 allow foo"',
:table => 'filter',
:params => {
:sport => ["15","512-1024"],
},
},
'dst_type_1' => {
:line => '-A INPUT -m addrtype --dst-type LOCAL',
:table => 'filter',
:params => {
:dst_type => 'LOCAL',
},
},
'src_type_1' => {
:line => '-A INPUT -m addrtype --src-type LOCAL',
:table => 'filter',
:params => {
:src_type => 'LOCAL',
},
},
'dst_range_1' => {
:line => '-A INPUT -m iprange --dst-range 10.0.0.2-10.0.0.20',
:table => 'filter',
:params => {
:dst_range => '10.0.0.2-10.0.0.20',
},
},
'src_range_1' => {
:line => '-A INPUT -m iprange --src-range 10.0.0.2-10.0.0.20',
:table => 'filter',
:params => {
:src_range => '10.0.0.2-10.0.0.20',
},
},
'tcp_flags_1' => {
:line => '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"',
:table => 'filter',
:compare_all => true,
:chain => 'INPUT',
:proto => 'tcp',
:params => {
:chain => "INPUT",
:ensure => :present,
:line => '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"',
:name => "000 initiation",
:proto => "tcp",
:provider => "iptables",
:table => "filter",
:tcp_flags => "SYN,RST,ACK,FIN SYN",
},
},
'state_returns_sorted_values' => {
:line => '-A INPUT -m state --state INVALID,RELATED,ESTABLISHED',
:table => 'filter',
:params => {
:state => ['ESTABLISHED', 'INVALID', 'RELATED'],
:action => nil,
},
},
'ctstate_returns_sorted_values' => {
:line => '-A INPUT -m conntrack --ctstate INVALID,RELATED,ESTABLISHED',
:table => 'filter',
:params => {
:ctstate => ['ESTABLISHED', 'INVALID', 'RELATED'],
:action => nil,
},
},
'comment_string_character_validation' => {
:line => '-A INPUT -s 192.168.0.1/32 -m comment --comment "000 allow from 192.168.0.1, please"',
:table => 'filter',
:params => {
:source => '192.168.0.1/32',
},
},
'log_level_debug' => {
:line => '-A INPUT -m comment --comment "956 INPUT log-level" -m state --state NEW -j LOG --log-level 7',
:table => 'filter',
:params => {
:state => ['NEW'],
:log_level => '7',
:jump => 'LOG'
},
},
'log_level_warn' => {
:line => '-A INPUT -m comment --comment "956 INPUT log-level" -m state --state NEW -j LOG',
:table => 'filter',
:params => {
:state => ['NEW'],
:log_level => '4',
:jump => 'LOG'
},
},
'load_limit_module_and_implicit_burst' => {
:line => '-A INPUT -m multiport --dports 123 -m comment --comment "057 INPUT limit NTP" -m limit --limit 15/hour',
:table => 'filter',
:params => {
:dport => ['123'],
:limit => '15/hour',
:burst => '5'
},
},
'limit_with_explicit_burst' => {
:line => '-A INPUT -m multiport --dports 123 -m comment --comment "057 INPUT limit NTP" -m limit --limit 30/hour --limit-burst 10',
:table => 'filter',
:params => {
:dport => ['123'],
:limit => '30/hour',
:burst => '10'
},
},
'proto_ipencap' => {
:line => '-A INPUT -p ipencap -m comment --comment "0100 INPUT accept ipencap"',
:table => 'filter',
:params => {
:proto => 'ipencap',
}
},
'load_uid_owner_filter_module' => {
:line => '-A OUTPUT -m owner --uid-owner root -m comment --comment "057 OUTPUT uid root only" -j ACCEPT',
:table => 'filter',
:params => {
:action => 'accept',
:uid => 'root',
:chain => 'OUTPUT',
},
},
'load_uid_owner_postrouting_module' => {
:line => '-t mangle -A POSTROUTING -m owner --uid-owner root -m comment --comment "057 POSTROUTING uid root only" -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'POSTROUTING',
:uid => 'root',
},
},
'load_gid_owner_filter_module' => {
:line => '-A OUTPUT -m owner --gid-owner root -m comment --comment "057 OUTPUT gid root only" -j ACCEPT',
:table => 'filter',
:params => {
:action => 'accept',
:chain => 'OUTPUT',
:gid => 'root',
},
},
'load_gid_owner_postrouting_module' => {
:line => '-t mangle -A POSTROUTING -m owner --gid-owner root -m comment --comment "057 POSTROUTING gid root only" -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'POSTROUTING',
:gid => 'root',
},
},
'mark_set-mark' => {
:line => '-t mangle -A PREROUTING -j MARK --set-xmark 0x3e8/0xffffffff',
:table => 'mangle',
:params => {
:jump => 'MARK',
:chain => 'PREROUTING',
:set_mark => '0x3e8/0xffffffff',
}
},
'iniface_1' => {
:line => '-A INPUT -i eth0 -m comment --comment "060 iniface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth0',
},
},
'iniface_with_vlans_1' => {
:line => '-A INPUT -i eth0.234 -m comment --comment "060 iniface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth0.234',
},
},
'iniface_with_plus_1' => {
:line => '-A INPUT -i eth+ -m comment --comment "060 iniface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth+',
},
},
'outiface_1' => {
:line => '-A OUTPUT -o eth0 -m comment --comment "060 outiface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth0',
},
},
'outiface_with_vlans_1' => {
:line => '-A OUTPUT -o eth0.234 -m comment --comment "060 outiface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth0.234',
},
},
'outiface_with_plus_1' => {
:line => '-A OUTPUT -o eth+ -m comment --comment "060 outiface" -j DROP',
:table => 'filter',
:params => {
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth+',
},
},
'pkttype multicast' => {
:line => '-A INPUT -m pkttype --pkt-type multicast -j ACCEPT',
:table => 'filter',
:params => {
:action => 'accept',
:pkttype => 'multicast',
},
},
'socket_option' => {
:line => '-A PREROUTING -m socket -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'PREROUTING',
:socket => true,
},
},
'isfragment_option' => {
:line => '-A INPUT -f -m comment --comment "010 a-f comment with dashf" -j ACCEPT',
:table => 'filter',
:params => {
:name => '010 a-f comment with dashf',
:action => 'accept',
:isfragment => true,
},
},
'single_tcp_sport' => {
:line => '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --sport 20443 -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'OUTPUT',
:source => "10.94.100.46/32",
:proto => "tcp",
:sport => ["20443"],
},
},
'single_udp_sport' => {
:line => '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --sport 20443 -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'OUTPUT',
:source => "10.94.100.46/32",
:proto => "udp",
:sport => ["20443"],
},
},
'single_tcp_dport' => {
:line => '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --dport 20443 -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'OUTPUT',
:source => "10.94.100.46/32",
:proto => "tcp",
:dport => ["20443"],
},
},
'single_udp_dport' => {
:line => '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --dport 20443 -j ACCEPT',
:table => 'mangle',
:params => {
:action => 'accept',
:chain => 'OUTPUT',
:source => "10.94.100.46/32",
:proto => "udp",
:dport => ["20443"],
},
},
'connlimit_above' => {
:line => '-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "061 REJECT connlimit_above 10" -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with icmp-port-unreachable',
:table => 'filter',
:params => {
:proto => 'tcp',
:dport => ["22"],
:connlimit_above => '10',
:action => 'reject',
},
},
'connlimit_above_with_connlimit_mask' => {
:line => '-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "061 REJECT connlimit_above 10 with mask 24" -m connlimit --connlimit-above 10 --connlimit-mask 24 -j REJECT --reject-with icmp-port-unreachable',
:table => 'filter',
:params => {
:proto => 'tcp',
:dport => ["22"],
:connlimit_above => '10',
:connlimit_mask => '24',
:action => 'reject',
},
},
'connmark' => {
:line => '-A INPUT -m comment --comment "062 REJECT connmark" -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable',
:table => 'filter',
:params => {
:proto => 'all',
:connmark => '0x1',
:action => 'reject',
},
},
}
# This hash is for testing converting a hash to an argument line.
HASH_TO_ARGS = {
'long_rule_1' => {
:params => {
:action => "accept",
:chain => "INPUT",
:destination => "1.1.1.1",
:dport => ["7061","7062"],
:ensure => :present,
:name => "000 allow foo",
:proto => "tcp",
:source => "1.1.1.1",
:sport => ["7061","7062"],
:table => "filter",
},
:args => ["-t", :filter, "-s", "1.1.1.1/32", "-d", "1.1.1.1/32", "-p", :tcp, "-m", "multiport", "--sports", "7061,7062", "-m", "multiport", "--dports", "7061,7062", "-m", "comment", "--comment", "000 allow foo", "-j", "ACCEPT"],
},
'long_rule_2' => {
:params => {
:chain => "INPUT",
:destination => "2.10.13.3/24",
:dport => ["7061"],
:ensure => :present,
:jump => "my_custom_chain",
:name => "700 allow bar",
:proto => "udp",
:source => "1.1.1.1",
:sport => ["7061","7062"],
:table => "filter",
},
:args => ["-t", :filter, "-s", "1.1.1.1/32", "-d", "2.10.13.0/24", "-p", :udp, "-m", "multiport", "--sports", "7061,7062", "-m", "multiport", "--dports", "7061", "-m", "comment", "--comment", "700 allow bar", "-j", "my_custom_chain"],
},
'no_action' => {
:params => {
:name => "100 no action",
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment",
"100 no action"],
},
'zero_prefixlen_ipv4' => {
:params => {
:name => '100 zero prefix length ipv4',
:table => 'filter',
:source => '0.0.0.0/0',
:destination => '0.0.0.0/0',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv4'],
},
'zero_prefixlen_ipv6' => {
:params => {
:name => '100 zero prefix length ipv6',
:table => 'filter',
:source => '::/0',
:destination => '::/0',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'],
},
'source_destination_ipv4_no_cidr' => {
:params => {
:name => '000 source destination ipv4 no cidr',
:table => 'filter',
:source => '1.1.1.1',
:destination => '2.2.2.2',
},
:args => ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'],
},
'source_destination_ipv6_no_cidr' => {
:params => {
:name => '000 source destination ipv6 no cidr',
:table => 'filter',
:source => '2001:db8:1234::',
:destination => '2001:db8:4321::',
},
:args => ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'],
},
'source_destination_ipv4_netmask' => {
:params => {
:name => '000 source destination ipv4 netmask',
:table => 'filter',
:source => '1.1.1.0/255.255.255.0',
:destination => '2.2.0.0/255.255.0.0',
},
:args => ['-t', :filter, '-s', '1.1.1.0/24', '-d', '2.2.0.0/16', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 netmask'],
},
'source_destination_ipv6_netmask' => {
:params => {
:name => '000 source destination ipv6 netmask',
:table => 'filter',
:source => '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
:destination => '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
},
:args => ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'],
},
'sport_range_1' => {
:params => {
:name => "100 sport range",
:sport => ["1-1024"],
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--sports", "1:1024", "-m", "comment", "--comment", "100 sport range"],
},
'sport_range_2' => {
:params => {
:name => "100 sport range",
:sport => ["15","512-1024"],
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--sports", "15,512:1024", "-m", "comment", "--comment", "100 sport range"],
},
'dport_range_1' => {
:params => {
:name => "100 sport range",
:dport => ["1-1024"],
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "1:1024", "-m", "comment", "--comment", "100 sport range"],
},
'dport_range_2' => {
:params => {
:name => "100 sport range",
:dport => ["15","512-1024"],
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "15,512:1024", "-m", "comment", "--comment", "100 sport range"],
},
'dst_type_1' => {
:params => {
:name => '000 dst_type',
:table => 'filter',
:dst_type => 'LOCAL',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', :LOCAL, '-m', 'comment', '--comment', '000 dst_type'],
},
'src_type_1' => {
:params => {
:name => '000 src_type',
:table => 'filter',
:src_type => 'LOCAL',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', :LOCAL, '-m', 'comment', '--comment', '000 src_type'],
},
'dst_range_1' => {
:params => {
:name => '000 dst_range',
:table => 'filter',
:dst_range => '10.0.0.1-10.0.0.10',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 dst_range'],
},
'src_range_1' => {
:params => {
:name => '000 src_range',
:table => 'filter',
:dst_range => '10.0.0.1-10.0.0.10',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 src_range'],
},
'tcp_flags_1' => {
:params => {
:name => "000 initiation",
:tcp_flags => "SYN,RST,ACK,FIN SYN",
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "tcp", "--tcp-flags", "SYN,RST,ACK,FIN", "SYN", "-m", "comment", "--comment", "000 initiation",]
},
'states_set_from_array' => {
:params => {
:name => "100 states_set_from_array",
:table => "filter",
:state => ['ESTABLISHED', 'INVALID']
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 states_set_from_array",
"-m", "state", "--state", "ESTABLISHED,INVALID"],
},
'ctstates_set_from_array' => {
:params => {
:name => "100 ctstates_set_from_array",
:table => "filter",
:ctstate => ['ESTABLISHED', 'INVALID']
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 ctstates_set_from_array",
"-m", "conntrack", "--ctstate", "ESTABLISHED,INVALID"],
},
'comment_string_character_validation' => {
:params => {
:name => "000 allow from 192.168.0.1, please",
:table => 'filter',
:source => '192.168.0.1'
},
:args => ['-t', :filter, '-s', '192.168.0.1/32', '-p', :tcp, '-m', 'comment', '--comment', '000 allow from 192.168.0.1, please'],
},
'port_property' => {
:params => {
:name => '001 port property',
:table => 'filter',
:port => '80',
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--ports', '80', '-m', 'comment', '--comment', '001 port property'],
},
'log_level_debug' => {
:params => {
:name => '956 INPUT log-level',
:table => 'filter',
:state => 'NEW',
:jump => 'LOG',
:log_level => 'debug'
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '956 INPUT log-level', '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '7'],
},
'log_level_warn' => {
:params => {
:name => '956 INPUT log-level',
:table => 'filter',
:state => 'NEW',
:jump => 'LOG',
:log_level => 'warn'
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '956 INPUT log-level', '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '4'],
},
'load_limit_module_and_implicit_burst' => {
:params => {
:name => '057 INPUT limit NTP',
:table => 'filter',
:dport => '123',
:limit => '15/hour'
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'comment', '--comment', '057 INPUT limit NTP', '-m', 'limit', '--limit', '15/hour'],
},
'limit_with_explicit_burst' => {
:params => {
:name => '057 INPUT limit NTP',
:table => 'filter',
:dport => '123',
:limit => '30/hour',
:burst => '10'
},
:args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'comment', '--comment', '057 INPUT limit NTP', '-m', 'limit', '--limit', '30/hour', '--limit-burst', '10'],
},
'proto_ipencap' => {
:params => {
:name => '0100 INPUT accept ipencap',
:table => 'filter',
:proto => 'ipencap',
},
:args => ['-t', :filter, '-p', :ipencap, '-m', 'comment', '--comment', '0100 INPUT accept ipencap'],
},
'load_uid_owner_filter_module' => {
:params => {
:name => '057 OUTPUT uid root only',
:table => 'filter',
:uid => 'root',
:action => 'accept',
:chain => 'OUTPUT',
:proto => 'all',
},
:args => ['-t', :filter, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-m', 'comment', '--comment', '057 OUTPUT uid root only', '-j', 'ACCEPT'],
},
'load_uid_owner_postrouting_module' => {
:params => {
:name => '057 POSTROUTING uid root only',
:table => 'mangle',
:uid => 'root',
:action => 'accept',
:chain => 'POSTROUTING',
:proto => 'all',
},
:args => ['-t', :mangle, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-m', 'comment', '--comment', '057 POSTROUTING uid root only', '-j', 'ACCEPT'],
},
'load_gid_owner_filter_module' => {
:params => {
:name => '057 OUTPUT gid root only',
:table => 'filter',
:chain => 'OUTPUT',
:gid => 'root',
:action => 'accept',
:proto => 'all',
},
:args => ['-t', :filter, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-m', 'comment', '--comment', '057 OUTPUT gid root only', '-j', 'ACCEPT'],
},
'load_gid_owner_postrouting_module' => {
:params => {
:name => '057 POSTROUTING gid root only',
:table => 'mangle',
:gid => 'root',
:action => 'accept',
:chain => 'POSTROUTING',
:proto => 'all',
},
:args => ['-t', :mangle, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-m', 'comment', '--comment', '057 POSTROUTING gid root only', '-j', 'ACCEPT'],
},
'mark_set-mark_int' => {
:params => {
:name => '058 set-mark 1000',
:table => 'mangle',
:jump => 'MARK',
:chain => 'PREROUTING',
:set_mark => '1000',
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 1000', '-j', 'MARK', '--set-xmark', '0x3e8/0xffffffff'],
},
'mark_set-mark_hex' => {
:params => {
:name => '058 set-mark 0x32',
:table => 'mangle',
:jump => 'MARK',
:chain => 'PREROUTING',
:set_mark => '0x32',
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32', '-j', 'MARK', '--set-xmark', '0x32/0xffffffff'],
},
'mark_set-mark_hex_with_hex_mask' => {
:params => {
:name => '058 set-mark 0x32/0xffffffff',
:table => 'mangle',
:jump => 'MARK',
:chain => 'PREROUTING',
:set_mark => '0x32/0xffffffff',
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32/0xffffffff', '-j', 'MARK', '--set-xmark', '0x32/0xffffffff'],
},
'mark_set-mark_hex_with_mask' => {
:params => {
:name => '058 set-mark 0x32/4',
:table => 'mangle',
:jump => 'MARK',
:chain => 'PREROUTING',
:set_mark => '0x32/4',
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32/4', '-j', 'MARK', '--set-xmark', '0x32/0x4'],
},
'iniface_1' => {
:params => {
:name => '060 iniface',
:table => 'filter',
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth0',
},
:args => ["-t", :filter, "-i", "eth0", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
},
'iniface_with_vlans_1' => {
:params => {
:name => '060 iniface',
:table => 'filter',
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth0.234',
},
:args => ["-t", :filter, "-i", "eth0.234", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
},
'iniface_with_plus_1' => {
:params => {
:name => '060 iniface',
:table => 'filter',
:action => 'drop',
:chain => 'INPUT',
:iniface => 'eth+',
},
:args => ["-t", :filter, "-i", "eth+", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
},
'outiface_1' => {
:params => {
:name => '060 outiface',
:table => 'filter',
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth0',
},
:args => ["-t", :filter, "-o", "eth0", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
},
'outiface_with_vlans_1' => {
:params => {
:name => '060 outiface',
:table => 'filter',
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth0.234',
},
:args => ["-t", :filter, "-o", "eth0.234", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
},
'outiface_with_plus_1' => {
:params => {
:name => '060 outiface',
:table => 'filter',
:action => 'drop',
:chain => 'OUTPUT',
:outiface => 'eth+',
},
:args => ["-t", :filter, "-o", "eth+", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
},
'pkttype multicast' => {
:params => {
:name => '062 pkttype multicast',
:table => "filter",
:action => 'accept',
:chain => 'INPUT',
:iniface => 'eth0',
:pkttype => 'multicast',
},
:args => ["-t", :filter, "-i", "eth0", "-p", :tcp, "-m", "pkttype", "--pkt-type", :multicast, "-m", "comment", "--comment", "062 pkttype multicast", "-j", "ACCEPT"],
},
'socket_option' => {
:params => {
:name => '050 socket option',
:table => 'mangle',
:action => 'accept',
:chain => 'PREROUTING',
:socket => true,
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'socket', '-m', 'comment', '--comment', '050 socket option', '-j', 'ACCEPT'],
},
'isfragment_option' => {
:params => {
:name => '050 isfragment option',
:table => 'filter',
:proto => :all,
:action => 'accept',
:isfragment => true,
},
:args => ['-t', :filter, '-p', :all, '-f', '-m', 'comment', '--comment', '050 isfragment option', '-j', 'ACCEPT'],
},
'isfragment_option not changing -f in comment' => {
:params => {
:name => '050 testcomment-with-fdashf',
:table => 'filter',
:proto => :all,
:action => 'accept',
},
:args => ['-t', :filter, '-p', :all, '-m', 'comment', '--comment', '050 testcomment-with-fdashf', '-j', 'ACCEPT'],
},
'connlimit_above' => {
:params => {
:name => '061 REJECT connlimit_above 10',
:table => 'filter',
:proto => 'tcp',
:dport => ["22"],
:connlimit_above => '10',
:action => 'reject',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "22", "-m", "comment", "--comment", "061 REJECT connlimit_above 10", "-j", "REJECT", "-m", "connlimit", "--connlimit-above", "10"],
},
'connlimit_above_with_connlimit_mask' => {
:params => {
:name => '061 REJECT connlimit_above 10 with mask 24',
:table => 'filter',
:proto => 'tcp',
:dport => ["22"],
:connlimit_above => '10',
:connlimit_mask => '24',
:action => 'reject',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "22", "-m", "comment", "--comment", "061 REJECT connlimit_above 10 with mask 24", "-j", "REJECT", "-m", "connlimit", "--connlimit-above", "10", "--connlimit-mask", "24"],
},
'connmark' => {
:params => {
:name => '062 REJECT connmark',
:table => 'filter',
:proto => 'all',
:connmark => '0x1',
:action => 'reject',
},
:args => ["-t", :filter, "-p", :all, "-m", "comment", "--comment", "062 REJECT connmark", "-j", "REJECT", "-m", "connmark", "--mark", "0x1"],
},
}

View file

@ -0,0 +1,29 @@
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')
# Don't want puppet getting the command line arguments for rake or autotest
ARGV.clear
require 'rubygems'
require 'bundler/setup'
require 'rspec-puppet'
Bundler.require :default, :test
require 'pathname'
require 'tmpdir'
Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour|
require behaviour.relative_path_from(Pathname.new(dir))
end
fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
RSpec.configure do |config|
config.tty = true
config.mock_with :rspec do |c|
c.syntax = :expect
end
config.module_path = File.join(fixture_path, 'modules')
config.manifest_dir = File.join(fixture_path, 'manifests')
end

View file

@ -0,0 +1,44 @@
require 'beaker-rspec'
def iptables_flush_all_tables
['filter', 'nat', 'mangle', 'raw'].each do |t|
expect(shell("iptables -t #{t} -F").stderr).to eq("")
end
end
def ip6tables_flush_all_tables
['filter'].each do |t|
expect(shell("ip6tables -t #{t} -F").stderr).to eq("")
end
end
unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
if hosts.first.is_pe?
install_pe
else
install_puppet
end
hosts.each do |host|
on host, "mkdir -p #{host['distmoduledir']}"
end
end
UNSUPPORTED_PLATFORMS = ['windows','Solaris','Darwin']
RSpec.configure do |c|
# Project root
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
# Readable test descriptions
c.formatter = :documentation
# Configure all nodes in nodeset
c.before :suite do
# Install module and dependencies
puppet_module_install(:source => proj_root, :module_name => 'firewall')
hosts.each do |host|
shell('/bin/touch /etc/puppet/hiera.yaml')
shell('puppet module install puppetlabs-stdlib --version 3.2.0', { :acceptable_exit_codes => [0,1] })
end
end
end

View file

@ -0,0 +1,32 @@
require 'spec_helper'
describe 'firewall::linux::archlinux', :type => :class do
it { should contain_service('iptables').with(
:ensure => 'running',
:enable => 'true'
)}
it { should contain_service('ip6tables').with(
:ensure => 'running',
:enable => 'true'
)}
context 'ensure => stopped' do
let(:params) {{ :ensure => 'stopped' }}
it { should contain_service('iptables').with(
:ensure => 'stopped'
)}
it { should contain_service('ip6tables').with(
:ensure => 'stopped'
)}
end
context 'enable => false' do
let(:params) {{ :enable => 'false' }}
it { should contain_service('iptables').with(
:enable => 'false'
)}
it { should contain_service('ip6tables').with(
:enable => 'false'
)}
end
end

View file

@ -0,0 +1,19 @@
require 'spec_helper'
describe 'firewall::linux::debian', :type => :class do
it { should contain_package('iptables-persistent').with(
:ensure => 'present'
)}
it { should contain_service('iptables-persistent').with(
:ensure => nil,
:enable => 'true',
:require => 'Package[iptables-persistent]'
)}
context 'enable => false' do
let(:params) {{ :enable => 'false' }}
it { should contain_service('iptables-persistent').with(
:enable => 'false'
)}
end
end

View file

@ -0,0 +1,22 @@
require 'spec_helper'
describe 'firewall::linux::redhat', :type => :class do
it { should contain_service('iptables').with(
:ensure => 'running',
:enable => 'true'
)}
context 'ensure => stopped' do
let(:params) {{ :ensure => 'stopped' }}
it { should contain_service('iptables').with(
:ensure => 'stopped'
)}
end
context 'enable => false' do
let(:params) {{ :enable => 'false' }}
it { should contain_service('iptables').with(
:enable => 'false'
)}
end
end

View file

@ -0,0 +1,30 @@
require 'spec_helper'
describe 'firewall::linux', :type => :class do
let(:facts_default) {{ :kernel => 'Linux' }}
it { should contain_package('iptables').with_ensure('present') }
context 'RedHat like' do
%w{RedHat CentOS Fedora}.each do |os|
context "operatingsystem => #{os}" do
releases = (os == 'Fedora' ? [14,15,'Rawhide'] : [6,7])
releases.each do |osrel|
context "operatingsystemrelease => #{osrel}" do
let(:facts) { facts_default.merge({ :operatingsystem => os,
:operatingsystemrelease => osrel}) }
it { should contain_class('firewall::linux::redhat').with_require('Package[iptables]') }
end
end
end
end
end
context 'Debian like' do
%w{Debian Ubuntu}.each do |os|
context "operatingsystem => #{os}" do
let(:facts) { facts_default.merge({ :operatingsystem => os }) }
it { should contain_class('firewall::linux::debian').with_require('Package[iptables]') }
end
end
end
end

View file

@ -0,0 +1,25 @@
require 'spec_helper'
describe 'firewall', :type => :class do
context 'kernel => Linux' do
let(:facts) {{ :kernel => 'Linux' }}
it { should contain_class('firewall::linux').with_ensure('running') }
end
context 'kernel => Windows' do
let(:facts) {{ :kernel => 'Windows' }}
it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
end
context 'ensure => stopped' do
let(:facts) {{ :kernel => 'Linux' }}
let(:params) {{ :ensure => 'stopped' }}
it { should contain_class('firewall::linux').with_ensure('stopped') }
end
context 'ensure => test' do
let(:facts) {{ :kernel => 'Linux' }}
let(:params) {{ :ensure => 'test' }}
it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
end
end

View file

@ -0,0 +1,35 @@
require 'spec_helper'
describe "Facter::Util::Fact iptables_persistent_version" do
before { Facter.clear }
let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" }
{
"Debian" => "0.0.20090701",
"Ubuntu" => "0.5.3ubuntu2",
}.each do |os, ver|
describe "#{os} package installed" do
before {
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return(os)
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(ver)
}
it { Facter.fact(:iptables_persistent_version).value.should == ver }
end
end
describe 'Ubuntu package not installed' do
before {
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(nil)
}
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
end
describe 'CentOS not supported' do
before { allow(Facter.fact(:operatingsystem)).to receive(:value).
and_return("CentOS") }
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
end
end

View file

@ -0,0 +1,23 @@
require 'spec_helper'
describe "Facter::Util::Fact" do
before {
Facter.clear
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
allow(Facter.fact(:kernelrelease)).to receive(:value).and_return('2.6')
}
describe 'iptables_version' do
it {
allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version').
and_return('iptables v1.4.7')
Facter.fact(:iptables_version).value.should == '1.4.7'
}
end
describe 'ip6tables_version' do
before { allow(Facter::Util::Resolution).to receive(:exec).
with('ip6tables --version').and_return('ip6tables v1.4.7') }
it { Facter.fact(:ip6tables_version).value.should == '1.4.7' }
end
end

View file

@ -0,0 +1,227 @@
#!/usr/bin/env rspec
require 'spec_helper'
if Puppet.version < '3.4.0'
require 'puppet/provider/confine/exists'
else
require 'puppet/confine/exists'
end
describe 'iptables chain provider detection' do
if Puppet.version < '3.4.0'
let(:exists) {
Puppet::Provider::Confine::Exists
}
else
let(:exists) {
Puppet::Confine::Exists
}
end
before :each do
# Reset the default provider
Puppet::Type.type(:firewallchain).defaultprovider = nil
end
it "should default to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists" do
# Stub lookup for /sbin/iptables & /sbin/iptables-save
allow(exists).to receive(:which).with("ebtables").
and_return "/sbin/ebtables"
allow(exists).to receive(:which).with("ebtables-save").
and_return "/sbin/ebtables-save"
allow(exists).to receive(:which).with("iptables").
and_return "/sbin/iptables"
allow(exists).to receive(:which).with("iptables-save").
and_return "/sbin/iptables-save"
allow(exists).to receive(:which).with("ip6tables").
and_return "/sbin/ip6tables"
allow(exists).to receive(:which).with("ip6tables-save").
and_return "/sbin/ip6tables-save"
# Every other command should return false so we don't pick up any
# other providers
allow(exists).to receive(:which).with() { |value|
value !~ /(eb|ip|ip6)tables(-save)?$/
}.and_return false
# Create a resource instance and make sure the provider is iptables
resource = Puppet::Type.type(:firewallchain).new({
:name => 'test:filter:IPv4',
})
expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewallchain::ProviderIptables_chain")
end
end
describe 'iptables chain provider' do
let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }
let(:resource) {
Puppet::Type.type(:firewallchain).new({
:name => ':test:',
})
}
before :each do
allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
allow(provider).to receive(:command).with(:ebtables_save).and_return "/sbin/ebtables-save"
allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"
allow(provider).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"
end
it 'should be able to get a list of existing rules' do
# Pretend to return nil from iptables
allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return("")
allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return("")
allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return("")
provider.instances.each do |chain|
expect(chain).to be_instance_of(provider)
expect(chain.properties[:provider].to_s).to eq(provider.name.to_s)
end
end
end
describe 'iptables chain resource parsing' do
let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }
before :each do
ebtables = ['BROUTE:BROUTING:ethernet',
'BROUTE:broute:ethernet',
':INPUT:ethernet',
':FORWARD:ethernet',
':OUTPUT:ethernet',
':filter:ethernet',
':filterdrop:ethernet',
':filterreturn:ethernet',
'NAT:PREROUTING:ethernet',
'NAT:OUTPUT:ethernet',
'NAT:POSTROUTING:ethernet',
]
allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return('
*broute
:BROUTING ACCEPT
:broute ACCEPT
*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
:filter ACCEPT
:filterdrop DROP
:filterreturn RETURN
*nat
:PREROUTING ACCEPT
:OUTPUT ACCEPT
:POSTROUTING ACCEPT
')
iptables = [
'raw:PREROUTING:IPv4',
'raw:OUTPUT:IPv4',
'raw:raw:IPv4',
'mangle:PREROUTING:IPv4',
'mangle:INPUT:IPv4',
'mangle:FORWARD:IPv4',
'mangle:OUTPUT:IPv4',
'mangle:POSTROUTING:IPv4',
'mangle:mangle:IPv4',
'NAT:PREROUTING:IPv4',
'NAT:OUTPUT:IPv4',
'NAT:POSTROUTING:IPv4',
'NAT:mangle:IPv4',
'NAT:mangle:IPv4',
'NAT:mangle:IPv4',
':$5()*&%\'"^$): :IPv4',
]
allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return('
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
*raw
:PREROUTING ACCEPT [12:1780]
:OUTPUT ACCEPT [19:1159]
:raw - [0:0]
COMMIT
# Completed on Mon Jan 2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
*mangle
:PREROUTING ACCEPT [12:1780]
:INPUT ACCEPT [12:1780]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [19:1159]
:POSTROUTING ACCEPT [19:1159]
:mangle - [0:0]
COMMIT
# Completed on Mon Jan 2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
*nat
:PREROUTING ACCEPT [2242:639750]
:OUTPUT ACCEPT [5176:326206]
:POSTROUTING ACCEPT [5162:325382]
COMMIT
# Completed on Mon Jan 2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [5673:420879]
:$5()*&%\'"^$): - [0:0]
COMMIT
# Completed on Mon Jan 2 01:20:06 2012
')
ip6tables = [
'raw:PREROUTING:IPv6',
'raw:OUTPUT:IPv6',
'raw:ff:IPv6',
'mangle:PREROUTING:IPv6',
'mangle:INPUT:IPv6',
'mangle:FORWARD:IPv6',
'mangle:OUTPUT:IPv6',
'mangle:POSTROUTING:IPv6',
'mangle:ff:IPv6',
':INPUT:IPv6',
':FORWARD:IPv6',
':OUTPUT:IPv6',
':test:IPv6',
]
allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return('
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
*raw
:PREROUTING ACCEPT [2173:489241]
:OUTPUT ACCEPT [0:0]
:ff - [0:0]
COMMIT
# Completed on Mon Jan 2 01:31:39 2012
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
*mangle
:PREROUTING ACCEPT [2301:518373]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:ff - [0:0]
COMMIT
# Completed on Mon Jan 2 01:31:39 2012
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [20:1292]
:test - [0:0]
COMMIT
# Completed on Mon Jan 2 01:31:39 2012
')
@all = ebtables + iptables + ip6tables
# IPv4 and IPv6 names also exist as resources {table}:{chain}:IP and {table}:{chain}:
iptables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
ip6tables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
end
it 'should have all in parsed resources' do
provider.instances.each do |resource|
@all.include?(resource.name)
end
end
end

View file

@ -0,0 +1,410 @@
#!/usr/bin/env rspec
require 'spec_helper'
if Puppet.version < '3.4.0'
require 'puppet/provider/confine/exists'
else
require 'puppet/confine/exists'
end
describe 'iptables provider detection' do
if Puppet.version < '3.4.0'
let(:exists) {
Puppet::Provider::Confine::Exists
}
else
let(:exists) {
Puppet::Confine::Exists
}
end
before :each do
# Reset the default provider
Puppet::Type.type(:firewall).defaultprovider = nil
end
it "should default to iptables provider if /sbin/iptables[-save] exists" do
# Stub lookup for /sbin/iptables & /sbin/iptables-save
allow(exists).to receive(:which).with("iptables").
and_return "/sbin/iptables"
allow(exists).to receive(:which).with("iptables-save").
and_return "/sbin/iptables-save"
# Every other command should return false so we don't pick up any
# other providers
allow(exists).to receive(:which).with() { |value|
! ["iptables","iptables-save"].include?(value)
}.and_return false
# Create a resource instance and make sure the provider is iptables
resource = Puppet::Type.type(:firewall).new({
:name => '000 test foo',
})
expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewall::ProviderIptables")
end
end
describe 'iptables provider' do
let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
let(:resource) {
Puppet::Type.type(:firewall).new({
:name => '000 test foo',
:action => 'accept',
})
}
before :each do
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider
allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"
# Stub iptables version
allow(Facter.fact(:iptables_version)).to receive(:value).and_return("1.4.2")
allow(Puppet::Util::Execution).to receive(:execute).and_return ""
allow(Puppet::Util).to receive(:which).with("iptables-save").
and_return "/sbin/iptables-save"
end
it 'should be able to get a list of existing rules' do
provider.instances.each do |rule|
expect(rule).to be_instance_of(provider)
expect(rule.properties[:provider].to_s).to eq(provider.name.to_s)
end
end
it 'should ignore lines with fatal errors' do
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/iptables-save']).
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
expect(provider.instances.length).to be_zero
end
describe '#insert_order' do
let(:iptables_save_output) { [
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -m comment --comment "200 test" -j ACCEPT',
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT'
] }
let(:resources) do
iptables_save_output.each_with_index.collect { |l,index| provider.rule_to_hash(l, 'filter', index) }
end
let(:providers) do
resources.collect { |r| provider.new(r) }
end
it 'understands offsets for adding rules to the beginning' do
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(1) # 1-indexed
end
it 'understands offsets for editing rules at the beginning' do
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(1)
end
it 'understands offsets for adding rules to the middle' do
resource = Puppet::Type.type(:firewall).new({ :name => '101 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(2)
end
it 'understands offsets for editing rules at the middle' do
resource = Puppet::Type.type(:firewall).new({ :name => '200 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(2)
end
it 'understands offsets for adding rules to the end' do
resource = Puppet::Type.type(:firewall).new({ :name => '301 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(4)
end
it 'understands offsets for editing rules at the end' do
resource = Puppet::Type.type(:firewall).new({ :name => '300 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(3)
end
context 'with unname rules between' do
let(:iptables_save_output) { [
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
] }
it 'understands offsets for adding rules before unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(1)
end
it 'understands offsets for editing rules before unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(1)
end
it 'understands offsets for adding rules between managed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(2)
end
it 'understands offsets for adding rules between unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(3)
end
it 'understands offsets for adding rules after unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(7)
end
end
context 'with unname rules before and after' do
let(:iptables_save_output) { [
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 050 -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 090 -j ACCEPT',
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
'-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 400 -j ACCEPT',
'-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 450 -j ACCEPT',
] }
it 'understands offsets for adding rules before unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(1)
end
it 'understands offsets for editing rules before unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(3)
end
it 'understands offsets for adding rules between managed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(4)
end
it 'understands offsets for adding rules between unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(5)
end
it 'understands offsets for adding rules after unnamed rules' do
resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(9)
end
it 'understands offsets for adding rules at the end' do
resource = Puppet::Type.type(:firewall).new({ :name => '950 test', })
allow(resource.provider.class).to receive(:instances).and_return(providers)
expect(resource.provider.insert_order).to eq(11)
end
end
end
# Load in ruby hash for test fixtures.
load 'spec/fixtures/iptables/conversion_hash.rb'
describe 'when converting rules to resources' do
ARGS_TO_HASH.each do |test_name,data|
describe "for test data '#{test_name}'" do
let(:resource) { provider.rule_to_hash(data[:line], data[:table], 0) }
# If this option is enabled, make sure the parameters exactly match
if data[:compare_all] then
it "the parameter hash keys should be the same as returned by rules_to_hash" do
expect(resource.keys).to match_array(data[:params].keys)
end
end
# Iterate across each parameter, creating an example for comparison
data[:params].each do |param_name, param_value|
it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
# booleans get cludged to string "true"
if param_value == true then
expect(resource[param_name]).to be_true
else
expect(resource[param_name]).to eq(data[:params][param_name])
end
end
end
end
end
end
describe 'when working out general_args' do
HASH_TO_ARGS.each do |test_name,data|
describe "for test data '#{test_name}'" do
let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
let(:instance) { provider.new(resource) }
it 'general_args should be valid' do
expect(instance.general_args.flatten).to eq(data[:args])
end
end
end
end
describe 'when converting rules without comments to resources' do
let(:sample_rule) {
'-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
}
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
let(:instance) { provider.new(resource) }
it 'rule name contains a MD5 sum of the line' do
expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
end
it 'parsed the rule arguments correctly' do
expect(resource[:chain]).to eq('INPUT')
expect(resource[:source]).to eq('1.1.1.1/32')
expect(resource[:destination]).to eq('1.1.1.1/32')
expect(resource[:proto]).to eq('tcp')
expect(resource[:dport]).to eq(['7061', '7062'])
expect(resource[:sport]).to eq(['7061', '7062'])
expect(resource[:action]).to eq('accept')
end
end
describe 'when converting existing rules generates by system-config-firewall-tui to resources' do
let(:sample_rule) {
# as generated by iptables-save from rules created with system-config-firewall-tui
'-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT'
}
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
let(:instance) { provider.new(resource) }
it 'rule name contains a MD5 sum of the line' do
expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
end
it 'parse arguments' do
expect(resource[:chain]).to eq('INPUT')
expect(resource[:proto]).to eq('tcp')
expect(resource[:dport]).to eq(['22'])
expect(resource[:state]).to eq(['NEW'])
expect(resource[:action]).to eq('accept')
end
end
describe 'when creating resources' do
let(:instance) { provider.new(resource) }
it 'insert_args should be an array' do
expect(instance.insert_args.class).to eq(Array)
end
end
describe 'when modifying resources' do
let(:instance) { provider.new(resource) }
it 'update_args should be an array' do
expect(instance.update_args.class).to eq(Array)
end
it 'fails when modifying the chain' do
expect { instance.chain = "OUTPUT" }.to raise_error(/is not supported/)
end
end
describe 'when deleting resources' do
let(:sample_rule) {
'-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
}
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
let(:instance) { provider.new(resource) }
it 'resource[:line] looks like the original rule' do
resource[:line] == sample_rule
end
it 'delete_args is an array' do
expect(instance.delete_args.class).to eq(Array)
end
it 'delete_args is the same as the rule string when joined' do
expect(instance.delete_args.join(' ')).to eq(sample_rule.gsub(/\-A/,
'-t filter -D'))
end
end
end
describe 'ip6tables provider' do
let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
let(:resource) {
Puppet::Type.type(:firewall).new({
:name => '000 test foo',
:action => 'accept',
:provider => "ip6tables",
})
}
before :each do
allow(Puppet::Type::Firewall).to receive(:ip6tables).and_return provider6
allow(provider6).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"
# Stub iptables version
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return '1.4.7'
allow(Puppet::Util::Execution).to receive(:execute).and_return ''
allow(Puppet::Util).to receive(:which).with("ip6tables-save").
and_return "/sbin/ip6tables-save"
end
it 'should be able to get a list of existing rules' do
provider6.instances.each do |rule|
rule.should be_instance_of(provider6)
rule.properties[:provider6].to_s.should == provider6.name.to_s
end
end
it 'should ignore lines with fatal errors' do
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/ip6tables-save']).
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
provider6.instances.length.should == 0
end
# Load in ruby hash for test fixtures.
load 'spec/fixtures/ip6tables/conversion_hash.rb'
describe 'when converting rules to resources' do
ARGS_TO_HASH6.each do |test_name,data|
describe "for test data '#{test_name}'" do
let(:resource) { provider6.rule_to_hash(data[:line], data[:table], 0) }
# If this option is enabled, make sure the parameters exactly match
if data[:compare_all] then
it "the parameter hash keys should be the same as returned by rules_to_hash" do
resource.keys.should =~ data[:params].keys
end
end
# Iterate across each parameter, creating an example for comparison
data[:params].each do |param_name, param_value|
it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
resource[param_name].should == data[:params][param_name]
end
end
end
end
end
describe 'when working out general_args' do
HASH_TO_ARGS6.each do |test_name,data|
describe "for test data '#{test_name}'" do
let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
let(:instance) { provider6.new(resource) }
it 'general_args should be valid' do
instance.general_args.flatten.should == data[:args]
end
end
end
end
end

View file

@ -0,0 +1,650 @@
#!/usr/bin/env rspec
require 'spec_helper'
firewall = Puppet::Type.type(:firewall)
describe firewall do
before :each do
@class = firewall
@provider = double 'provider'
allow(@provider).to receive(:name).and_return(:iptables)
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return @provider
@resource = @class.new({:name => '000 test foo'})
# Stub iptables version
allow(Facter.fact(:iptables_version)).to receive(:value).and_return('1.4.2')
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return('1.4.2')
# Stub confine facts
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
end
it 'should have :name be its namevar' do
@class.key_attributes.should == [:name]
end
describe ':name' do
it 'should accept a name' do
@resource[:name] = '000-test-foo'
@resource[:name].should == '000-test-foo'
end
it 'should not accept a name with non-ASCII chars' do
lambda { @resource[:name] = '%*#^(#$' }.should raise_error(Puppet::Error)
end
end
describe ':action' do
it "should have no default" do
res = @class.new(:name => "000 test")
res.parameters[:action].should == nil
end
[:accept, :drop, :reject].each do |action|
it "should accept value #{action}" do
@resource[:action] = action
@resource[:action].should == action
end
end
it 'should fail when value is not recognized' do
lambda { @resource[:action] = 'not valid' }.should raise_error(Puppet::Error)
end
end
describe ':chain' do
[:INPUT, :FORWARD, :OUTPUT, :PREROUTING, :POSTROUTING].each do |chain|
it "should accept chain value #{chain}" do
@resource[:chain] = chain
@resource[:chain].should == chain
end
end
it 'should fail when the chain value is not recognized' do
lambda { @resource[:chain] = 'not valid' }.should raise_error(Puppet::Error)
end
end
describe ':table' do
[:nat, :mangle, :filter, :raw].each do |table|
it "should accept table value #{table}" do
@resource[:table] = table
@resource[:table].should == table
end
end
it "should fail when table value is not recognized" do
lambda { @resource[:table] = 'not valid' }.should raise_error(Puppet::Error)
end
end
describe ':proto' do
[:tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :ipencap, :ospf, :gre, :all].each do |proto|
it "should accept proto value #{proto}" do
@resource[:proto] = proto
@resource[:proto].should == proto
end
end
it "should fail when proto value is not recognized" do
lambda { @resource[:proto] = 'foo' }.should raise_error(Puppet::Error)
end
end
describe ':jump' do
it "should have no default" do
res = @class.new(:name => "000 test")
res.parameters[:jump].should == nil
end
['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump|
it "should accept jump value #{jump}" do
@resource[:jump] = jump
@resource[:jump].should == jump
end
end
['ACCEPT', 'DROP', 'REJECT'].each do |jump|
it "should now fail when value #{jump}" do
lambda { @resource[:jump] = jump }.should raise_error(Puppet::Error)
end
end
it "should fail when jump value is not recognized" do
lambda { @resource[:jump] = '%^&*' }.should raise_error(Puppet::Error)
end
end
[:source, :destination].each do |addr|
describe addr do
it "should accept a #{addr} as a string" do
@resource[addr] = '127.0.0.1'
@resource[addr].should == '127.0.0.1/32'
end
['0.0.0.0/0', '::/0'].each do |prefix|
it "should be nil for zero prefix length address #{prefix}" do
@resource[addr] = prefix
@resource[addr].should == nil
end
end
it "should accept a negated #{addr} as a string" do
@resource[addr] = '! 127.0.0.1'
@resource[addr].should == '! 127.0.0.1/32'
end
end
end
[:dport, :sport].each do |port|
describe port do
it "should accept a #{port} as string" do
@resource[port] = '22'
@resource[port].should == ['22']
end
it "should accept a #{port} as an array" do
@resource[port] = ['22','23']
@resource[port].should == ['22','23']
end
it "should accept a #{port} as a number" do
@resource[port] = 22
@resource[port].should == ['22']
end
it "should accept a #{port} as a hyphen separated range" do
@resource[port] = ['22-1000']
@resource[port].should == ['22-1000']
end
it "should accept a #{port} as a combination of arrays of single and " \
"hyphen separated ranges" do
@resource[port] = ['22-1000','33','3000-4000']
@resource[port].should == ['22-1000','33','3000-4000']
end
it "should convert a port name for #{port} to its number" do
@resource[port] = 'ssh'
@resource[port].should == ['22']
end
it "should not accept something invalid for #{port}" do
expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
end
it "should not accept something invalid in an array for #{port}" do
expect { @resource[port] = ['something odd','something even odder'] }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
end
end
end
[:dst_type, :src_type].each do |addrtype|
describe addrtype do
it "should have no default" do
res = @class.new(:name => "000 test")
res.parameters[addrtype].should == nil
end
end
[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE,
:UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type|
it "should accept #{addrtype} value #{type}" do
@resource[addrtype] = type
@resource[addrtype].should == type
end
end
it "should fail when #{addrtype} value is not recognized" do
lambda { @resource[addrtype] = 'foo' }.should raise_error(Puppet::Error)
end
end
[:iniface, :outiface].each do |iface|
describe iface do
it "should accept #{iface} value as a string" do
@resource[iface] = 'eth1'
@resource[iface].should == 'eth1'
end
end
end
[:tosource, :todest].each do |addr|
describe addr do
it "should accept #{addr} value as a string" do
@resource[addr] = '127.0.0.1'
end
end
end
describe ':log_level' do
values = {
'panic' => '0',
'alert' => '1',
'crit' => '2',
'err' => '3',
'warn' => '4',
'warning' => '4',
'not' => '5',
'notice' => '5',
'info' => '6',
'debug' => '7'
}
values.each do |k,v|
it {
@resource[:log_level] = k
@resource[:log_level].should == v
}
it {
@resource[:log_level] = 3
@resource[:log_level].should == 3
}
it { lambda { @resource[:log_level] = 'foo' }.should raise_error(Puppet::Error) }
end
end
describe ':icmp' do
icmp_codes = {
:iptables => {
'0' => 'echo-reply',
'3' => 'destination-unreachable',
'4' => 'source-quench',
'6' => 'redirect',
'8' => 'echo-request',
'9' => 'router-advertisement',
'10' => 'router-solicitation',
'11' => 'time-exceeded',
'12' => 'parameter-problem',
'13' => 'timestamp-request',
'14' => 'timestamp-reply',
'17' => 'address-mask-request',
'18' => 'address-mask-reply'
},
:ip6tables => {
'1' => 'destination-unreachable',
'3' => 'time-exceeded',
'4' => 'parameter-problem',
'128' => 'echo-request',
'129' => 'echo-reply',
'133' => 'router-solicitation',
'134' => 'router-advertisement',
'137' => 'redirect'
}
}
icmp_codes.each do |provider, values|
describe provider do
values.each do |k,v|
it 'should convert icmp string to number' do
@resource[:provider] = provider
@resource[:provider].should == provider
@resource[:icmp] = v
@resource[:icmp].should == k
end
end
end
end
it 'should accept values as integers' do
@resource[:icmp] = 9
@resource[:icmp].should == 9
end
it 'should fail if icmp type is "any"' do
lambda { @resource[:icmp] = 'any' }.should raise_error(Puppet::Error)
end
it 'should fail if icmp type cannot be mapped to a numeric' do
lambda { @resource[:icmp] = 'foo' }.should raise_error(Puppet::Error)
end
end
describe ':state' do
it 'should accept value as a string' do
@resource[:state] = :INVALID
@resource[:state].should == [:INVALID]
end
it 'should accept value as an array' do
@resource[:state] = [:INVALID, :NEW]
@resource[:state].should == [:INVALID, :NEW]
end
it 'should sort values alphabetically' do
@resource[:state] = [:NEW, :ESTABLISHED]
@resource[:state].should == [:ESTABLISHED, :NEW]
end
end
describe ':ctstate' do
it 'should accept value as a string' do
@resource[:ctstate] = :INVALID
@resource[:ctstate].should == [:INVALID]
end
it 'should accept value as an array' do
@resource[:ctstate] = [:INVALID, :NEW]
@resource[:ctstate].should == [:INVALID, :NEW]
end
it 'should sort values alphabetically' do
@resource[:ctstate] = [:NEW, :ESTABLISHED]
@resource[:ctstate].should == [:ESTABLISHED, :NEW]
end
end
describe ':burst' do
it 'should accept numeric values' do
@resource[:burst] = 12
@resource[:burst].should == 12
end
it 'should fail if value is not numeric' do
lambda { @resource[:burst] = 'foo' }.should raise_error(Puppet::Error)
end
end
describe ':recent' do
['set', 'update', 'rcheck', 'remove'].each do |recent|
it "should accept recent value #{recent}" do
@resource[:recent] = recent
@resource[:recent].should == "--#{recent}"
end
end
end
describe ':action and :jump' do
it 'should allow only 1 to be set at a time' do
expect {
@class.new(
:name => "001-test",
:action => "accept",
:jump => "custom_chain"
)
}.to raise_error(Puppet::Error, /Only one of the parameters 'action' and 'jump' can be set$/)
end
end
describe ':gid and :uid' do
it 'should allow me to set uid' do
@resource[:uid] = 'root'
@resource[:uid].should == 'root'
end
it 'should allow me to set uid as an array, and silently hide my error' do
@resource[:uid] = ['root', 'bobby']
@resource[:uid].should == 'root'
end
it 'should allow me to set gid' do
@resource[:gid] = 'root'
@resource[:gid].should == 'root'
end
it 'should allow me to set gid as an array, and silently hide my error' do
@resource[:gid] = ['root', 'bobby']
@resource[:gid].should == 'root'
end
end
describe ':set_mark' do
['1.3.2', '1.4.2'].each do |iptables_version|
describe "with iptables #{iptables_version}" do
before {
Facter.clear
allow(Facter.fact(:iptables_version)).to receive(:value).and_return iptables_version
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return iptables_version
}
if iptables_version == '1.3.2'
it 'should allow me to set set-mark without mask' do
@resource[:set_mark] = '0x3e8'
@resource[:set_mark].should == '0x3e8'
end
it 'should convert int to hex without mask' do
@resource[:set_mark] = '1000'
@resource[:set_mark].should == '0x3e8'
end
it 'should fail if mask is present' do
lambda { @resource[:set_mark] = '0x3e8/0xffffffff'}.should raise_error(
Puppet::Error, /iptables version #{iptables_version} does not support masks on MARK rules$/
)
end
end
if iptables_version == '1.4.2'
it 'should allow me to set set-mark with mask' do
@resource[:set_mark] = '0x3e8/0xffffffff'
@resource[:set_mark].should == '0x3e8/0xffffffff'
end
it 'should convert int to hex and add a 32 bit mask' do
@resource[:set_mark] = '1000'
@resource[:set_mark].should == '0x3e8/0xffffffff'
end
it 'should add a 32 bit mask' do
@resource[:set_mark] = '0x32'
@resource[:set_mark].should == '0x32/0xffffffff'
end
it 'should use the mask provided' do
@resource[:set_mark] = '0x32/0x4'
@resource[:set_mark].should == '0x32/0x4'
end
it 'should use the mask provided and convert int to hex' do
@resource[:set_mark] = '1000/0x4'
@resource[:set_mark].should == '0x3e8/0x4'
end
it 'should fail if mask value is more than 32 bits' do
lambda { @resource[:set_mark] = '1/4294967296'}.should raise_error(
Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
)
end
it 'should fail if mask is malformed' do
lambda { @resource[:set_mark] = '1000/0xq4'}.should raise_error(
Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
)
end
end
['/', '1000/', 'pwnie'].each do |bad_mark|
it "should fail with malformed mark '#{bad_mark}'" do
lambda { @resource[:set_mark] = bad_mark}.should raise_error(Puppet::Error)
end
end
it 'should fail if mark value is more than 32 bits' do
lambda { @resource[:set_mark] = '4294967296'}.should raise_error(
Puppet::Error, /MARK value must be integer or hex between 0 and 0xffffffff$/
)
end
end
end
end
[:chain, :jump].each do |param|
describe param do
it 'should autorequire fwchain when table and provider are undefined' do
@resource[param] = 'FOO'
@resource[:table].should == :filter
@resource[:provider].should == :iptables
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
it 'should autorequire fwchain when table is undefined and provider is ip6tables' do
@resource[param] = 'FOO'
@resource[:table].should == :filter
@resource[:provider] = :ip6tables
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv6')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
it 'should autorequire fwchain when table is raw and provider is undefined' do
@resource[param] = 'FOO'
@resource[:table] = :raw
@resource[:provider].should == :iptables
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv4')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
it 'should autorequire fwchain when table is raw and provider is ip6tables' do
@resource[param] = 'FOO'
@resource[:table] = :raw
@resource[:provider] = :ip6tables
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv6')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
# test where autorequire is still needed (table != filter)
['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|
it "should autorequire fwchain #{test_chain} when table is mangle and provider is undefined" do
@resource[param] = test_chain
@resource[:table] = :mangle
@resource[:provider].should == :iptables
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv4")
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
it "should autorequire fwchain #{test_chain} when table is mangle and provider is ip6tables" do
@resource[param] = test_chain
@resource[:table] = :mangle
@resource[:provider] = :ip6tables
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv6")
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.source.ref.should == chain.ref
rel.target.ref.should == @resource.ref
end
end
# test of case where autorequire should not happen
['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|
it "should not autorequire fwchain #{test_chain} when table and provider are undefined" do
@resource[param] = test_chain
@resource[:table].should == :filter
@resource[:provider].should == :iptables
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv4")
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.should == nil
end
it "should not autorequire fwchain #{test_chain} when table is undefined and provider is ip6tables" do
@resource[param] = test_chain
@resource[:table].should == :filter
@resource[:provider] = :ip6tables
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv6")
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain
rel = @resource.autorequire[0]
rel.should == nil
end
end
end
end
describe ":chain and :jump" do
it 'should autorequire independent fwchains' do
@resource[:chain] = 'FOO'
@resource[:jump] = 'BAR'
@resource[:table].should == :filter
@resource[:provider].should == :iptables
chain_foo = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
chain_bar = Puppet::Type.type(:firewallchain).new(:name => 'BAR:filter:IPv4')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource chain_foo
catalog.add_resource chain_bar
rel = @resource.autorequire
rel[0].source.ref.should == chain_foo.ref
rel[0].target.ref.should == @resource.ref
rel[1].source.ref.should == chain_bar.ref
rel[1].target.ref.should == @resource.ref
end
end
describe ':pkttype' do
[:multicast, :broadcast, :unicast].each do |pkttype|
it "should accept pkttype value #{pkttype}" do
@resource[:pkttype] = pkttype
@resource[:pkttype].should == pkttype
end
end
it 'should fail when the pkttype value is not recognized' do
lambda { @resource[:pkttype] = 'not valid' }.should raise_error(Puppet::Error)
end
end
describe 'autorequire packages' do
[:iptables, :ip6tables].each do |provider|
it "provider #{provider} should autorequire package iptables" do
@resource[:provider] = provider
@resource[:provider].should == provider
package = Puppet::Type.type(:package).new(:name => 'iptables')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
catalog.add_resource package
rel = @resource.autorequire[0]
rel.source.ref.should == package.ref
rel.target.ref.should == @resource.ref
end
it "provider #{provider} should autorequire packages iptables and iptables-persistent" do
@resource[:provider] = provider
@resource[:provider].should == provider
packages = [
Puppet::Type.type(:package).new(:name => 'iptables'),
Puppet::Type.type(:package).new(:name => 'iptables-persistent')
]
catalog = Puppet::Resource::Catalog.new
catalog.add_resource @resource
packages.each do |package|
catalog.add_resource package
end
packages.zip(@resource.autorequire) do |package, rel|
rel.source.ref.should == package.ref
rel.target.ref.should == @resource.ref
end
end
end
end
end

View file

@ -0,0 +1,185 @@
#!/usr/bin/env rspec
require 'spec_helper'
firewallchain = Puppet::Type.type(:firewallchain)
describe firewallchain do
before(:each) do
# Stub confine facts
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
end
let(:klass) { firewallchain }
let(:provider) {
prov = double 'provider'
allow(prov).to receive(:name).and_return(:iptables_chain)
prov
}
let(:resource) {
allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
klass.new({:name => 'INPUT:filter:IPv4', :policy => :accept })
}
it 'should have :name be its namevar' do
klass.key_attributes.should == [:name]
end
describe ':name' do
{'nat' => ['PREROUTING', 'POSTROUTING', 'INPUT', 'OUTPUT'],
'mangle' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ],
'filter' => ['INPUT','OUTPUT','FORWARD'],
'raw' => [ 'PREROUTING', 'OUTPUT'],
'broute' => ['BROUTING']
}.each_pair do |table, allowedinternalchains|
['IPv4', 'IPv6', 'ethernet'].each do |protocol|
[ 'test', '$5()*&%\'"^$09):' ].each do |chainname|
name = "#{chainname}:#{table}:#{protocol}"
if table == 'nat' && protocol == 'IPv6'
it "should fail #{name}" do
expect { resource[:name] = name }.to raise_error(Puppet::Error)
end
elsif protocol != 'ethernet' && table == 'broute'
it "should fail #{name}" do
expect { resource[:name] = name }.to raise_error(Puppet::Error)
end
else
it "should accept name #{name}" do
resource[:name] = name
resource[:name].should == name
end
end
end # chainname
end # protocol
[ 'PREROUTING', 'POSTROUTING', 'BROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ].each do |internalchain|
name = internalchain + ':' + table + ':'
if internalchain == 'BROUTING'
name += 'ethernet'
elsif table == 'nat'
name += 'IPv4'
else
name += 'IPv4'
end
if allowedinternalchains.include? internalchain
it "should allow #{name}" do
resource[:name] = name
resource[:name].should == name
end
else
it "should fail #{name}" do
expect { resource[:name] = name }.to raise_error(Puppet::Error)
end
end
end # internalchain
end # table, allowedinternalchainnames
it 'should fail with invalid table names' do
expect { resource[:name] = 'wrongtablename:test:IPv4' }.to raise_error(Puppet::Error)
end
it 'should fail with invalid protocols names' do
expect { resource[:name] = 'test:filter:IPv5' }.to raise_error(Puppet::Error)
end
end
describe ':policy' do
[:accept, :drop, :queue, :return].each do |policy|
it "should accept policy #{policy}" do
resource[:policy] = policy
resource[:policy].should == policy
end
end
it 'should fail when value is not recognized' do
expect { resource[:policy] = 'not valid' }.to raise_error(Puppet::Error)
end
[:accept, :drop, :queue, :return].each do |policy|
it "non-inbuilt chains should not accept policy #{policy}" do
expect { klass.new({:name => 'testchain:filter:IPv4', :policy => policy }) }.to raise_error(Puppet::Error)
end
it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do
klass.new({:name => 'testchain:filter:ethernet', :policy => policy })
end
end
end
describe 'autorequire packages' do
it "provider iptables_chain should autorequire package iptables" do
resource[:provider].should == :iptables_chain
package = Puppet::Type.type(:package).new(:name => 'iptables')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource resource
catalog.add_resource package
rel = resource.autorequire[0]
rel.source.ref.should == package.ref
rel.target.ref.should == resource.ref
end
it "provider iptables_chain should autorequire packages iptables and iptables-persistent" do
resource[:provider].should == :iptables_chain
packages = [
Puppet::Type.type(:package).new(:name => 'iptables'),
Puppet::Type.type(:package).new(:name => 'iptables-persistent')
]
catalog = Puppet::Resource::Catalog.new
catalog.add_resource resource
packages.each do |package|
catalog.add_resource package
end
packages.zip(resource.autorequire) do |package, rel|
rel.source.ref.should == package.ref
rel.target.ref.should == resource.ref
end
end
end
describe 'purge iptables rules' do
before(:each) do
allow(Puppet::Type.type(:firewall).provider(:iptables)).to receive(:iptables_save).and_return(<<EOS
# Completed on Sun Jan 5 19:30:21 2014
# Generated by iptables-save v1.4.12 on Sun Jan 5 19:30:21 2014
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:LOCAL_FORWARD - [0:0]
:LOCAL_FORWARD_PRE - [0:0]
:LOCAL_INPUT - [0:0]
:LOCAL_INPUT_PRE - [0:0]
:fail2ban-ssh - [0:0]
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
-A INPUT -i lo -m comment --comment "012 accept loopback" -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "020 ssh" -j ACCEPT
-A OUTPUT -d 1.2.1.2 -j DROP
-A fail2ban-ssh -j RETURN
COMMIT
# Completed on Sun Jan 5 19:30:21 2014
EOS
)
end
it 'should generate iptables resources' do
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true)
expect(resource.generate.size).to eq(3)
end
it 'should not generate ignored iptables rules' do
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true, :ignore => ['-j fail2ban-ssh'])
expect(resource.generate.size).to eq(2)
end
it 'should not generate iptables resources when not enabled' do
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4')
expect(resource.generate.size).to eq(0)
end
end
end

View file

@ -0,0 +1,197 @@
require 'spec_helper'
describe 'Puppet::Util::Firewall' do
let(:resource) {
type = Puppet::Type.type(:firewall)
provider = double 'provider'
allow(provider).to receive(:name).and_return(:iptables)
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return(provider)
type.new({:name => '000 test foo'})
}
before(:each) { resource }
describe '#host_to_ip' do
subject { resource }
specify {
expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51')
subject.host_to_ip('puppetlabs.com').should == '96.126.112.51/32'
}
specify { subject.host_to_ip('96.126.112.51').should == '96.126.112.51/32' }
specify { subject.host_to_ip('96.126.112.51/32').should == '96.126.112.51/32' }
specify { subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_ip('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
specify { subject.host_to_ip('0.0.0.0/0').should == nil }
specify { subject.host_to_ip('::/0').should == nil }
end
describe '#host_to_mask' do
subject { resource }
specify {
expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51')
subject.host_to_mask('puppetlabs.com').should == '96.126.112.51/32'
subject.host_to_mask('!puppetlabs.com').should == '! 96.126.112.51/32'
}
specify { subject.host_to_mask('96.126.112.51').should == '96.126.112.51/32' }
specify { subject.host_to_mask('!96.126.112.51').should == '! 96.126.112.51/32' }
specify { subject.host_to_mask('96.126.112.51/32').should == '96.126.112.51/32' }
specify { subject.host_to_mask('! 96.126.112.51/32').should == '! 96.126.112.51/32' }
specify { subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334').should == '! 2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_mask('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
specify { subject.host_to_mask('! 2001:db8:1234::/48').should == '! 2001:db8:1234::/48' }
specify { subject.host_to_mask('0.0.0.0/0').should == nil }
specify { subject.host_to_mask('!0.0.0.0/0').should == nil }
specify { subject.host_to_mask('::/0').should == nil }
specify { subject.host_to_mask('! ::/0').should == nil }
end
describe '#icmp_name_to_number' do
describe 'proto unsupported' do
subject { resource }
%w{inet5 inet8 foo}.each do |proto|
it "should reject invalid proto #{proto}" do
expect { subject.icmp_name_to_number('echo-reply', proto) }.
to raise_error(ArgumentError, "unsupported protocol family '#{proto}'")
end
end
end
describe 'proto IPv4' do
proto = 'inet'
subject { resource }
specify { subject.icmp_name_to_number('echo-reply', proto).should == '0' }
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '3' }
specify { subject.icmp_name_to_number('source-quench', proto).should == '4' }
specify { subject.icmp_name_to_number('redirect', proto).should == '6' }
specify { subject.icmp_name_to_number('echo-request', proto).should == '8' }
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '9' }
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '10' }
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '11' }
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '12' }
specify { subject.icmp_name_to_number('timestamp-request', proto).should == '13' }
specify { subject.icmp_name_to_number('timestamp-reply', proto).should == '14' }
specify { subject.icmp_name_to_number('address-mask-request', proto).should == '17' }
specify { subject.icmp_name_to_number('address-mask-reply', proto).should == '18' }
end
describe 'proto IPv6' do
proto = 'inet6'
subject { resource }
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '1' }
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '3' }
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '4' }
specify { subject.icmp_name_to_number('echo-request', proto).should == '128' }
specify { subject.icmp_name_to_number('echo-reply', proto).should == '129' }
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '133' }
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '134' }
specify { subject.icmp_name_to_number('redirect', proto).should == '137' }
end
end
describe '#string_to_port' do
subject { resource }
specify { subject.string_to_port('80','tcp').should == '80' }
specify { subject.string_to_port(80,'tcp').should == '80' }
specify { subject.string_to_port('http','tcp').should == '80' }
specify { subject.string_to_port('domain','udp').should == '53' }
end
describe '#to_hex32' do
subject { resource }
specify { subject.to_hex32('0').should == '0x0' }
specify { subject.to_hex32('0x32').should == '0x32' }
specify { subject.to_hex32('42').should == '0x2a' }
specify { subject.to_hex32('4294967295').should == '0xffffffff' }
specify { subject.to_hex32('4294967296').should == nil }
specify { subject.to_hex32('-1').should == nil }
specify { subject.to_hex32('bananas').should == nil }
end
describe '#persist_iptables' do
before { Facter.clear }
subject { resource }
describe 'when proto is IPv4' do
let(:proto) { 'IPv4' }
it 'should exec /sbin/service if running RHEL 6 or earlier' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
subject.persist_iptables(proto)
end
it 'should exec for systemd if running RHEL 7 or greater' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7')
expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
subject.persist_iptables(proto)
end
it 'should exec for systemd if running Fedora 15 or greater' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Fedora')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('15')
expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
subject.persist_iptables(proto)
end
it 'should exec for CentOS identified from operatingsystem' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS')
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
subject.persist_iptables(proto)
end
it 'should exec for Archlinux identified from osfamily' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Archlinux')
expect(subject).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules'])
subject.persist_iptables(proto)
end
it 'should raise a warning when exec fails' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}).
and_raise(Puppet::ExecutionFailure, 'some error')
expect(subject).to receive(:warning).with('Unable to persist firewall rules: some error')
subject.persist_iptables(proto)
end
end
describe 'when proto is IPv6' do
let(:proto) { 'IPv6' }
it 'should exec for newer Ubuntu' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.5.3ubuntu2')
expect(subject).to receive(:execute).with(%w{/usr/sbin/service iptables-persistent save})
subject.persist_iptables(proto)
end
it 'should not exec for older Ubuntu which does not support IPv6' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.0.20090701')
expect(subject).to receive(:execute).never
subject.persist_iptables(proto)
end
it 'should not exec for Suse which is not supported' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse')
expect(subject).to receive(:execute).never
subject.persist_iptables(proto)
end
end
end
end

View file

@ -0,0 +1,67 @@
require 'spec_helper'
describe 'Puppet::Util::IPCidr' do
describe 'ipv4 address' do
before { @ipaddr = Puppet::Util::IPCidr.new('96.126.112.51') }
subject { @ipaddr }
specify { subject.cidr.should == '96.126.112.51/32' }
specify { subject.prefixlen.should == 32 }
specify { subject.netmask.should == '255.255.255.255' }
end
describe 'single ipv4 address with cidr' do
before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.51/32') }
subject { @ipcidr }
specify { subject.cidr.should == '96.126.112.51/32' }
specify { subject.prefixlen.should == 32 }
specify { subject.netmask.should == '255.255.255.255' }
end
describe 'ipv4 address range with cidr' do
before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.0/24') }
subject { @ipcidr }
specify { subject.cidr.should == '96.126.112.0/24' }
specify { subject.prefixlen.should == 24 }
specify { subject.netmask.should == '255.255.255.0' }
end
describe 'ipv4 open range with cidr' do
before { @ipcidr = Puppet::Util::IPCidr.new('0.0.0.0/0') }
subject { @ipcidr }
specify { subject.cidr.should == '0.0.0.0/0' }
specify { subject.prefixlen.should == 0 }
specify { subject.netmask.should == '0.0.0.0' }
end
describe 'ipv6 address' do
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334') }
subject { @ipaddr }
specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.prefixlen.should == 128 }
specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
end
describe 'single ipv6 addr with cidr' do
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334/128') }
subject { @ipaddr }
specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.prefixlen.should == 128 }
specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
end
describe 'ipv6 addr range with cidr' do
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:1234::/48') }
subject { @ipaddr }
specify { subject.cidr.should == '2001:db8:1234::/48' }
specify { subject.prefixlen.should == 48 }
specify { subject.netmask.should == 'ffff:ffff:ffff:0000:0000:0000:0000:0000' }
end
describe 'ipv6 open range with cidr' do
before { @ipaddr = Puppet::Util::IPCidr.new('::/0') }
subject { @ipaddr }
specify { subject.cidr.should == '::/0' }
specify { subject.prefixlen.should == 0 }
specify { subject.netmask.should == '0000:0000:0000:0000:0000:0000:0000:0000' }
end
end