: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",
+ :dst_range => '--dst-range',
+ :dst_type => "--dst-type",
+ :gid => "--gid-owner",
:hop_limit => "-m hl --hl-eq",
:icmp => "-m icmp6 --icmpv6-type",
:iniface => "-i",
:socket => "-m socket",
:source => "-s",
:sport => ["-m multiport --sports", "--sport"],
- :src_range => '-m iprange --src-range',
- :src_type => "-m addrtype --src-type",
+ :src_range => '--src-range',
+ :src_type => "--src-type",
:stat_every => '--every',
:stat_mode => "-m statistic --mode",
:stat_packet => '--packet',
:todest => "--to-destination",
:toports => "--to-ports",
:tosource => "--to-source",
- :uid => "-m owner --uid-owner",
- :physdev_in => "-m physdev --physdev-in",
- :physdev_out => "-m physdev --physdev-out",
- :physdev_is_bridged => "-m physdev --physdev-is-bridged"
+ :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
: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],
+ }
+
# Create property methods dynamically
(@resource_map.keys << :chain << :table << :action).each do |property|
if @known_booleans.include?(property) then
# not provided with current parser [georg.koester])
@resource_list = [:table, :source, :destination, :iniface, :outiface, :physdev_in,
:physdev_out, :physdev_is_bridged, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range,
- :tcp_flags, :gid, :uid, :mac_source, :sport, :dport, :port, :dst_type,
- :src_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state,
+ :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type,
+ :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state,
:ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :todest,
:tosource, :toports, :log_level, :log_prefix, :reject, :set_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",
+ :dst_range => "--dst-range",
+ :dst_type => "--dst-type",
+ :gid => "--gid-owner",
:icmp => "-m icmp --icmp-type",
:iniface => "-i",
:ipsec_dir => "-m policy --dir",
:socket => "-m socket",
:source => "-s",
:sport => ["-m multiport --sports", "--sport"],
- :src_range => "-m iprange --src-range",
- :src_type => "-m addrtype --src-type",
+ :src_range => "--src-range",
+ :src_type => "--src-type",
:stat_every => '--every',
:stat_mode => "-m statistic --mode",
:stat_packet => '--packet',
: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",
- :physdev_is_bridged => "-m physdev --physdev-is-bridged"
+ :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
: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|
@resource_list = [
: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,
'--pol "ipsec\1\2\3\4\5\6\7\8" '
)
- # Handle resource_map values depending on whether physdev-in, physdev-out, ,physdev-is-bridged, or all three are specified
- if values.include? "--physdev-in"
- @resource_map[:physdev_in] = "-m physdev --physdev-in"
- @resource_map[:physdev_out] = "--physdev-out"
- @resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
- elsif values.include? "--physdev-out"
- @resource_map[:physdev_out] = "-m physdev --physdev-out"
- @resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
- else
- @resource_map[:physdev_is_bridged] = "-m physdev --physdev-is-bridged"
- end
+ resource_map = munge_resource_map_from_existing_values(@resource_map, values)
# Trick the system for booleans
@known_booleans.each do |bool|
# 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
# 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
# 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
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, physdev-is-bridged, or all three are specified
- if (resource[:physdev_in])
- resource_map[:physdev_in] = "-m physdev --physdev-in"
- resource_map[:physdev_out] = "--physdev-out"
- resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
- elsif (resource[:physdev_out])
- resource_map[:physdev_out] = "-m physdev --physdev-out"
- resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
- else
- resource_map[:physdev_is_bridged] = "-m physdev --physdev-is-bridged"
- 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
--- /dev/null
+ 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 => 500,
+ 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 500 --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 => 500,
+ 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 500 --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 => 500,
+ 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 500 --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
\ No newline at end of file