215 changes: 134 additions & 81 deletions lib/puppet/provider/firewall/iptables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,77 +50,142 @@
@protocol = "IPv4"

@resource_map = {
:burst => "--limit-burst",
:connlimit_above => "-m connlimit --connlimit-above",
:connlimit_mask => "--connlimit-mask",
:connmark => "-m connmark --mark",
:ctstate => "-m conntrack --ctstate",
:destination => "-d",
:dport => ["-m multiport --dports", "--dport"],
:dst_range => "-m iprange --dst-range",
:dst_type => "-m addrtype --dst-type",
:gid => "-m owner --gid-owner",
:icmp => "-m icmp --icmp-type",
:iniface => "-i",
:ipsec_dir => "-m policy --dir",
:ipsec_policy => "--pol",
:ipset => "-m set --match-set",
:isfragment => "-f",
:jump => "-j",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mask => '--mask',
:name => "-m comment --comment",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:random => "--random",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_mark => mark_flag,
:socket => "-m socket",
:source => "-s",
:sport => ["-m multiport --sports", "--sport"],
:src_range => "-m iprange --src-range",
:src_type => "-m addrtype --src-type",
:stat_every => '--every',
:stat_mode => "-m statistic --mode",
:stat_packet => '--packet',
:stat_probability => '--probability',
:state => "-m state --state",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
:toports => "--to-ports",
:tosource => "--to-source",
:to => "--to",
:uid => "-m owner --uid-owner",
:physdev_in => "-m physdev --physdev-in",
:physdev_out => "-m physdev --physdev-out",
:burst => "--limit-burst",
:checksum_fill => "--checksum-fill",
:connlimit_above => "-m connlimit --connlimit-above",
:connlimit_mask => "--connlimit-mask",
:connmark => "-m connmark --mark",
:ctstate => "-m conntrack --ctstate",
:destination => "-d",
:dport => ["-m multiport --dports", "--dport"],
:dst_range => "--dst-range",
:dst_type => "--dst-type",
:gid => "--gid-owner",
:icmp => "-m icmp --icmp-type",
:iniface => "-i",
:ipsec_dir => "-m policy --dir",
:ipsec_policy => "--pol",
:ipset => "-m set --match-set",
:isfragment => "-f",
:jump => "-j",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mask => '--mask',
:name => "-m comment --comment",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:random => "--random",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_mark => mark_flag,
:socket => "-m socket",
:source => "-s",
:sport => ["-m multiport --sports", "--sport"],
:src_range => "--src-range",
:src_type => "--src-type",
:stat_every => '--every',
:stat_mode => "-m statistic --mode",
:stat_packet => '--packet',
:stat_probability => '--probability',
:state => "-m state --state",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
:toports => "--to-ports",
:tosource => "--to-source",
:to => "--to",
:uid => "--uid-owner",
:physdev_in => "--physdev-in",
:physdev_out => "--physdev-out",
:physdev_is_bridged => "--physdev-is-bridged"
}

# These are known booleans that do not take a value, but we want to munge
# to true if they exist.
@known_booleans = [
:checksum_fill,
:isfragment,
:random,
:rdest,
:reap,
:rsource,
:rttl,
:socket
:socket,
:physdev_is_bridged
]

# Properties that use "-m <ipt module name>" (with the potential to have multiple
# arguments against the same IPT module) must be in this hash. The keys in this
# hash are the IPT module names, with the values being an array of the respective
# supported arguments for this IPT module.
#
# ** IPT Module arguments must be in order as they would appear in iptables-save **
#
# Exceptions:
# => multiport: (For some reason, the multiport arguments can't be)
# specified within the same "-m multiport", but works in seperate
# ones.
#
@module_to_argument_mapping = {
:physdev => [:physdev_in, :physdev_out, :physdev_is_bridged],
:addrtype => [:src_type, :dst_type],
:iprange => [:src_range, :dst_range],
:owner => [:uid, :gid],
}

def self.munge_resource_map_from_existing_values(resource_map_original, compare)
resource_map_new = resource_map_original.clone

@module_to_argument_mapping.each do |ipt_module, arg_array|
arg_array.each do |argument|
if resource_map_original[argument].is_a?(Array)
if compare.include?(resource_map_original[argument].first)
resource_map_new[argument] = resource_map_original[argument].clone
resource_map_new[argument][0] = "-m #{ipt_module.to_s} #{resource_map_original[argument].first}"
break
end
else
if compare.include?(resource_map_original[argument])
resource_map_new[argument] = "-m #{ipt_module.to_s} #{resource_map_original[argument]}"
break
end
end
end
end
resource_map_new
end

def munge_resource_map_from_resource(resource_map_original, compare)
resource_map_new = resource_map_original.clone
module_to_argument_mapping = self.class.instance_variable_get('@module_to_argument_mapping')

module_to_argument_mapping.each do |ipt_module, arg_array|
arg_array.each do |argument|
if compare[argument]
if resource_map_original[argument].is_a?(Array)
resource_map_new[argument] = resource_map_original[argument].clone
resource_map_new[argument][0] = "-m #{ipt_module.to_s} #{resource_map_original[argument].first}"
else
resource_map_new[argument] = "-m #{ipt_module.to_s} #{resource_map_original[argument]}"
end
break
end
end
end
resource_map_new
end


# Create property methods dynamically
(@resource_map.keys << :chain << :table << :action).each do |property|
Expand Down Expand Up @@ -154,13 +219,13 @@
# changes between puppet runs, the changed rules will be re-applied again.
# This order can be determined by going through iptables source code or just tweaking and trying manually
@resource_list = [
:table, :source, :destination, :iniface, :outiface, :physdev_in, :physdev_out, :proto, :isfragment,
:table, :source, :destination, :iniface, :outiface, :physdev_in, :physdev_out, :physdev_is_bridged, :proto, :isfragment,
:stat_mode, :stat_every, :stat_packet, :stat_probability,
:src_range, :dst_range, :tcp_flags, :gid, :uid, :mac_source, :sport, :dport, :port,
:dst_type, :src_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
:src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port,
:src_type, :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
:state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :todest,
:tosource, :toports, :to, :random, :log_prefix, :log_level, :reject, :set_mark,
:tosource, :toports, :to, :checksum_fill, :random, :log_prefix, :log_level, :reject, :set_mark,
:connlimit_above, :connlimit_mask, :connmark
]

Expand Down Expand Up @@ -250,6 +315,8 @@ def self.rule_to_hash(line, table, counter)
'--pol "ipsec\1\2\3\4\5\6\7\8" '
)

resource_map = munge_resource_map_from_existing_values(@resource_map, values)

# Trick the system for booleans
@known_booleans.each do |bool|
# append "true" because all params are expected to have values
Expand All @@ -259,23 +326,15 @@ def self.rule_to_hash(line, table, counter)
# distinguish between -f and the '-f' inside of --tcp-flags.
values = values.sub(/-f(?!l)(?=.*--comment)/, '-f true')
else
values = values.sub(/#{@resource_map[bool]}/, "#{@resource_map[bool]} true")
values = values.sub(/#{resource_map[bool]}/, "#{resource_map[bool]} true")
end
end

# Handle resource_map values depending on whether physdev-in, physdev-out, or both are specified
if values.include? "--physdev-in" and values.include? "--physdev-out" then
#values = values.sub("--physdev-out","-m physdev --physdev-out")
@resource_map[:physdev_out] = "--physdev-out"
else
@resource_map[:physdev_out] = "-m physdev --physdev-out"
end

############
# Populate parser_list with used value, in the correct order
############
map_index={}
@resource_map.each_pair do |map_k,map_v|
resource_map.each_pair do |map_k,map_v|
[map_v].flatten.each do |v|
ind=values.index(/\s#{v}\s/)
next unless ind
Expand All @@ -292,7 +351,7 @@ def self.rule_to_hash(line, table, counter)

# Here we iterate across our values to generate an array of keys
parser_list.reverse.each do |k|
resource_map_key = @resource_map[k]
resource_map_key = resource_map[k]
[resource_map_key].flatten.each do |opt|
if values.slice!(/\s#{opt}/)
keys << k
Expand Down Expand Up @@ -449,15 +508,9 @@ def general_args

args = []
resource_list = self.class.instance_variable_get('@resource_list')
resource_map = self.class.instance_variable_get('@resource_map')
known_booleans = self.class.instance_variable_get('@known_booleans')

# Handle physdev args depending on whether physdev-in, physdev-out, or both are specified
if (resource[:physdev_in])
resource_map[:physdev_out] = "--physdev-out"
else
resource_map[:physdev_out] = "-m physdev --physdev-out"
end
resource_map = self.class.instance_variable_get('@resource_map')
resource_map = munge_resource_map_from_resource(resource_map, resource)

resource_list.each do |res|
resource_value = nil
Expand Down
21 changes: 21 additions & 0 deletions lib/puppet/type/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,14 @@ def insync?(is)
EOS
end

newproperty(:checksum_fill, :required_features => :iptables) do
desc <<-EOS
Compute and fill missing packet checksums.
EOS

newvalues(:true, :false)
end

newparam(:line) do
desc <<-EOS
Read-only property for caching the rule line.
Expand Down Expand Up @@ -1087,6 +1095,13 @@ def insync?(is)
newvalues(/^[a-zA-Z0-9\-\._\+]+$/)
end

newproperty(:physdev_is_bridged, :required_features => :iptables) do
desc <<-EOS
Match if the packet is transversing a bridge.
EOS
newvalues(:true, :false)
end

autorequire(:firewallchain) do
reqs = []
protocol = nil
Expand Down Expand Up @@ -1245,5 +1260,11 @@ def insync?(is)
self.fail "Parameter 'stat_probability' requires 'stat_mode' to be set to 'random'"
end

if value(:checksum_fill)
unless value(:jump).to_s == "CHECKSUM" && value(:table).to_s == "mangle"
self.fail "Parameter checksum_fill requires jump => CHECKSUM and table => mangle"
end
end

end
end
9 changes: 9 additions & 0 deletions manifests/linux.pp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
require => Package['iptables'],
}
}
'Gentoo': {
class { "${title}::gentoo":
ensure => $ensure,
enable => $enable,
package_name => $package_name,
service_name => $service_name,
require => Package['iptables'],
}
}
default: {}
}
}
43 changes: 43 additions & 0 deletions manifests/linux/gentoo.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# = Class: firewall::linux::gentoo
#
# Manages `iptables` and `ip6tables` services, and creates files used for
# persistence, on Arch Linux systems.
#
# == Parameters:
#
# [*ensure*]
# Ensure parameter passed onto Service[] resources.
# Default: running
#
# [*enable*]
# Enable parameter passed onto Service[] resources.
# Default: true
#
class firewall::linux::gentoo (
$ensure = 'running',
$enable = true,
$service_name = $::firewall::params::service_name,
$package_name = $::firewall::params::package_name,
) inherits ::firewall::params {
if $package_name {
package { $package_name:
ensure => present,
}
}

service { $service_name:
ensure => $ensure,
enable => $enable,
hasstatus => true,
}

file { '/var/lib/iptables/rules-save':
ensure => present,
before => Service[$service_name],
}

file { '/var/lib/iptables/rules-save6':
ensure => present,
before => Service[$service_name],
}
}
4 changes: 4 additions & 0 deletions manifests/params.pp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
}
}
}
'Gentoo': {
$service_name = ['iptables','ip6tables']
$package_name = 'net-firewall/iptables'
}
default: {
$package_name = undef
$service_name = 'iptables'
Expand Down
12 changes: 9 additions & 3 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "puppetlabs-firewall",
"version": "1.4.0",
"version": "1.5.0",
"author": "Puppet Labs",
"summary": "Manages Firewalls such as iptable",
"summary": "Manages Firewalls such as iptables",
"license": "Apache-2.0",
"source": "https://github.com/puppetlabs/puppetlabs-firewall",
"project_page": "http://github.com/puppetlabs/puppetlabs-firewall",
Expand Down Expand Up @@ -60,6 +60,12 @@
"12.04",
"14.04"
]
},
{
"operatingsystem": "Gentoo",
"operatingsystemrelease": [
"1.0"
]
}
],
"requirements": [
Expand All @@ -73,6 +79,6 @@
}
],
"dependencies": [

]
}
221 changes: 221 additions & 0 deletions spec/acceptance/firewall_bridging_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,115 @@ class { '::firewall': }
end
end
end

context 'physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '704 - test':
chain => 'FORWARD',
proto => tcp,
port => '704',
action => accept,
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT/)
end
end
end

context 'physdev_in eth0 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '705 - test':
chain => 'FORWARD',
proto => tcp,
port => '705',
action => accept,
physdev_in => 'eth0',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-is-bridged -m multiport --ports 705 -m comment --comment "705 - test" -j ACCEPT/)
end
end
end

context 'physdev_out eth1 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '706 - test':
chain => 'FORWARD',
proto => tcp,
port => '706',
action => accept,
physdev_out => 'eth1',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m multiport --ports 706 -m comment --comment "706 - test" -j ACCEPT/)
end
end
end

context 'physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '707 - test':
chain => 'FORWARD',
proto => tcp,
port => '707',
action => accept,
physdev_in => 'eth0',
physdev_out => 'eth1',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m multiport --ports 707 -m comment --comment "707 - test" -j ACCEPT/)
end
end
end

end

#iptables version 1.3.5 is not suppored by the ip6tables provider
Expand Down Expand Up @@ -176,6 +285,118 @@ class { '::firewall': }
end
end
end

context 'physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '704 - test':
provider => 'ip6tables',
chain => 'FORWARD',
proto => tcp,
port => '704',
action => accept,
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT/)
end
end
end

context 'physdev_in eth0 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '705 - test':
provider => 'ip6tables',
chain => 'FORWARD',
proto => tcp,
port => '705',
action => accept,
physdev_in => 'eth0',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-is-bridged -m multiport --ports 705 -m comment --comment "705 - test" -j ACCEPT/)
end
end
end

context 'physdev_out eth1 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '706 - test':
provider => 'ip6tables',
chain => 'FORWARD',
proto => tcp,
port => '706',
action => accept,
physdev_out => 'eth1',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m multiport --ports 706 -m comment --comment "706 - test" -j ACCEPT/)
end
end
end

context 'physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '707 - test':
provider => 'ip6tables',
chain => 'FORWARD',
proto => tcp,
port => '707',
action => accept,
physdev_in => 'eth0',
physdev_out => 'eth1',
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m multiport --ports 707 -m comment --comment "707 - test" -j ACCEPT/)
end
end
end
end
end

Expand Down
218 changes: 218 additions & 0 deletions spec/acceptance/firewall_iptmodules_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
require 'spec_helper_acceptance'

describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

describe 'reset' do
it 'deletes all iptables rules' do
shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush')
end
it 'deletes all ip6tables rules' do
shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush')
end
end

describe 'iptables ipt_modules tests' do
context 'all the modules with multiple args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '801 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
uid => 0,
gid => 404,
src_range => "90.0.0.1-90.0.0.2",
dst_range => "100.0.0.1-100.0.0.2",
src_type => 'LOCAL',
dst_type => 'UNICAST',
physdev_in => "eth0",
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 90.0.0.1-90.0.0.2\s+--dst-range 100.0.0.1-100.0.0.2 -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m addrtype --src-type LOCAL --dst-type UNICAST -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end

context 'all the modules with single args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '802 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
gid => 404,
dst_range => "100.0.0.1-100.0.0.2",
dst_type => 'UNICAST',
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 100.0.0.1-100.0.0.2 -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
end

#iptables version 1.3.5 is not suppored by the ip6tables provider
if default['platform'] =~ /debian-7/ or default['platform'] =~ /ubuntu-14\.04/
describe 'ip6tables ipt_modules tests' do
context 'all the modules with multiple args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '801 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
provider => 'ip6tables',
uid => 0,
gid => 404,
src_range => "2001::-2002::",
dst_range => "2003::-2004::",
src_type => 'LOCAL',
dst_type => 'UNICAST',
physdev_in => "eth0",
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 2001::-2002::\s+--dst-range 2003::-2004:: -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m addrtype --src-type LOCAL --dst-type UNICAST -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/)
end
end
end

context 'all the modules with single args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '802 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
provider => 'ip6tables',
gid => 404,
dst_range => "2003::-2004::",
dst_type => 'UNICAST',
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/)
end
end
end
end
# Older OSes don't have addrtype so we leave those properties out.
# el-5 doesn't support ipv6 by default
elsif default['platform'] !~ /el-5/
describe 'ip6tables ipt_modules tests' do
context 'all the modules with multiple args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '801 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
provider => 'ip6tables',
uid => 0,
gid => 404,
src_range => "2001::-2002::",
dst_range => "2003::-2004::",
physdev_in => "eth0",
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 2001::-2002::\s+--dst-range 2003::-2004:: -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/)
end
end
end

context 'all the modules with single args' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '802 - ipt_modules tests':
proto => tcp,
dport => '8080',
action => reject,
chain => 'OUTPUT',
provider => 'ip6tables',
gid => 404,
dst_range => "2003::-2004::",
physdev_out => "eth1",
physdev_is_bridged => true,
}
EOS

apply_manifest(pp, :catch_failures => true)
unless fact('selinux') == 'true'
apply_manifest(pp, :catch_changes => true)
end
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/)
end
end
end
end
end

end
59 changes: 59 additions & 0 deletions spec/acceptance/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,65 @@ class { '::firewall': }
end
end


if default['platform'] !~ /el-5/ and default['platform'] !~ /ubuntu-10\.04/ and default['platform'] !~ /debian-6/ and default['platform'] !~ /sles/
describe 'checksum_fill' do
context 'virbr' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '576 - test':
proto => udp,
table => 'mangle',
outiface => 'virbr0',
chain => 'POSTROUTING',
dport => '68',
jump => 'CHECKSUM',
checksum_fill => true,
provider => iptables,
}
EOS

apply_manifest(pp, :catch_failures => true)
end

it 'should contain the rule' do
shell('iptables-save -t mangle') do |r|
expect(r.stdout).to match(/-A POSTROUTING -o virbr0 -p udp -m multiport --dports 68 -m comment --comment "576 - test" -j CHECKSUM --checksum-fill/)
end
end
end
end

describe 'checksum_fill6' do
context 'virbr' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '576 - test':
proto => udp,
table => 'mangle',
outiface => 'virbr0',
chain => 'POSTROUTING',
dport => '68',
jump => 'CHECKSUM',
checksum_fill => true,
provider => ip6tables,
}
EOS

apply_manifest(pp, :catch_failures => true)
end

it 'should contain the rule' do
shell('ip6tables-save -t mangle') do |r|
expect(r.stdout).to match(/-A POSTROUTING -o virbr0 -p udp -m multiport --dports 68 -m comment --comment "576 - test" -j CHECKSUM --checksum-fill/)
end
end
end
end
end

# RHEL5 does not support --random
if default['platform'] !~ /el-5/
describe 'random' do
Expand Down
11 changes: 11 additions & 0 deletions spec/acceptance/nodesets/centos-7-x64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
HOSTS:
centos-7-x64:
roles:
- master
platform: el-7-x86_64
box : puppetlabs/centos-7.0-64-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-7.0-64-virtualbox-nocm.box
hypervisor : vagrant
CONFIG:
type: foss
log_level: verbose
15 changes: 15 additions & 0 deletions spec/spec_helper_acceptance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ def ip6tables_flush_all_tables
end
end

def is_rhel7(osfamily, operatingsystem, operatingsystemrelease)
if osfamily == 'RedHat'
case operatingsystem
when 'Amazon'
false
when 'Fedora'
operatingsystemrelease >= '7.0'
else
operatingsystemrelease >= '15'
end
else
false
end
end

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
# This will install the latest available package on el and deb based
# systems fail on windows and osx, and install via gem on other *nixes
Expand Down
41 changes: 41 additions & 0 deletions spec/unit/classes/firewall_linux_gentoo_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'spec_helper'

describe 'firewall::linux::gentoo', :type => :class do
let(:facts) do
{
:osfamily => 'Gentoo',
:operatingsystem => 'Gentoo'
}
end
it { should contain_service('iptables').with(
:ensure => 'running',
:enable => 'true'
)}
it { should contain_service('ip6tables').with(
:ensure => 'running',
:enable => 'true'
)}
it { should contain_package('net-firewall/iptables').with(
:ensure => 'present'
)}

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