diff --git a/README.markdown b/README.markdown index 3b43b624d..b9c4713d2 100644 --- a/README.markdown +++ b/README.markdown @@ -467,6 +467,10 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov * `ctstate`: Matches a packet based on its state in the firewall stateful inspection table, using the conntrack module. Valid values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED'. Requires the `state_match` feature. +* `date_start`: Start Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' + +* `date_stop`: End Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' + * `destination`: The destination address to match. For example: `destination => '192.168.1.0/24'`. You can also negate a mask by putting ! in front. For example: `destination => '! 192.168.2.0/24'`. The destination can also be an IPv6 address if your provider supports it. For some firewall providers you can pass a range of ports in the format: 'start number-end number'. For example, '1-1024' would cover ports 1 to 1024. @@ -525,6 +529,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov If you set both `accept` and `jump` parameters, you will get an error, because only one of the options should be set. Requires the `iptables` feature. +* `kernel_timezone`: Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations. + * `limit`: Rate limiting value for matched packets. The format is: 'rate/[/second/|/minute|/hour|/day]'. Example values are: '50/sec', '40/min', '30/hour', '10/day'. Requires the `rate_limiting` feature. * `line`: Read-only property for caching the rule line. @@ -535,6 +541,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov * `mask`: Sets the mask to use when `recent` is enabled. Requires the `mask` feature. +* `month_days`: Only match on the given days of the month. Possible values are '1' to '31'. Note that specifying 31 will of course not match on months which do not have a 31st day; the same goes for 28- or 29-day February. + * `name`: The canonical name of the rule. This name is also used for ordering, so make sure you prefix the rule with a number. For example: ```puppet @@ -668,6 +676,12 @@ firewall { '101 blacklist strange traffic': Note that you specify flags in the order that iptables `--list` rules would list them to avoid having Puppet think you changed the flags. For example, 'FIN,SYN,RST,ACK SYN' matches packets with the SYN bit set and the ACK, RST and FIN bits cleared. Such packets are used to request TCP connection initiation. Requires the `tcp_flags` feature. +* `time_contiguous`: When time_stop is smaller than time_start value, match this as a single time period instead distinct intervals. + +* `time_start`: Start time for the rule to match. The possible time range is '00:00:00' to '23:59:59'. Leading zeroes are allowed (e.g. '06:03') and correctly interpreted as base-10. + +* `time_stop`: End time for the rule to match. The possible time range is '00:00:00' to '23:59:59'. Leading zeroes are allowed (e.g. '06:03') and correctly interpreted as base-10. + * `todest`: When using `jump => 'DNAT'`, you can specify the new destination address using this parameter. Requires the `dnat` feature. * `toports`: For DNAT this is the port that will replace the destination port. Requires the `dnat` feature. @@ -678,6 +692,8 @@ firewall { '101 blacklist strange traffic': * `uid`: UID or Username owner matching rule. Accepts a string argument only, as iptables does not accept multiple uid in a single statement. Requires the `owner` feature. +* `week_days`: Only match on the given weekdays. Possible values are 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'. + ###Type: firewallchain Enables you to manage rule chains for firewalls. diff --git a/lib/puppet/provider/firewall/ip6tables.rb b/lib/puppet/provider/firewall/ip6tables.rb index 8acae8f2e..63d160ab9 100644 --- a/lib/puppet/provider/firewall/ip6tables.rb +++ b/lib/puppet/provider/firewall/ip6tables.rb @@ -123,7 +123,15 @@ def self.iptables_save(*args) :uid => "--uid-owner", :physdev_in => "--physdev-in", :physdev_out => "--physdev-out", - :physdev_is_bridged => "--physdev-is-bridged" + :physdev_is_bridged => "--physdev-is-bridged", + :date_start => "--datestart", + :date_stop => "--datestop", + :time_start => "--timestart", + :time_stop => "--timestop", + :month_days => "--monthdays", + :week_days => "--weekdays", + :time_contiguous => "--contiguous", + :kernel_timezone => "--kerneltz", } # These are known booleans that do not take a value, but we want to munge @@ -138,7 +146,9 @@ def self.iptables_save(*args) :reap, :rttl, :socket, - :physdev_is_bridged + :physdev_is_bridged, + :time_contiguous, + :kernel_timezone, ] # Properties that use "-m " (with the potential to have multiple @@ -158,6 +168,7 @@ def self.iptables_save(*args) :addrtype => [:src_type, :dst_type], :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] } # Create property methods dynamically @@ -201,6 +212,6 @@ def self.iptables_save(*args) :ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :todest, :tosource, :toports, :checksum_fill, :log_level, :log_prefix, :reject, - :set_mark, :connlimit_above, :connlimit_mask, :connmark] + :set_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone] end diff --git a/lib/puppet/provider/firewall/iptables.rb b/lib/puppet/provider/firewall/iptables.rb index 089689cdf..374cb1c22 100644 --- a/lib/puppet/provider/firewall/iptables.rb +++ b/lib/puppet/provider/firewall/iptables.rb @@ -108,7 +108,15 @@ :uid => "--uid-owner", :physdev_in => "--physdev-in", :physdev_out => "--physdev-out", - :physdev_is_bridged => "--physdev-is-bridged" + :physdev_is_bridged => "--physdev-is-bridged", + :date_start => "--datestart", + :date_stop => "--datestop", + :time_start => "--timestart", + :time_stop => "--timestop", + :month_days => "--monthdays", + :week_days => "--weekdays", + :time_contiguous => "--contiguous", + :kernel_timezone => "--kerneltz", } # These are known booleans that do not take a value, but we want to munge @@ -122,7 +130,9 @@ :rsource, :rttl, :socket, - :physdev_is_bridged + :physdev_is_bridged, + :time_contiguous, + :kernel_timezone, ] # Properties that use "-m " (with the potential to have multiple @@ -142,6 +152,7 @@ :addrtype => [:src_type, :dst_type], :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] } def self.munge_resource_map_from_existing_values(resource_map_original, compare) @@ -226,7 +237,7 @@ def munge_resource_map_from_resource(resource_map_original, compare) :state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix, :log_level, :reject, :set_mark, - :connlimit_above, :connlimit_mask, :connmark + :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone ] def insert diff --git a/lib/puppet/type/firewall.rb b/lib/puppet/type/firewall.rb index 65d3533e7..fc563b6fa 100644 --- a/lib/puppet/type/firewall.rb +++ b/lib/puppet/type/firewall.rb @@ -1102,6 +1102,101 @@ def insync?(is) newvalues(:true, :false) end + newproperty(:date_start, :required_features => :iptables) do + desc <<-EOS + Only match during the given time, which must be in ISO 8601 "T" notation. + The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 + EOS + end + + newproperty(:date_stop, :required_features => :iptables) do + desc <<-EOS + Only match during the given time, which must be in ISO 8601 "T" notation. + The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 + EOS + end + + newproperty(:time_start, :required_features => :iptables) do + desc <<-EOS + Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. + Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. + EOS + + munge do |value| + if value =~ /^([0-9]):/ + value = "0#{value}" + end + + if value =~ /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/ + value = "#{value}:00" + end + + value + end + end + + newproperty(:time_stop, :required_features => :iptables) do + desc <<-EOS + Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. + Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. + EOS + + munge do |value| + if value =~ /^([0-9]):/ + value = "0#{value}" + end + + if value =~ /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/ + value = "#{value}:00" + end + + value + end + end + + newproperty(:month_days, :required_features => :iptables) do + desc <<-EOS + Only match on the given days of the month. Possible values are 1 to 31. + Note that specifying 31 will of course not match on months which do not have a 31st day; + the same goes for 28- or 29-day February. + EOS + + validate do |value| + month = value.to_i + if month >= 1 and month <=31 + value + else + raise ArgumentError, + "month_days must be in the range of 1-31" + end + end + end + + newproperty(:week_days, :required_features => :iptables) do + desc <<-EOS + Only match on the given weekdays. Possible values are Mon, Tue, Wed, Thu, Fri, Sat, Sun. + EOS + + newvalues(:Mon, :Tue, :Wed, :Thu, :Fri, :Sat, :Sun) + end + + newproperty(:time_contiguous, :required_features => :iptables) do + desc <<-EOS + When time_stop is smaller than time_start value, match this as a single time period instead distinct intervals. + EOS + + newvalues(:true, :false) + end + + newproperty(:kernel_timezone, :required_features => :iptables) do + desc <<-EOS + Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations. + EOS + + newvalues(:true, :false) + end + + autorequire(:firewallchain) do reqs = [] protocol = nil diff --git a/spec/acceptance/firewall_time_spec.rb b/spec/acceptance/firewall_time_spec.rb new file mode 100644 index 000000000..589148e1f --- /dev/null +++ b/spec/acceptance/firewall_time_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper_acceptance' + +describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + + + before(:all) do + shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') + shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') + end + + if default['platform'] =~ /ubuntu-1404/ or default['platform'] =~ /debian-7/ or default['platform'] =~ /debian-8/ or default['platform'] =~ /el-7/ + describe "time tests ipv4" do + context 'set all time parameters' do + it 'applies' do + pp = <<-EOS + class { '::firewall': } + firewall { '805 - test': + proto => tcp, + dport => '8080', + action => accept, + chain => 'OUTPUT', + date_start => '2016-01-19T04:17:07', + date_stop => '2038-01-19T04:17:07', + time_start => '6:00', + time_stop => '17:00:00', + month_days => '7', + week_days => 'Tue', + kernel_timezone => 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 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/) + end + end + end + end + + describe "time tests ipv6" do + context 'set all time parameters' do + it 'applies' do + pp = <<-EOS + class { '::firewall': } + firewall { '805 - test': + proto => tcp, + dport => '8080', + action => accept, + chain => 'OUTPUT', + date_start => '2016-01-19T04:17:07', + date_stop => '2038-01-19T04:17:07', + time_start => '6:00', + time_stop => '17:00:00', + month_days => '7', + week_days => 'Tue', + kernel_timezone => true, + provider => 'ip6tables', + } + 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 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/) + end + end + end + end + end +end