44 changes: 17 additions & 27 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,38 +29,28 @@ end

# Used for gem conditionals
supports_windows = false
ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments
minor_version = "#{ruby_version_segments[0]}.#{ruby_version_segments[1]}"

group :development do
gem 'puppet-lint', :require => false
gem 'metadata-json-lint', :require => false, :platforms => 'ruby'
gem 'puppet_facts', :require => false
gem 'puppet-blacksmith', '>= 3.4.0', :require => false, :platforms => 'ruby'
gem 'puppetlabs_spec_helper', '~> 1.2', :require => false
gem 'rspec-puppet', '>= 2.3.2', :require => false
gem 'rspec-puppet-facts', :require => false, :platforms => 'ruby'
gem 'mocha', '< 1.2.0', :require => false
gem 'simplecov', :require => false, :platforms => 'ruby'
gem 'parallel_tests', '< 2.10.0', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem 'parallel_tests', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0.0')
gem 'rubocop', '0.41.2', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem 'rubocop', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0.0')
gem 'rubocop-rspec', '~> 1.6', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')
gem 'pry', :require => false
gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem 'fast_gettext', '1.1.0', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0')
gem 'fast_gettext', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0')
gem 'rainbow', '< 2.2.0', :require => false
gem "puppet-module-posix-default-r#{minor_version}", :require => false, :platforms => "ruby"
gem "puppet-module-win-default-r#{minor_version}", :require => false, :platforms => ["mswin", "mingw", "x64_mingw"]
gem "puppet-module-posix-dev-r#{minor_version}", :require => false, :platforms => "ruby"
gem "puppet-module-win-dev-r#{minor_version}", '0.0.7', :require => false, :platforms => ["mswin", "mingw", "x64_mingw"]
gem "json_pure", '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem "fast_gettext", '1.1.0', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0')
gem "fast_gettext", :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0')
end

group :system_tests do
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '>= 3')
gem 'beaker-pe', :require => false
gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'])
gem 'beaker-puppet_install_helper', :require => false
gem 'beaker-module_install_helper', :require => false
gem 'master_manipulator', :require => false
gem 'beaker-hostgenerator', *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION'])
gem 'beaker-abs', *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1')
gem "puppet-module-posix-system-r#{minor_version}", :require => false, :platforms => "ruby"
gem "puppet-module-win-system-r#{minor_version}", :require => false, :platforms => ["mswin", "mingw", "x64_mingw"]
gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '>= 3')
gem "beaker-pe", :require => false
gem "beaker-rspec", *location_for(ENV['BEAKER_RSPEC_VERSION'])
gem "beaker-hostgenerator", *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION'])
gem "beaker-abs", *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1')
gem "puppet-blacksmith", '~> 3.4', :require => false
end

gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION'])
Expand Down
114 changes: 82 additions & 32 deletions README.markdown

Large diffs are not rendered by default.

197 changes: 107 additions & 90 deletions lib/puppet/provider/firewall/ip6tables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,93 +70,105 @@ def self.iptables_save(*args)
@protocol = "IPv6"

@resource_map = {
:burst => "--limit-burst",
:checksum_fill => "--checksum-fill",
:clamp_mss_to_pmtu => "--clamp-mss-to-pmtu",
: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",
:gateway => "--gateway",
:gid => "--gid-owner",
:hop_limit => "-m hl --hl-eq",
:icmp => "-m icmp6 --icmpv6-type",
:iniface => "-i",
:ipsec_dir => "-m policy --dir",
:ipsec_policy => "--pol",
:ipset => "-m set --match-set",
:isfirstfrag => "-m frag --fragid 0 --fragfirst",
:ishasmorefrags => "-m frag --fragid 0 --fragmore",
:islastfrag => "-m frag --fragid 0 --fraglast",
:jump => "-j",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:log_uid => "--log-uid",
:mask => "--mask",
:match_mark => "-m mark --mark",
:name => "-m comment --comment",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mss => "-m tcpmss --mss",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:queue_num => "--queue-num",
:queue_bypass => "--queue-bypass",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_dscp => '--set-dscp',
:set_dscp_class => '--set-dscp-class',
:set_mark => mark_flag,
:set_mss => '--set-mss',
: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",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
:toports => "--to-ports",
:tosource => "--to-source",
:uid => "--uid-owner",
:physdev_in => "--physdev-in",
:physdev_out => "--physdev-out",
:physdev_is_bridged => "--physdev-is-bridged",
:physdev_is_in => "--physdev-is-in",
:physdev_is_out => "--physdev-is-out",
:date_start => "--datestart",
:date_stop => "--datestop",
:time_start => "--timestart",
:time_stop => "--timestop",
:month_days => "--monthdays",
:week_days => "--weekdays",
:time_contiguous => "--contiguous",
:kernel_timezone => "--kerneltz",
:src_cc => "--source-country",
:dst_cc => "--destination-country",
:burst => "--limit-burst",
:checksum_fill => "--checksum-fill",
:clamp_mss_to_pmtu => "--clamp-mss-to-pmtu",
: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",
:gateway => "--gateway",
:gid => "--gid-owner",
:hop_limit => "-m hl --hl-eq",
:icmp => "-m icmp6 --icmpv6-type",
:iniface => "-i",
:ipsec_dir => "-m policy --dir",
:ipsec_policy => "--pol",
:ipset => "-m set --match-set",
:isfirstfrag => "-m frag --fragid 0 --fragfirst",
:ishasmorefrags => "-m frag --fragid 0 --fragmore",
:islastfrag => "-m frag --fragid 0 --fraglast",
:jump => "-j",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:log_uid => "--log-uid",
:mask => "--mask",
:match_mark => "-m mark --mark",
:name => "-m comment --comment",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mss => "-m tcpmss --mss",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:queue_num => "--queue-num",
:queue_bypass => "--queue-bypass",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_dscp => '--set-dscp',
:set_dscp_class => '--set-dscp-class',
:set_mark => mark_flag,
:set_mss => '--set-mss',
: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",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
:toports => "--to-ports",
:tosource => "--to-source",
:uid => "--uid-owner",
:physdev_in => "--physdev-in",
:physdev_out => "--physdev-out",
:physdev_is_bridged => "--physdev-is-bridged",
:physdev_is_in => "--physdev-is-in",
:physdev_is_out => "--physdev-is-out",
:date_start => "--datestart",
:date_stop => "--datestop",
:time_start => "--timestart",
:time_stop => "--timestop",
:month_days => "--monthdays",
:week_days => "--weekdays",
:time_contiguous => "--contiguous",
:kernel_timezone => "--kerneltz",
:src_cc => "--source-country",
:dst_cc => "--destination-country",
:hashlimit_name => "--hashlimit-name",
:hashlimit_upto => "--hashlimit-upto",
:hashlimit_above => "--hashlimit-above",
:hashlimit_burst => "--hashlimit-burst",
:hashlimit_mode => "--hashlimit-mode",
:hashlimit_srcmask => "--hashlimit-srcmask",
:hashlimit_dstmask => "--hashlimit-dstmask",
:hashlimit_htable_size => "--hashlimit-htable-size",
:hashlimit_htable_max => "--hashlimit-htable-max",
:hashlimit_htable_expire => "--hashlimit-htable-expire",
:hashlimit_htable_gcinterval => "--hashlimit-htable-gcinterval",

}

# These are known booleans that do not take a value, but we want to munge
Expand Down Expand Up @@ -199,7 +211,10 @@ def self.iptables_save(*args)
:iprange => [:src_range, :dst_range],
:owner => [:uid, :gid],
:time => [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone],
:geoip => [:src_cc, :dst_cc]
:geoip => [:src_cc, :dst_cc],
:hashlimit => [:hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask,
:hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval],

}

# Create property methods dynamically
Expand Down Expand Up @@ -240,12 +255,14 @@ def self.iptables_save(*args)
:physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out,
:proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :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,
:dst_type, :socket, :pkttype, :ipsec_dir, :ipsec_policy, :state,
:ctstate, :icmp, :hop_limit, :limit, :burst, :length, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo,
:string_from, :string_to, :jump, :clamp_mss_to_pmtu, :gateway, :todest,
:tosource, :toports, :checksum_fill, :log_level, :log_prefix, :log_uid, :reject, :set_mss, :set_dscp, :set_dscp_class, :mss, :queue_num, :queue_bypass,
:set_mark, :match_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone,
:src_cc, :dst_cc]
:src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst,
:hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size,
:hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :name]

end
241 changes: 135 additions & 106 deletions lib/puppet/provider/firewall/iptables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,103 +61,114 @@
@protocol = "IPv4"

@resource_map = {
:burst => "--limit-burst",
:checksum_fill => "--checksum-fill",
:clamp_mss_to_pmtu => "--clamp-mss-to-pmtu",
: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",
:gateway => "--gateway",
: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",
:goto => "-g",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:log_uid => "--log-uid",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mask => '--mask',
:match_mark => "-m mark --mark",
:mss => '-m tcpmss --mss',
:name => "-m comment --comment",
:nflog_group => "--nflog-group",
:nflog_prefix => "--nflog-prefix",
:nflog_range => "--nflog-range",
:nflog_threshold => "--nflog-threshold",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:queue_num => "--queue-num",
:queue_bypass => "--queue-bypass",
:random => "--random",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_dscp => '--set-dscp',
:set_dscp_class => '--set-dscp-class',
:set_mark => mark_flag,
:set_mss => '--set-mss',
: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",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
: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",
:physdev_is_in => "--physdev-is-in",
:physdev_is_out => "--physdev-is-out",
:date_start => "--datestart",
:date_stop => "--datestop",
:time_start => "--timestart",
:time_stop => "--timestop",
:month_days => "--monthdays",
:week_days => "--weekdays",
:time_contiguous => "--contiguous",
:kernel_timezone => "--kerneltz",
:clusterip_new => "--new",
:clusterip_hashmode => "--hashmode",
:clusterip_clustermac => "--clustermac",
:clusterip_total_nodes => "--total-nodes",
:clusterip_local_node => "--local-node",
:clusterip_hash_init => "--hash-init",
:src_cc => "--source-country",
:dst_cc => "--destination-country",
:burst => "--limit-burst",
:checksum_fill => "--checksum-fill",
:clamp_mss_to_pmtu => "--clamp-mss-to-pmtu",
: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",
:gateway => "--gateway",
: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",
:goto => "-g",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
:log_uid => "--log-uid",
:mac_source => ["-m mac --mac-source", "--mac-source"],
:mask => '--mask',
:match_mark => "-m mark --mark",
:mss => '-m tcpmss --mss',
:name => "-m comment --comment",
:nflog_group => "--nflog-group",
:nflog_prefix => "--nflog-prefix",
:nflog_range => "--nflog-range",
:nflog_threshold => "--nflog-threshold",
:outiface => "-o",
:pkttype => "-m pkttype --pkt-type",
:port => '-m multiport --ports',
:proto => "-p",
:queue_num => "--queue-num",
:queue_bypass => "--queue-bypass",
:random => "--random",
:rdest => "--rdest",
:reap => "--reap",
:recent => "-m recent",
:reject => "--reject-with",
:rhitcount => "--hitcount",
:rname => "--name",
:rseconds => "--seconds",
:rsource => "--rsource",
:rttl => "--rttl",
:set_dscp => '--set-dscp',
:set_dscp_class => '--set-dscp-class',
:set_mark => mark_flag,
:set_mss => '--set-mss',
: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",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
: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",
:physdev_is_in => "--physdev-is-in",
:physdev_is_out => "--physdev-is-out",
:date_start => "--datestart",
:date_stop => "--datestop",
:time_start => "--timestart",
:time_stop => "--timestop",
:month_days => "--monthdays",
:week_days => "--weekdays",
:time_contiguous => "--contiguous",
:kernel_timezone => "--kerneltz",
:clusterip_new => "--new",
:clusterip_hashmode => "--hashmode",
:clusterip_clustermac => "--clustermac",
:clusterip_total_nodes => "--total-nodes",
:clusterip_local_node => "--local-node",
:clusterip_hash_init => "--hash-init",
:src_cc => "--source-country",
:dst_cc => "--destination-country",
:hashlimit_name => "--hashlimit-name",
:hashlimit_upto => "--hashlimit-upto",
:hashlimit_above => "--hashlimit-above",
:hashlimit_burst => "--hashlimit-burst",
:hashlimit_mode => "--hashlimit-mode",
:hashlimit_srcmask => "--hashlimit-srcmask",
:hashlimit_dstmask => "--hashlimit-dstmask",
:hashlimit_htable_size => "--hashlimit-htable-size",
:hashlimit_htable_max => "--hashlimit-htable-max",
:hashlimit_htable_expire => "--hashlimit-htable-expire",
:hashlimit_htable_gcinterval => "--hashlimit-htable-gcinterval",
}

# These are known booleans that do not take a value, but we want to munge
Expand Down Expand Up @@ -200,7 +211,9 @@
:iprange => [:src_range, :dst_range],
:owner => [:uid, :gid],
:time => [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone],
:geoip => [:src_cc, :dst_cc]
:geoip => [:src_cc, :dst_cc],
:hashlimit => [:hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask,
:hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval],
}

def self.munge_resource_map_from_existing_values(resource_map_original, compare)
Expand Down Expand Up @@ -282,7 +295,7 @@ def munge_resource_map_from_resource(resource_map_original, compare)
:physdev_in, :physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out,
:proto, :isfragment, :stat_mode, :stat_every, :stat_packet, :stat_probability,
:src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port,
:src_type, :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
:src_type, :dst_type, :socket, :pkttype, :ipsec_dir, :ipsec_policy,
:state, :ctstate, :icmp, :limit, :burst, :length, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo,
:string_from, :string_to, :jump, :goto, :clusterip_new, :clusterip_hashmode,
Expand All @@ -291,7 +304,9 @@ def munge_resource_map_from_resource(resource_map_original, compare)
:set_mss, :set_dscp, :set_dscp_class, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix,
:log_level, :log_uid, :reject, :set_mark, :match_mark, :mss, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop,
:month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone,
:src_cc, :dst_cc ]
:src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst,
:hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size,
:hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :name]

def insert
debug 'Inserting rule %s' % resource[:name]
Expand Down Expand Up @@ -375,7 +390,7 @@ def self.rule_to_hash(line, table, counter)
# so it behaves like --comment
values = values.gsub(/(!\s+)?--tcp-flags (\S*) (\S*)/, '--tcp-flags "\1\2 \3"')
# --match-set can have multiple values with weird iptables format
if values =~ /-m set --match-set/
if values =~ /-m set (!\s+)?--match-set/
values = values.gsub(/(!\s+)?--match-set (\S*) (\S*)/, '--match-set \1\2 \3')
ind = values.index('-m set --match-set')
sets = values.scan(/-m set --match-set ((?:!\s+)?\S* \S*)/)
Expand Down Expand Up @@ -455,13 +470,27 @@ def self.rule_to_hash(line, table, counter)
end

# Manually remove chain
values.slice!('-A')
keys << :chain
if values =~ /(\s|^)-A\s/
values = values.sub(/(\s|^)-A\s/, '\1')
keys << :chain
end

# Manually remove table (used in some tests)
if values =~ /^-t\s/
values = values.sub(/^-t\s/, '')
keys << :table
end

valrev = values.scan(/("([^"\\]|\\.)*"|\S+)/).transpose[0].reverse

if keys.length != valrev.length then
raise "Parser error: keys (#{keys.length}) and values (#{valrev.length}) count mismatch on line: #{line}"
end

# Here we generate the main hash by scanning arguments off the values
# string, handling any quoted characters present in the value, and then
# zipping the values with the array of keys.
keys.zip(values.scan(/("([^"\\]|\\.)*"|\S+)/).transpose[0].reverse) do |f, v|
keys.zip(valrev) do |f, v|
if v =~ /^".*"$/ then
hash[f] = v.sub(/^"(.*)"$/, '\1').gsub(/\\(\\|'|")/, '\1')
else
Expand Down Expand Up @@ -633,7 +662,7 @@ def update_args

def delete_args
# Split into arguments
line = properties[:line].gsub(/^\-A /, '-D ').split(/\s(?=(?:[^"]|"[^"]*")*$)/).map{|v| v.gsub(/^"/, '').gsub(/"$/, '')}
line = properties[:line].gsub(/^\-A /, '-D ').split(/\s+(?=(?:[^"]|"[^"]*")*$)/).map{|v| v.gsub(/^"/, '').gsub(/"$/, '')}
line.unshift("-t", properties[:table])
end

Expand Down Expand Up @@ -770,7 +799,7 @@ def insert_order
my_rule = resource[:name].to_s
rules << my_rule

unmanaged_rule_regex = /^9[0-9]{3}\s[a-f0-9]{32}$/
unmanaged_rule_regex = /^9[0-9]{3}\s.*$/
# Find if this is a new rule or an existing rule, then find how many
# unmanaged rules preceed it.
if rules.length == rules.uniq.length
Expand Down
154 changes: 150 additions & 4 deletions lib/puppet/type/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
feature :string_matching, "String matching features"
feature :queue_num, "Which NFQUEUE to send packets to"
feature :queue_bypass, "If nothing is listening on queue_num, allow packets to bypass the queue"
feature :hashlimit, "Hashlimit features"

# provider specific features
feature :iptables, "The provider provides iptables features."
Expand Down Expand Up @@ -133,8 +134,17 @@
EOS

munge do |value|
case @resource[:provider]
when :iptables
protocol = :IPv4
when :ip6tables
protocol = :IPv6
else
self.fail("cannot work out protocol family")
end

begin
@resource.host_to_mask(value)
@resource.host_to_mask(value, protocol)
rescue Exception => e
self.fail("host_to_ip failed for #{value}, exception #{e}")
end
Expand Down Expand Up @@ -183,8 +193,17 @@
EOS

munge do |value|
case @resource[:provider]
when :iptables
protocol = :IPv4
when :ip6tables
protocol = :IPv6
else
self.fail("cannot work out protocol family")
end

begin
@resource.host_to_mask(value)
@resource.host_to_mask(value, protocol)
rescue Exception => e
self.fail("host_to_ip failed for #{value}, exception #{e}")
end
Expand Down Expand Up @@ -691,6 +710,8 @@ def should_to_s(value)
A value of "any" is not supported. To achieve this behaviour the
parameter should simply be omitted or undefined.
An array of values is also not supported. To match against multiple ICMP
types, please use separate rules for each ICMP type.
EOS

validate do |value|
Expand All @@ -699,6 +720,11 @@ def should_to_s(value)
"Value 'any' is not valid. This behaviour should be achieved " \
"by omitting or undefining the ICMP parameter."
end
if value.kind_of?(Array)
raise ArgumentError,
"Argument must not be an array of values. To match multiple " \
"ICMP types, please use separate rules for each ICMP type."
end
end

munge do |value|
Expand All @@ -722,6 +748,7 @@ def should_to_s(value)
self.fail("cannot work out icmp type")
end
value

end
end

Expand All @@ -736,9 +763,10 @@ def should_to_s(value)
* ESTABLISHED
* NEW
* RELATED
* UNTRACKED
EOS

newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)
newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED,:UNTRACKED)

# States should always be sorted. This normalizes the resource states to
# keep it consistent with the sorted result from iptables-save.
Expand Down Expand Up @@ -767,9 +795,10 @@ def should_to_s(value)
* ESTABLISHED
* NEW
* RELATED
* UNTRACKED
EOS

newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)
newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED,:UNTRACKED)

# States should always be sorted. This normalizes the resource states to
# keep it consistent with the sorted result from iptables-save.
Expand Down Expand Up @@ -911,6 +940,45 @@ def insync?(is)
only, as iptables does not accept multiple gid in a single
statement.
EOS
def insync?(is)
require 'etc'

# The following code allow us to take into consideration unix mappings
# between string group names and GIDs (integers). We also need to ignore
# spaces as they are irrelevant with respect to rule sync.

# Remove whitespace
is = is.gsub(/\s+/,'')
should = @should.first.to_s.gsub(/\s+/,'')

# Keep track of negation, but remove the '!'
is_negate = ''
should_negate = ''
if is.start_with?('!')
is = is.gsub(/^!/,'')
is_negate = '!'
end
if should.start_with?('!')
should = should.gsub(/^!/,'')
should_negate = '!'
end

# If 'should' contains anything other than digits,
# we assume that we have to do a lookup to convert
# to UID
unless should[/[0-9]+/] == should
should = Etc.getgrnam(should).gid
end

# If 'is' contains anything other than digits,
# we assume that we have to do a lookup to convert
# to UID
unless is[/[0-9]+/] == is
is = Etc.getgrnam(is).gid
end

return "#{is_negate}#{is}" == "#{should_negate}#{should}"
end
end

# match mark
Expand Down Expand Up @@ -1579,6 +1647,79 @@ def should_to_s(value)
newvalues(/^[A-Z]{2}(,[A-Z]{2})*$/)
end

newproperty(:hashlimit_name) do
desc <<-EOS
The name for the /proc/net/ipt_hashlimit/foo entry.
This parameter is required.
EOS
end

newproperty(:hashlimit_upto) do
desc <<-EOS
Match if the rate is below or equal to amount/quantum. It is specified either as a number, with an optional time quantum suffix (the default is 3/hour), or as amountb/second (number of bytes per second).
This parameter or hashlimit_above is required.
Allowed forms are '40','40/second','40/minute','40/hour','40/day'.
EOS
end

newproperty(:hashlimit_above) do
desc <<-EOS
Match if the rate is above amount/quantum.
This parameter or hashlimit_upto is required.
Allowed forms are '40','40/second','40/minute','40/hour','40/day'.
EOS
end

newproperty(:hashlimit_burst) do
desc <<-EOS
Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not reached, up to this number; the default is 5. When byte-based rate matching is requested, this option specifies the amount of bytes that can exceed the given rate. This option should be used with caution -- if the entry expires, the burst value is reset too.
EOS
newvalue(/^\d+$/)
end

newproperty(:hashlimit_mode) do
desc <<-EOS
A comma-separated list of objects to take into consideration. If no --hashlimit-mode option is given, hashlimit acts like limit, but at the expensive of doing the hash housekeeping.
Allowed values are: srcip, srcport, dstip, dstport
EOS
end

newproperty(:hashlimit_srcmask) do
desc <<-EOS
When --hashlimit-mode srcip is used, all source addresses encountered will be grouped according to the given prefix length and the so-created subnet will be subject to hashlimit. prefix must be between (inclusive) 0 and 32. Note that --hashlimit-srcmask 0 is basically doing the same thing as not specifying srcip for --hashlimit-mode, but is technically more expensive.
EOS
end

newproperty(:hashlimit_dstmask) do
desc <<-EOS
Like --hashlimit-srcmask, but for destination addresses.
EOS
end

newproperty(:hashlimit_htable_size) do
desc <<-EOS
The number of buckets of the hash table
EOS
end

newproperty(:hashlimit_htable_max) do
desc <<-EOS
Maximum entries in the hash.
EOS
end

newproperty(:hashlimit_htable_expire) do
desc <<-EOS
After how many milliseconds do hash entries expire.
EOS
end

newproperty(:hashlimit_htable_gcinterval) do
desc <<-EOS
How many milliseconds between garbage collection intervals.
EOS
end

autorequire(:firewallchain) do
reqs = []
protocol = nil
Expand Down Expand Up @@ -1784,5 +1925,10 @@ def should_to_s(value)
end
end

if value(:hashlimit_name)
unless value(:hashlimit_upto) || value(:hashlimit_above)
self.fail "Either hashlimit_upto or hashlimit_above are required"
end
end
end
end
38 changes: 31 additions & 7 deletions lib/puppet/util/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def string_to_port(value, proto)
end
end

# Takes an address and returns it in CIDR notation.
# Takes an address and protocol and returns the address in CIDR notation.
#
# The protocol is only used when the address is a hostname.
#
# If the address is:
#
Expand All @@ -105,27 +107,49 @@ def string_to_port(value, proto)
# - Any address with a resulting prefix length of zero:
# It will return nil which is equivilent to not specifying an address
#
def host_to_ip(value)
def host_to_ip(value, proto = nil)
begin
value = Puppet::Util::IPCidr.new(value)
rescue
value = Puppet::Util::IPCidr.new(Resolv.getaddress(value))
family = case proto
when :IPv4
Socket::AF_INET
when :IPv6
Socket::AF_INET6
when nil
raise ArgumentError, "Proto must be specified for a hostname"
else
raise ArgumentError, "Unsupported address family: #{proto}"
end

new_value = nil
Resolv.each_address(value) do |addr|
begin
new_value = Puppet::Util::IPCidr.new(addr, family)
break
rescue
end
end

raise "Failed to resolve hostname #{value}" unless new_value != nil
value = new_value
end

return nil if value.prefixlen == 0
value.cidr
end

# Takes an address mask and converts the host portion to CIDR notation.
# Takes an address mask and protocol and converts the host portion to CIDR
# notation.
#
# This takes into account you can negate a mask but follows all rules
# defined in host_to_ip for the host/address part.
#
def host_to_mask(value)
def host_to_mask(value, proto)
match = value.match /(!)\s?(.*)$/
return host_to_ip(value) unless match
return host_to_ip(value, proto) unless match

cidr = host_to_ip(match[2])
cidr = host_to_ip(match[2], proto)
return nil if cidr == nil
"#{match[1]} #{cidr}"
end
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/util/ipcidr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
module Puppet
module Util
class IPCidr < IPAddr
def initialize(ipaddr)
def initialize(ipaddr, family = Socket::AF_UNSPEC)
begin
super(ipaddr)
super(ipaddr, family)
rescue ArgumentError => e
if e.message =~ /invalid address/
raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}"
Expand Down
26 changes: 26 additions & 0 deletions locales/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
# This is the project-specific configuration file for setting up
# fast_gettext for your project.
gettext:
# This is used for the name of the .pot and .po files; they will be
# called <project_name>.pot?
project_name: puppetlabs-firewall
# This is used in comments in the .pot and .po files to indicate what
# project the files belong to and should bea little more desctiptive than
# <project_name>
package_name: puppetlabs-firewall
# The locale that the default messages in the .pot file are in
default_locale: en
# The email used for sending bug reports.
bugs_address: docs@puppet.com
# The holder of the copyright.
copyright_holder: Puppet, Inc.
# This determines which comments in code should be eligible for translation.
# Any comments that start with this string will be externalized. (Leave
# empty to include all.)
comments_tag: TRANSLATOR
# Patterns for +Dir.glob+ used to find all files that might contain
# translatable content, relative to the project root directory
source_files:
- './lib/**/*.rb'

15 changes: 15 additions & 0 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
#
class firewall (
$ensure = running,
$ensure_v6 = undef,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$service_name_v6 = $::firewall::params::service_name_v6,
$package_name = $::firewall::params::package_name,
$ebtables_manage = false,
) inherits ::firewall::params {
$_ensure_v6 = pick($ensure_v6, $ensure)

case $ensure {
/^(running|stopped)$/: {
# Do nothing.
Expand All @@ -28,10 +31,22 @@
}
}

if $ensure_v6 {
case $ensure_v6 {
/^(running|stopped)$/: {
# Do nothing.
}
default: {
fail("${title}: ensure_v6 value '${ensure_v6}' is not supported")
}
}
}

case $::kernel {
'Linux': {
class { "${title}::linux":
ensure => $ensure,
ensure_v6 => $_ensure_v6,
pkg_ensure => $pkg_ensure,
service_name => $service_name,
service_name_v6 => $service_name_v6,
Expand Down
15 changes: 15 additions & 0 deletions manifests/linux.pp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,28 @@
# service will be started on boot, and when `stopped` it will not.
# Default: running
#
# [*ensure_v6*]
# Ensure parameter passed onto Service[] resources. When `running` the
# service will be started on boot, and when `stopped` it will not.
# Default: running
#
class firewall::linux (
$ensure = running,
$ensure_v6 = undef,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$service_name_v6 = $::firewall::params::service_name_v6,
$package_name = $::firewall::params::package_name,
$ebtables_manage = false,
) inherits ::firewall::params {
$enable = $ensure ? {
'running' => true,
'stopped' => false,
}

$_ensure_v6 = pick($ensure_v6, $ensure)

$_enable_v6 = $_ensure_v6 ? {
running => true,
stopped => false,
}
Expand All @@ -40,7 +53,9 @@
'VirtuozzoLinux': {
class { "${title}::redhat":
ensure => $ensure,
ensure_v6 => $_ensure_v6,
enable => $enable,
enable_v6 => $_enable_v6,
package_name => $package_name,
service_name => $service_name,
service_name_v6 => $service_name_v6,
Expand Down
4 changes: 2 additions & 2 deletions manifests/linux/debian.pp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
#Fixes hang while installing iptables-persistent on debian 8
exec {'iptables-persistent-debconf':
command => "/bin/echo \"${package_name} ${package_name}/autosave_v4 boolean false\" | /usr/bin/debconf-set-selections && /bin/echo \"${package_name} ${package_name}/autosave_v6 boolean false\" | /usr/bin/debconf-set-selections",
refreshonly => true
refreshonly => true,
}
package { $package_name:
ensure => $package_ensure,
require => Exec['iptables-persistent-debconf']
require => Exec['iptables-persistent-debconf'],
}
}

Expand Down
24 changes: 19 additions & 5 deletions manifests/linux/redhat.pp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,31 @@
# Ensure parameter passed onto Service[] resources.
# Default: running
#
# [*ensure_v6*]
# Ensure parameter passed onto Service[] resources.
# Default: running
#
# [*enable*]
# Enable parameter passed onto Service[] resources.
# Default: true
#
# [*enable_v6*]
# Enable parameter passed onto Service[] resources.
# Default: true
#
#
class firewall::linux::redhat (
$ensure = running,
$ensure_v6 = undef,
$enable = true,
$enable_v6 = undef,
$service_name = $::firewall::params::service_name,
$service_name_v6 = $::firewall::params::service_name_v6,
$package_name = $::firewall::params::package_name,
$package_ensure = $::firewall::params::package_ensure,
) inherits ::firewall::params {
$_ensure_v6 = pick($ensure_v6, $ensure)
$_enable_v6 = pick($enable_v6, $enable)

# RHEL 7 / CentOS 7 and later and Fedora 15 and later require the iptables-services
# package, which provides the /usr/libexec/iptables/iptables.init used by
Expand All @@ -46,9 +59,10 @@
or ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
if $ensure == 'running' {
exec { '/usr/bin/systemctl daemon-reload':
require => Package[$package_name],
before => Service[$service_name, $service_name_v6],
unless => "/usr/bin/systemctl is-active ${service_name} ${service_name_v6}",
require => Package[$package_name],
before => Service[$service_name, $service_name_v6],
subscribe => Package[$package_name],
refreshonly => true,
}
}
}
Expand All @@ -59,8 +73,8 @@
hasstatus => true,
}
service { $service_name_v6:
ensure => $ensure,
enable => $enable,
ensure => $_ensure_v6,
enable => $_enable_v6,
hasstatus => true,
}

Expand Down
6 changes: 3 additions & 3 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "puppetlabs-firewall",
"version": "1.9.0",
"version": "1.10.0",
"author": "Puppet Labs",
"summary": "Manages Firewalls such as iptables",
"license": "Apache-2.0",
Expand Down Expand Up @@ -71,10 +71,10 @@
"requirements": [
{
"name": "puppet",
"version_requirement": ">= 3.5.0 < 5.0.0"
"version_requirement": ">= 4.7.0 < 6.0.0"
}
],
"dependencies": [

{"name":"puppetlabs/stdlib","version_requirement":">= 4.0.0 < 5.0.0"}
]
}
4 changes: 2 additions & 2 deletions spec/acceptance/connlimit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class { '::firewall': }
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 2222 -m comment --comment "500 - test" -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 2222 -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-m comment --comment "500 - test" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
Expand All @@ -54,7 +54,7 @@ class { '::firewall': }
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 2222 -m comment --comment "501 - test" -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 2222 -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-m comment --comment "501 - test" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/acceptance/connmark_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class { '::firewall': }

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/)
expect(r.stdout).to match(/-A INPUT -m connmark --mark 0x1 -m comment --comment "502 - test" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
Expand Down
104 changes: 104 additions & 0 deletions spec/acceptance/firewall_gid_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require 'spec_helper_acceptance'

describe 'firewall gid' do
before :all do
iptables_flush_all_tables
ip6tables_flush_all_tables
end

describe "gid tests" do
context 'gid set to root' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '801 - test':
chain => 'OUTPUT',
action => accept,
gid => 'root',
proto => 'all',
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -m owner --gid-owner (0|root) -m comment --comment "801 - test" -j ACCEPT/)
end
end
end

context 'gid set to !root' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '802 - test':
chain => 'OUTPUT',
action => accept,
gid => '!root',
proto => 'all',
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -m owner ! --gid-owner (0|root) -m comment --comment "802 - test" -j ACCEPT/)
end
end
end

context 'gid set to 0' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '803 - test':
chain => 'OUTPUT',
action => accept,
gid => '0',
proto => 'all',
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -m owner --gid-owner (0|root) -m comment --comment "803 - test" -j ACCEPT/)
end
end
end

context 'gid set to !0' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '804 - test':
chain => 'OUTPUT',
action => accept,
gid => '!0',
proto => 'all',
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -m owner ! --gid-owner (0|root) -m comment --comment "804 - test" -j ACCEPT/)
end
end
end

end

end
4 changes: 2 additions & 2 deletions spec/acceptance/firewall_mss_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save -t mangle') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "502 - set_mss" -m tcpmss --mss 1361:1541 -j TCPMSS --set-mss 1360/)
expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1541 -m comment --comment "502 - set_mss" -j TCPMSS --set-mss 1360/)
end
end
end
Expand Down Expand Up @@ -82,7 +82,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save -t mangle') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "502 - set_mss" -m tcpmss --mss 1361:1541 -j TCPMSS --set-mss 1360/)
expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1541 -m comment --comment "502 - set_mss" -j TCPMSS --set-mss 1360/)
end
end
end
Expand Down
39 changes: 20 additions & 19 deletions spec/acceptance/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,9 @@ class { '::firewall': }
end
end

#iptables version 1.3.5 is not suppored by the ip6tables provider
if default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/
# iptables version 1.3.5 is not suppored by the ip6tables provider
# iptables version 1.4.7 fails for multiple hl entries
if default['platform'] !~ /(el-5|el-6|sles-10|sles-11)/
describe 'hop_limit' do
context '5' do
it 'applies' do
Expand All @@ -976,7 +977,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 571 -m comment --comment "571 - test" -m hl --hl-eq 5 -j ACCEPT/)
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 571 -m hl --hl-eq 5 -m comment --comment "571 - test" -j ACCEPT/)
end
end
end
Expand Down Expand Up @@ -1390,7 +1391,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "607 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp6-adm-prohibited/)
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol ipsec -m comment --comment "607 - test" -j REJECT --reject-with icmp6-adm-prohibited/)
end
end
end
Expand Down Expand Up @@ -1418,7 +1419,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "608 - test" -m policy --dir out --pol none -j REJECT --reject-with icmp6-adm-prohibited/)
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol none -m comment --comment "608 - test" -j REJECT --reject-with icmp6-adm-prohibited/)
end
end
end
Expand Down Expand Up @@ -1448,7 +1449,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "609 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp6-adm-prohibited/)
expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol ipsec -m comment --comment "609 - test" -j REJECT --reject-with icmp6-adm-prohibited/)
end
end
end
Expand Down Expand Up @@ -1476,7 +1477,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "610 - test" -m policy --dir in --pol none -j REJECT --reject-with icmp6-adm-prohibited/)
expect(r.stdout).to match(/-A INPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir in --pol none -m comment --comment "610 - test" -j REJECT --reject-with icmp6-adm-prohibited/)
end
end
end
Expand Down Expand Up @@ -1564,7 +1565,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "612 - test" -m set --match-set blacklist src,dst -m set ! --match-set honeypot dst -j DROP/)
expect(r.stdout).to match(/-A INPUT -p tcp -m set --match-set blacklist src,dst -m set ! --match-set honeypot dst -m comment --comment "612 - test" -j DROP/)
end
end
end
Expand Down Expand Up @@ -1593,7 +1594,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A FORWARD -p tcp -m comment --comment "613 - test" -m recent --update --seconds 60 --name test --mask ffff:: --rsource -j DROP/)
expect(r.stdout).to match(/-A FORWARD -p tcp -m recent --update --seconds 60 --name test --mask ffff:: --rsource -m comment --comment "613 - test" -j DROP/)
end
end
end
Expand Down Expand Up @@ -1695,7 +1696,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 572 -m comment --comment "572 - test" -m limit --limit 500\/sec -j ACCEPT/)
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 572 -m limit --limit 500\/sec -m comment --comment "572 - test" -j ACCEPT/)
end
end
end
Expand All @@ -1721,7 +1722,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 573 -m comment --comment "573 - test" -m limit --limit 500\/sec --limit-burst 1500 -j ACCEPT/)
expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 573 -m limit --limit 500\/sec --limit-burst 1500 -m comment --comment "573 - test" -j ACCEPT/)
end
end
end
Expand Down Expand Up @@ -2009,7 +2010,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "593 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/)
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol ipsec -m comment --comment "593 - test" -j REJECT --reject-with icmp-net-unreachable/)
end
end
end
Expand All @@ -2036,7 +2037,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "594 - test" -m policy --dir out --pol none -j REJECT --reject-with icmp-net-unreachable/)
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol none -m comment --comment "594 - test" -j REJECT --reject-with icmp-net-unreachable/)
end
end
end
Expand Down Expand Up @@ -2065,7 +2066,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "595 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/)
expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol ipsec -m comment --comment "595 - test" -j REJECT --reject-with icmp-net-unreachable/)
end
end
end
Expand All @@ -2092,7 +2093,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "596 - test" -m policy --dir in --pol none -j REJECT --reject-with icmp-net-unreachable/)
expect(r.stdout).to match(/-A INPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir in --pol none -m comment --comment "596 - test" -j REJECT --reject-with icmp-net-unreachable/)
end
end
end
Expand Down Expand Up @@ -2121,7 +2122,7 @@ class { '::firewall': }
it 'should contain the rule' do
shell('iptables-save') do |r|
# Mask added as of Ubuntu 14.04.
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "597 - test" -m recent --set --name list1 (--mask 255.255.255.255 )?--rdest/)
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --set --name list1 (--mask 255.255.255.255 )?--rdest -m comment --comment "597 - test"/)
end
end
end
Expand Down Expand Up @@ -2150,7 +2151,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "598 - test" -m recent --rcheck --seconds 60 --hitcount 5 --rttl --name list1 (--mask 255.255.255.255 )?--rsource/)
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --rcheck --seconds 60 --hitcount 5 --rttl --name list1 (--mask 255.255.255.255 )?--rsource -m comment --comment "598 - test"/)
end
end
end
Expand All @@ -2174,7 +2175,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "599 - test" -m recent --update/)
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --update --name DEFAULT (--mask 255.255.255.255 )?--rsource -m comment --comment "599 - test"/)
end
end
end
Expand All @@ -2198,7 +2199,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "600 - test" -m recent --remove/)
expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --remove --name DEFAULT (--mask 255.255.255.255 )?--rsource -m comment --comment "600 - test"/)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/acceptance/firewall_time_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m comment --comment "805 - test" -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -j ACCEPT/)
expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -m comment --comment "805 - test" -j ACCEPT/)
end
end
end
Expand Down Expand Up @@ -66,7 +66,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m comment --comment "805 - test" -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -j ACCEPT/)
expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -m comment --comment "805 - test" -j ACCEPT/)
end
end
end
Expand Down
133 changes: 133 additions & 0 deletions spec/acceptance/hashlimit_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@

require 'spec_helper_acceptance'

describe 'hashlimit property', if: fact('operatingsystemmajrelease') != '5' && (fact('operatingsystem') != 'Scientific' || fact('operatingsystem') != 'RedHat') do
before :all do
iptables_flush_all_tables
ip6tables_flush_all_tables
end

describe 'hashlimit_tests' do
context 'hashlimit_above' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '800 - hashlimit_above test':
chain => 'INPUT',
proto => 'tcp',
hashlimit_name => 'above',
hashlimit_above => '526/sec',
hashlimit_htable_gcinterval => '10',
hashlimit_mode => 'srcip,dstip',
action => accept,
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT/)
expect(r.stdout).to match(/-p tcp/)
expect(r.stdout).to match(/--hashlimit-above 526\/sec/)
expect(r.stdout).to match(/--hashlimit-mode srcip,dstip/)
expect(r.stdout).to match(/--hashlimit-name above/)
expect(r.stdout).to match(/--hashlimit-htable-gcinterval 10/)
expect(r.stdout).to match(/-j ACCEPT/)
end
end
end

context 'hashlimit_above_ip6' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '801 - hashlimit_above test ipv6':
chain => 'INPUT',
provider => 'ip6tables',
proto => 'tcp',
hashlimit_name => 'above-ip6',
hashlimit_above => '526/sec',
hashlimit_htable_gcinterval => '10',
hashlimit_mode => 'srcip,dstip',
action => accept,
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT/)
expect(r.stdout).to match(/-p tcp/)
expect(r.stdout).to match(/--hashlimit-above 526\/sec/)
expect(r.stdout).to match(/--hashlimit-mode srcip,dstip/)
expect(r.stdout).to match(/--hashlimit-name above-ip6/)
expect(r.stdout).to match(/--hashlimit-htable-gcinterval 10/)
expect(r.stdout).to match(/-j ACCEPT/)
end
end
end

context 'hashlimit_upto' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '802 - hashlimit_upto test':
chain => 'INPUT',
hashlimit_name => 'upto',
hashlimit_upto => '16/sec',
hashlimit_burst => '640',
hashlimit_htable_size => '1310000',
hashlimit_htable_max => '320000',
hashlimit_htable_expire => '36000000',
action => accept,
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m hashlimit --hashlimit-upto 16\/sec --hashlimit-burst 640 --hashlimit-name upto --hashlimit-htable-size 1310000 --hashlimit-htable-max 320000 --hashlimit-htable-expire 36000000 -m comment --comment "802 - hashlimit_upto test" -j ACCEPT/)
end
end
end

context 'hashlimit_upto_ip6' do
it 'applies' do
pp = <<-EOS
class { '::firewall': }
firewall { '803 - hashlimit_upto test ip6':
chain => 'INPUT',
provider => 'ip6tables',
hashlimit_name => 'upto-ip6',
hashlimit_upto => '16/sec',
hashlimit_burst => '640',
hashlimit_htable_size => '1310000',
hashlimit_htable_max => '320000',
hashlimit_htable_expire => '36000000',
action => accept,
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => do_catch_changes)
end

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT -p tcp -m hashlimit --hashlimit-upto 16\/sec --hashlimit-burst 640 --hashlimit-name upto-ip6 --hashlimit-htable-size 1310000 --hashlimit-htable-max 320000 --hashlimit-htable-expire 36000000 -m comment --comment "803 - hashlimit_upto test ip6" -j ACCEPT/)
end
end
end

end

end
12 changes: 5 additions & 7 deletions spec/acceptance/invert_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ class { '::firewall': }

it 'should contain the rules' do
shell('iptables-save') do |r|
if (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '5') or (default['platform'] =~ /sles-10/)
expect(r.stdout).to match(/-A INPUT -p ! esp -m comment --comment "601 disallow esp protocol" -j ACCEPT/)
expect(r.stdout).to match(/-A INPUT -s ! 10\.0\.0\.0\/255\.0\.0\.0 -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m multiport --sports ! 80,443 -m comment --comment "602 drop NEW external website packets with FIN\/RST\/ACK set and SYN unset" -m state --state NEW -j DROP/)
else
expect(r.stdout).to match(/-A INPUT ! -p esp -m comment --comment "601 disallow esp protocol" -j ACCEPT/)
expect(r.stdout).to match(/-A INPUT ! -s 10\.0\.0\.0\/8 -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m multiport ! --sports 80,443 -m comment --comment "602 drop NEW external website packets with FIN\/RST\/ACK set and SYN unset" -m state --state NEW -j DROP/)
end
expect(r.stdout).to match(/-A INPUT (-s !|! -s) (10\.0\.0\.0\/8|10\.0\.0\.0\/255\.0\.0\.0).*/)
expect(r.stdout).to match(/-A INPUT.*(--sports !|! --sports) 80,443.*/)
expect(r.stdout).to match(/-A INPUT.*-m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN.*/)
expect(r.stdout).to match(/-A INPUT.*-j DROP/)
expect(r.stdout).to match(/-A INPUT (! -p|-p !) esp -m comment --comment "601 disallow esp protocol" -j ACCEPT/)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/acceptance/match_mark_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('iptables-save') do |r|
expect(r.stdout).to match(/-A INPUT -m comment --comment "503 match_mark - test" -m mark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable/)
expect(r.stdout).to match(/-A INPUT -m mark --mark 0x1 -m comment --comment "503 match_mark - test" -j REJECT --reject-with icmp-port-unreachable/)
end
end
end
Expand All @@ -48,7 +48,7 @@ class { '::firewall': }

it 'should contain the rule' do
shell('ip6tables-save') do |r|
expect(r.stdout).to match(/-A INPUT -m comment --comment "503 match_mark ip6tables - test" -m mark --mark 0x1 -j REJECT --reject-with icmp6-port-unreachable/)
expect(r.stdout).to match(/-A INPUT -m mark --mark 0x1 -m comment --comment "503 match_mark ip6tables - test" -j REJECT --reject-with icmp6-port-unreachable/)
end
end
end
Expand Down
30 changes: 14 additions & 16 deletions spec/acceptance/rules_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
/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 tcp -m multiport --ports 80,443,21,20,22,53,123,43,873,25,465 -m state --state NEW -m comment --comment \"100 forward standard allow tcp\" -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)
Expand All @@ -131,10 +131,8 @@ class { '::firewall': }
Firewall {
proto => 'all',
stage => 'pre',
}
Firewallchain {
stage => 'pre',
purge => 'true',
ignore => [
'--comment "[^"]*(?i:ignore)[^"]*"',
Expand Down Expand Up @@ -259,19 +257,19 @@ class { '::firewall': }
/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 -d 127.0.0.0\/(8|255\.0\.0\.0) (! -i|-i !) lo -m comment --comment \"011 reject local traffic not on loopback interface\" -j REJECT --reject-with icmp-port-unreachable/,
/-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 -p tcp -m multiport --dports 22 -m comment --comment \"001 ssh needed for beaker testing\" -j ACCEPT/,
/-A OUTPUT (! -o|-o !) eth0:2 -p tcp -m multiport --dports 25 -m comment --comment \"025 smtp\" -m state --state NEW -j ACCEPT/,
/-A INPUT -i eth0:3 -p tcp -m multiport --dports 443 -m comment --comment \"443 ssl on aliased interface\" -m state --state NEW -j ACCEPT/,
/-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT/,
/-A FORWARD -m comment --comment \"010 allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/
/-A INPUT -m comment --comment \"001 LOCAL_INPUT_PRE\" -j LOCAL_INPUT_PRE/,
/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"001 ssh needed for beaker testing\" -j ACCEPT/,
/-A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment \"010 INPUT allow established and related\" -j ACCEPT/,
/-A INPUT -d 127.0.0.0\/(8|255\.0\.0\.0) (! -i|-i !) lo -m comment --comment \"011 reject local traffic not on loopback interface\" -j REJECT --reject-with icmp-port-unreachable/,
/-A INPUT -i lo -m comment --comment \"012 accept loopback\" -j ACCEPT/,
/-A INPUT -p icmp -m icmp --icmp-type 3 -m comment --comment \"013 icmp destination-unreachable\" -j ACCEPT/,
/-A INPUT -s 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m icmp --icmp-type 8 -m comment --comment \"013 icmp echo-request\" -j ACCEPT/,
/-A INPUT -p icmp -m icmp --icmp-type 11 -m comment --comment \"013 icmp time-exceeded\" -j ACCEPT/,
/-A INPUT -p tcp -m multiport --dports 22 -m state --state NEW -m comment --comment \"020 ssh\" -j ACCEPT/,
/-A INPUT -i eth0:3 -p tcp -m multiport --dports 443 -m state --state NEW -m comment --comment \"443 ssl on aliased interface\" -j ACCEPT/,
/-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT/,
/-A FORWARD -m state --state RELATED,ESTABLISHED -m comment --comment \"010 allow established and related\" -j ACCEPT/,
/-A OUTPUT (! -o|-o !) eth0:2 -p tcp -m multiport --dports 25 -m state --state NEW -m comment --comment \"025 smtp\" -j ACCEPT/
].each do |line|
expect(r.stdout).to match(line)
end
Expand Down
2 changes: 1 addition & 1 deletion spec/fixtures/ip6tables/conversion_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@
:provider => 'ip6tables',
:table => "filter",
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 hop limit", "-m", "hl", "--hl-eq", 255],
:args => ["-t", :filter, "-p", :tcp, "-m", "hl", "--hl-eq", 255, "-m", "comment", "--comment", "100 hop limit"],
},
}
178 changes: 97 additions & 81 deletions spec/fixtures/iptables/conversion_hash.rb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#This file is generated by ModuleSync, do not edit.
require 'puppetlabs_spec_helper/module_spec_helper'

if Puppet.version.to_f >= 4.5
if Puppet::Util::Package.versioncmp(Puppet.version, '4.5.0') >= 0
RSpec.configure do |c|
c.before :each do
Puppet.settings[:strict] = :error
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper_acceptance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def do_catch_changes
c.before :suite do
# Install module and dependencies
hosts.each do |host|
on host, puppet('module', 'install', 'puppetlabs-stdlib'), { :acceptable_exit_codes => [0] }
# the ubuntu-14.04 docker image doesn't carry the iptables command
apply_manifest_on host, 'package { "iptables": ensure => installed }' if fact('osfamily') == 'Debian'
end
Expand Down
16 changes: 12 additions & 4 deletions spec/unit/classes/firewall_linux_redhat_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,21 @@
:enable => 'true'
)}
it { should contain_service('ip6tables').with(
:ensure => 'running',
:enable => 'true'
:ensure => 'running',
:enable => 'true'
)}

context 'ensure => stopped' do
let(:params) {{ :ensure => 'stopped' }}
it { should contain_service('iptables').with(
:ensure => 'stopped'
)}
end

context 'ensure_v6 => stopped' do
let(:params) {{ :ensure_v6 => 'stopped' }}
it { should contain_service('ip6tables').with(
:ensure => 'stopped'
:ensure => 'stopped'
)}
end

Expand All @@ -79,8 +83,12 @@
it { should contain_service('iptables').with(
:enable => 'false'
)}
end

context 'enable_v6 => false' do
let(:params) {{ :enable_v6 => 'false' }}
it { should contain_service('ip6tables').with(
:enable => 'false'
:enable => 'false'
)}
end

Expand Down
6 changes: 6 additions & 0 deletions spec/unit/documentation/readme_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
describe 'formatting in README.markdown' do
it 'should not contain badly formatted heading markers' do
content = File.read('README.markdown')
expect(content).to_not match /^#+[^# ]/
end
end
8 changes: 8 additions & 0 deletions spec/unit/puppet/provider/iptables_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@
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 error was raised
if data[:raise_error] then
it "the input rules should raise an error by rules_to_hash" do
expect{ resource }.to raise_error
end
end

# 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
Expand Down Expand Up @@ -425,6 +432,7 @@
let(:instance) { provider6.new(resource) }

it 'general_args should be valid' do
data[:args].unshift("--wait") if instance.general_args.flatten.include? '--wait'
expect(instance.general_args.flatten).to eql data[:args]
end
end
Expand Down
17 changes: 15 additions & 2 deletions spec/unit/puppet/type/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@
it 'should fail if icmp type is "any"' do
expect(lambda { @resource[:icmp] = 'any' }).to raise_error(Puppet::Error)
end
it 'should fail if icmp type is an array' do
expect(lambda { @resource[:icmp] = "['0', '8']" }).to raise_error(Puppet::Error)
end

it 'should fail if icmp type cannot be mapped to a numeric' do
expect(lambda { @resource[:icmp] = 'foo' }).to raise_error(Puppet::Error)
Expand All @@ -357,14 +360,19 @@
expect(@resource[:state]).to eql [:INVALID]
end

it 'should accept value as a string' do
@resource[:state] = :UNTRACKED
expect(@resource[:state]).to eql [:UNTRACKED]
end

it 'should accept value as an array' do
@resource[:state] = [:INVALID, :NEW]
expect(@resource[:state]).to eql [:INVALID, :NEW]
end

it 'should sort values alphabetically' do
@resource[:state] = [:NEW, :ESTABLISHED]
expect(@resource[:state]).to eql [:ESTABLISHED, :NEW]
@resource[:state] = [:NEW, :UNTRACKED, :ESTABLISHED]
expect(@resource[:state]).to eql [:ESTABLISHED, :NEW, :UNTRACKED]
end
end

Expand All @@ -374,6 +382,11 @@
expect(@resource[:ctstate]).to eql [:INVALID]
end

it 'should accept value as a string' do
@resource[:state] = :UNTRACKED
expect(@resource[:state]).to eql [:UNTRACKED]
end

it 'should accept value as an array' do
@resource[:ctstate] = [:INVALID, :NEW]
expect(@resource[:ctstate]).to eql [:INVALID, :NEW]
Expand Down
37 changes: 20 additions & 17 deletions spec/unit/puppet/util/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
describe '#host_to_ip' do
subject { resource }
it {
expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51')
expect(subject.host_to_ip('puppetlabs.com')).to eql '96.126.112.51/32'
expect(Resolv).to receive(:each_address).at_least(:once).with('puppetlabs.com').and_yield('96.126.112.51').and_yield('2001:DB8:4650::13:8A')
expect(subject.host_to_ip('puppetlabs.com', :IPv4)).to eql '96.126.112.51/32'
expect(subject.host_to_ip('puppetlabs.com', :IPv6)).to eql '2001:db8:4650::13:8a/128'
}
it { expect(subject.host_to_ip('96.126.112.51')).to eql '96.126.112.51/32' }
it { expect(subject.host_to_ip('96.126.112.51/32')).to eql '96.126.112.51/32' }
Expand All @@ -28,22 +29,24 @@
describe '#host_to_mask' do
subject { resource }
it {
expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51')
expect(subject.host_to_mask('puppetlabs.com')).to eql '96.126.112.51/32'
expect(subject.host_to_mask('!puppetlabs.com')).to eql '! 96.126.112.51/32'
expect(Resolv).to receive(:each_address).at_least(:once).with('puppetlabs.com').and_yield('96.126.112.51').and_yield('2001:DB8:4650::13:8A')
expect(subject.host_to_mask('puppetlabs.com', :IPv4)).to eql '96.126.112.51/32'
expect(subject.host_to_mask('!puppetlabs.com', :IPv4)).to eql '! 96.126.112.51/32'
expect(subject.host_to_mask('puppetlabs.com', :IPv6)).to eql '2001:db8:4650::13:8a/128'
expect(subject.host_to_mask('!puppetlabs.com', :IPv6)).to eql '! 2001:db8:4650::13:8a/128'
}
it { expect(subject.host_to_mask('96.126.112.51')).to eql '96.126.112.51/32' }
it { expect(subject.host_to_mask('!96.126.112.51')).to eql '! 96.126.112.51/32' }
it { expect(subject.host_to_mask('96.126.112.51/32')).to eql '96.126.112.51/32' }
it { expect(subject.host_to_mask('! 96.126.112.51/32')).to eql '! 96.126.112.51/32' }
it { expect(subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334')).to eql '2001:db8:85a3::8a2e:370:7334/128' }
it { expect(subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334')).to eql '! 2001:db8:85a3::8a2e:370:7334/128' }
it { expect(subject.host_to_mask('2001:db8:1234::/48')).to eql '2001:db8:1234::/48' }
it { expect(subject.host_to_mask('! 2001:db8:1234::/48')).to eql '! 2001:db8:1234::/48' }
it { expect(subject.host_to_mask('0.0.0.0/0')).to eql nil }
it { expect(subject.host_to_mask('!0.0.0.0/0')).to eql nil }
it { expect(subject.host_to_mask('::/0')).to eql nil }
it { expect(subject.host_to_mask('! ::/0')).to eql nil }
it { expect(subject.host_to_mask('96.126.112.51', :IPv4)).to eql '96.126.112.51/32' }
it { expect(subject.host_to_mask('!96.126.112.51', :IPv4)).to eql '! 96.126.112.51/32' }
it { expect(subject.host_to_mask('96.126.112.51/32', :IPv4)).to eql '96.126.112.51/32' }
it { expect(subject.host_to_mask('! 96.126.112.51/32', :IPv4)).to eql '! 96.126.112.51/32' }
it { expect(subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334', :IPv6)).to eql '2001:db8:85a3::8a2e:370:7334/128' }
it { expect(subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334', :IPv6)).to eql '! 2001:db8:85a3::8a2e:370:7334/128' }
it { expect(subject.host_to_mask('2001:db8:1234::/48', :IPv6)).to eql '2001:db8:1234::/48' }
it { expect(subject.host_to_mask('! 2001:db8:1234::/48', :IPv6)).to eql '! 2001:db8:1234::/48' }
it { expect(subject.host_to_mask('0.0.0.0/0', :IPv4)).to eql nil }
it { expect(subject.host_to_mask('!0.0.0.0/0', :IPv4)).to eql nil }
it { expect(subject.host_to_mask('::/0', :IPv6)).to eql nil }
it { expect(subject.host_to_mask('! ::/0', :IPv6)).to eql nil }
end

describe '#icmp_name_to_number' do
Expand Down