508 changes: 508 additions & 0 deletions .rubocop.yml

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
#This file is generated by ModuleSync, do not edit.
---
sudo: false
language: ruby
cache: bundler
script: "bundle exec rake validate lint spec"
#Inserting below due to the following issue: https://github.com/travis-ci/travis-ci/issues/3531#issuecomment-88311203
before_install:
- gem update bundler
matrix:
fast_finish: true
include:
- rvm: 2.1.6
- rvm: 2.3.1
dist: trusty
env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/ubuntu-14.04 SPEC_OPTS="--tag docker"
script: bundle exec rake beaker
services: docker
sudo: required
- rvm: 2.1.6
- rvm: 2.3.1
dist: trusty
env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/centos-7 SPEC_OPTS=""--tag docker"
script: bundle exec rake beaker
services: docker
sudo: required
- rvm: 2.1.6
- rvm: 2.3.1
bundler_args: --without system_tests
env: PUPPET_GEM_VERSION="~> 4.0" STRICT_VARIABLES="yes"
env: PUPPET_GEM_VERSION="~> 4.0"
- rvm: 2.1.9
bundler_args: --without system_tests
env: PUPPET_GEM_VERSION="~> 4.0"
- rvm: 2.1.5
bundler_args: --without system_tests
env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes"
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## Supported Release 1.8.2
### Summary
This release includes numerous features and bugfixes, See below.

#### Bugfixes
- Fixing issue with double quotes being removed when part of the rule comment
- Add the --wait flag to the insert/update/delete iptables actions to prevent failures from occuring when iptables is running outside of puppet for iptables >= 1.4.20
- Fix iptables_version and ip6tables_version facts not returning the version

#### Features
- Support for multiple IP sets in a single rule
- Implement queue_bypass and queue_num parameters for NFQUEUE jump target
- Tighten SELinux permissions on persistent files
- RHEL7 SELinux support for puppet 3
- Manage ip6tables service for Redhat Family

## Supported Release 1.8.1
### Summary
This release documents an important issue with mcollective that may impact users of the firewall module. Workarounds are suggested as part of this advisory until mcollective can be patched.
Expand Down
6 changes: 2 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,9 @@ review.
Additional Resources
====================

* [Getting additional help](http://puppetlabs.com/community/get-help)
* [Getting additional help](http://puppet.com/community/get-help)

* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests)

* [Patchwork](https://patchwork.puppetlabs.com)
* [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing)

* [General GitHub documentation](http://help.github.com/)

Expand Down
101 changes: 70 additions & 31 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,48 +1,87 @@
#This file is generated by ModuleSync, do not edit.

source ENV['GEM_SOURCE'] || "https://rubygems.org"

def location_for(place, fake_version = nil)
if place =~ /^(git[:@][^#]*)#(.*)/
# Determines what type of gem is requested based on place_or_version.
def gem_type(place_or_version)
if place_or_version =~ /^git:/
:git
elsif place_or_version =~ /^file:/
:file
else
:gem
end
end

# Find a location or specific version for a gem. place_or_version can be a
# version, which is most often used. It can also be git, which is specified as
# `git://somewhere.git#branch`. You can also use a file source location, which
# is specified as `file://some/location/on/disk`.
def location_for(place_or_version, fake_version = nil)
if place_or_version =~ /^(git[:@][^#]*)#(.*)/
[fake_version, { :git => $1, :branch => $2, :require => false }].compact
elsif place =~ /^file:\/\/(.*)/
elsif place_or_version =~ /^file:\/\/(.*)/
['>= 0', { :path => File.expand_path($1), :require => false }]
else
[place, { :require => false }]
[place_or_version, { :require => false }]
end
end

group :development, :unit_tests do
gem 'json', :require => false
gem 'metadata-json-lint', :require => false
gem 'puppet_facts', :require => false
gem 'puppet-blacksmith', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'rspec-puppet', '>= 2.3.2', :require => false
gem 'simplecov', :require => false
# Used for gem conditionals
supports_windows = false

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.1', :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')
end

group :system_tests do
gem 'beaker-puppet_install_helper', :require => false
if beaker_version = ENV['BEAKER_VERSION']
gem 'beaker', *location_for(beaker_version)
end
if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION']
gem 'beaker-rspec', *location_for(beaker_rspec_version)
else
gem 'beaker-rspec', :require => false
end
gem 'master_manipulator', :require => false
gem 'serverspec', :require => false
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20') if supports_windows
gem 'beaker', *location_for(ENV['BEAKER_VERSION']) if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0') and ! supports_windows
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '< 3') if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0') and ! supports_windows
gem 'beaker-pe', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')
gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'] || '>= 3.4') if ! supports_windows
gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'] || '~> 5.1') if supports_windows
gem 'beaker-puppet_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')
end

if facterversion = ENV['FACTER_GEM_VERSION']
gem 'facter', facterversion, :require => false
else
gem 'facter', :require => false
gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION'])

# Only explicitly specify Facter/Hiera if a version has been specified.
# Otherwise it can lead to strange bundler behavior. If you are seeing weird
# gem resolution behavior, try setting `DEBUG_RESOLVER` environment variable
# to `1` and then run bundle install.
gem 'facter', *location_for(ENV['FACTER_GEM_VERSION']) if ENV['FACTER_GEM_VERSION']
gem 'hiera', *location_for(ENV['HIERA_GEM_VERSION']) if ENV['HIERA_GEM_VERSION']


# Evaluate Gemfile.local if it exists
if File.exists? "#{__FILE__}.local"
eval(File.read("#{__FILE__}.local"), binding)
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
# Evaluate ~/.gemfile if it exists
if File.exists?(File.join(Dir.home, '.gemfile'))
eval(File.read(File.join(Dir.home, '.gemfile')), binding)
end

# vim:ft=ruby
213 changes: 195 additions & 18 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,25 +1,202 @@
Puppet Firewall Module - Puppet module for managing Firewalls

Copyright (C) 2011-2013 Puppet Labs, Inc.
Copyright (C) 2011 Jonathan Boyett
Copyright (C) 2011 Media Temple, Inc.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

Some of the iptables code was taken from puppet-iptables which was:
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

Copyright (C) 2011 Bob.sh Limited
Copyright (C) 2008 Camptocamp Association
Copyright (C) 2007 Dmitri Priimak
1. Definitions.

Puppet Labs can be contacted at: info@puppetlabs.com
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

http://www.apache.org/licenses/LICENSE-2.0
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
26 changes: 26 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
firewall puppet module

Copyright (C) 2011-2016 Puppet Labs, Inc.
Copyright (C) 2011 Jonathan Boyett
Copyright (C) 2011 Media Temple, Inc.

Some of the iptables code was taken from puppet-iptables which was:

Copyright (C) 2011 Bob.sh Limited
Copyright (C) 2008 Camptocamp Association
Copyright (C) 2007 Dmitri Priimak

Puppet Labs can be contacted at: info@puppetlabs.com


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
54 changes: 39 additions & 15 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Therefore, the run order is:

The rules in the `pre` and `post` classes are fairly general. These two classes ensure that you retain connectivity and that you drop unmatched packets appropriately. The rules you define in your manifests are likely specific to the applications you run.

1.) Add the `pre` class to my_fw/manifests/pre.pp. Your pre.pp file should contain any default rules to be applied first. The rules in this class should be added in the order you want them to run.2.
1.) Add the `pre` class to my_fw/manifests/pre.pp. Your pre.pp file should contain any default rules to be applied first. The rules in this class should be added in the order you want them to run.2.
~~~puppet
class my_fw::pre {
Firewall {
Expand Down Expand Up @@ -145,7 +145,7 @@ Rules are persisted automatically between reboots, although there are known issu
purge => true,
}
~~~

**Note** - If there are unmanaged rules in unmanaged chains, it will take two Puppet runs before the firewall chain is purged. This is different than the `purge` parameter available in `firewallchain`.

2.) Use the following code to set up the default parameters for all of the firewall rules you will establish later. These defaults will ensure that the `pre` and `post` classes are run in the correct order to avoid locking you out of your box during the first Puppet run.
Expand Down Expand Up @@ -216,7 +216,7 @@ IPv6 rules can be specified using the _ip6tables_ provider:

~~~puppet
firewall { '006 Allow inbound SSH (v6)':
dport => 22,
dport => 22,
proto => tcp,
action => accept,
provider => 'ip6tables',
Expand All @@ -240,7 +240,7 @@ class profile::apache {
apache::vhost { 'mysite': ensure => present }
firewall { '100 allow http and https access':
dport => [80, 443],
dport => [80, 443],
proto => tcp,
action => accept,
}
Expand Down Expand Up @@ -387,19 +387,23 @@ Parameter that controls the state of the iptables service on your system, allowi

`ensure` can either be 'running' or 'stopped'. Defaults to 'running'.

#### package

Specify the platform-specific package(s) to install. Defaults defined in `firewall::params`.

#### pkg_ensure

Parameter that controls the state of the iptables package on your system, allowing you to update it if you wish.

`ensure` can either be 'present' or 'latest'. Defaults to 'present'.

#### service
#### service_name

Specify the name of the IPv4 iptables service. Defaults defined in `firewall::params`.

Specify the platform-specific service(s) to start or stop. Defaults defined in `firewall::params`.
#### service_name_v6

Specify the name of the IPv6 ip6tables service. Defaults defined in `firewall::params`.

#### package_name

Specify the platform-specific package(s) to install. Defaults defined in `firewall::params`.

###Type: firewall

Expand All @@ -410,12 +414,12 @@ This type enables you to manage firewall rules within Puppet.

* `ip6tables`: Ip6tables type provider
* Required binaries: `ip6tables-save`, `ip6tables`.
* Supported features: `address_type`, `connection_limiting`, `dnat`, `hop_limiting`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfirstfrag`, `ishasmorefrags`, `islastfrag`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `tcp_flags`.
* Supported features: `address_type`, `connection_limiting`, `dnat`, `hop_limiting`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfirstfrag`, `ishasmorefrags`, `islastfrag`, `length`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `owner`, `pkttype`, `queue_bypass`, `queue_num`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `string_matching`, `tcp_flags`.

* `iptables`: Iptables type provider
* Required binaries: `iptables-save`, `iptables`.
* Default for `kernel` == `linux`.
* Supported features: `address_type`, `clusterip`, `connection_limiting`, `dnat`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfragment`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `netmap`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `tcp_flags`.
* Supported features: `address_type`, `clusterip`, `connection_limiting`, `dnat`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfragment`, `length`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `netmap`, `owner`, `pkttype`, `queue_bypass`, `queue_num`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `string_matching`, `tcp_flags`.

**Autorequires:**

Expand Down Expand Up @@ -455,6 +459,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `islastfrag`: The ability to match the last fragment of an ipv6 packet.

* `length`: The ability to match the length of the layer-3 payload.

* `log_level`: The ability to control the log level.

* `log_prefix`: The ability to add prefixes to log messages.
Expand Down Expand Up @@ -483,6 +489,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `state_match`: The ability to match stateful firewall states.

* `string_matching`: The ability to match a given string by using some pattern matching strategy.

* `tcp_flags`: The ability to match on particular TCP flag settings.

* `netmap`: The ability to map entire subnets via source or destination nat rules.
Expand Down Expand Up @@ -572,7 +580,7 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `ipsec_policy`: Sets the ipsec policy type. Valid values are 'none', 'ipsec'. Requires the `ipsec_policy` feature.

* `ipset`: Matches IP sets. Value must be 'ipset_name (src|dst|src,dst)' and can be negated by putting ! in front. Requires ipset kernel module.
* `ipset`: Matches IP sets. Value must be 'ipset_name (src|dst|src,dst)' and can be negated by putting ! in front. Requires ipset kernel module. Will accept a single element or an array.

* `isfirstfrag`: If true, matches when the packet is the first fragment of a fragmented ipv6 packet. Cannot be negated. Supported by ipv6 only. Valid values are 'true', 'false'. Requires the `isfirstfrag` feature.

Expand All @@ -590,6 +598,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `kernel_timezone`: Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations.

* `length`: Set the value for matching the length of the layer-3 payload. Can be a single number or a range using '-' as a separator. Requires the `length` feature.

* `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.
Expand Down Expand Up @@ -634,6 +644,7 @@ firewall { '999 this runs last':
* `port`: *DEPRECATED* Using the unspecific 'port' parameter can lead to firewall rules that are unexpectedly too lax. It is recommended to always use the specific dport and sport parameters to avoid this ambiguity. The destination or source port to match for this filter (if the protocol supports ports). Will accept a single element or an array. 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.

* `proto`: The specific protocol to match for this rule. This is 'tcp' by default. Valid values are:
* 'ip'
* 'tcp'
* 'udp'
* 'icmp'
Expand All @@ -647,11 +658,16 @@ firewall { '999 this runs last':
* 'ipencap'
* 'ospf'
* 'gre'
* 'pim'
* 'all'

* `provider`: The specific backend to use for this firewall resource. You will seldom need to specify this --- Puppet will usually discover the appropriate provider for your platform. Available providers are ip6tables and iptables. See the [Providers](#providers) section above for details about these providers.

* `random`: When using a `jump` value of 'MASQUERADE', 'DNAT', 'REDIRECT', or 'SNAT', this boolean will enable randomized port mapping. Valid values are true or false. Requires the `dnat` feature.
* `queue_bypass`: When using a `jump` value of 'NFQUEUE' this boolean will allow packets to bypass `queue_num`. This is useful when the process in userspace may not be listening on `queue_num` all the time.

* `queue_num`: When using a `jump` value of 'NFQUEUE' this parameter specifies the queue number to send packets to.

* `random`: When using a `jump` value of 'MASQUERADE', 'DNAT', 'REDIRECT', or 'SNAT', this boolean will enable randomized port mapping. Valid values are true or false. Requires the `dnat` feature.

* `rdest`: If boolean 'true', adds the destination IP address to the list. Valid values are true or false. Requires the `recent_limiting` feature and the `recent` parameter.

Expand Down Expand Up @@ -741,6 +757,14 @@ firewall { '101 blacklist strange traffic':

* `state`: Matches a packet based on its state in the firewall stateful inspection table. Valid values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED'. Requires the `state_match` feature.

* `string`: Set the pattern for string matching. Requires the `string_matching` feature.

* `string_algo`: Used in conjunction with `string`, select the pattern matching strategy. Valid values are: 'bm', 'kmp' (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris). Requires the `string_matching` feature.

* `string_from`: Used in conjunction with `string`, set the offset from which it starts looking for any matching. Requires the `string_matching` feature.

* `string_to`: Used in conjunction with `string`, set the offset up to which should be scanned. Requires the `string_matching` feature.

* `table`: Table to use. Valid values are: 'nat', 'mangle', 'filter', 'raw', 'rawpost'. By default the setting is 'filter'. Requires the `iptables` feature.

* `tcp_flags`: Match when the TCP flags are as specified. Set as a string with a list of comma-separated flag names for the mask, then a space, then a comma-separated list of flags that should be set. The flags are: 'SYN', 'ACK', 'FIN', 'RST', 'URG', 'PSH', 'ALL', 'NONE'.
Expand Down Expand Up @@ -861,7 +885,7 @@ As Puppet Enterprise itself does not yet support Debian 8, use of this module wi
system should be regarded as experimental.

### Known Issues

#### MCollective causes PE to reverse firewall rule order

Firewall rules appear in reverse order if you use MCollective to run Puppet in Puppet Enterprise 2016.1, 2015.3, 2015.2, or 3.8.x.
Expand Down
35 changes: 31 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,37 @@ require 'puppet_blacksmith/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'puppetlabs_spec_helper/rake_tasks'

PuppetLint.configuration.fail_on_warnings = true
PuppetLint.configuration.send('relative')
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_documentation')
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]

desc 'Generate pooler nodesets'
task :gen_nodeset do
require 'beaker-hostgenerator'
require 'securerandom'
require 'fileutils'

agent_target = ENV['TEST_TARGET']
if ! agent_target
STDERR.puts 'TEST_TARGET environment variable is not set'
STDERR.puts 'setting to default value of "redhat-64default."'
agent_target = 'redhat-64default.'
end

master_target = ENV['MASTER_TEST_TARGET']
if ! master_target
STDERR.puts 'MASTER_TEST_TARGET environment variable is not set'
STDERR.puts 'setting to default value of "redhat7-64mdcl"'
master_target = 'redhat7-64mdcl'
end

targets = "#{master_target}-#{agent_target}"
cli = BeakerHostGenerator::CLI.new([targets])
nodeset_dir = "tmp/nodesets"
nodeset = "#{nodeset_dir}/#{targets}-#{SecureRandom.uuid}.yaml"
FileUtils.mkdir_p(nodeset_dir)
File.open(nodeset, 'w') do |fh|
fh.print(cli.execute)
end
puts nodeset
end
2 changes: 1 addition & 1 deletion lib/facter/ip6tables_version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Facter.add(:ip6tables_version) do
confine :kernel => :linux
confine :kernel => :Linux
setcode do
version = Facter::Util::Resolution.exec('ip6tables --version')
if version
Expand Down
2 changes: 1 addition & 1 deletion lib/facter/iptables_version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Facter.add(:iptables_version) do
confine :kernel => :linux
confine :kernel => :Linux
setcode do
version = Facter::Util::Resolution.exec('iptables --version')
if version
Expand Down
19 changes: 16 additions & 3 deletions lib/puppet/provider/firewall/ip6tables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
has_feature :ipsec_policy
has_feature :mask
has_feature :ipset
has_feature :length
has_feature :string_matching
has_feature :queue_num
has_feature :queue_bypass

optional_commands({
:ip6tables => 'ip6tables',
Expand Down Expand Up @@ -89,6 +93,7 @@ def self.iptables_save(*args)
: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",
Expand All @@ -102,6 +107,8 @@ def self.iptables_save(*args)
: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",
Expand All @@ -125,6 +132,10 @@ def self.iptables_save(*args)
: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",
Expand Down Expand Up @@ -161,6 +172,7 @@ def self.iptables_save(*args)
:physdev_is_bridged,
:time_contiguous,
:kernel_timezone,
:queue_bypass,
]

# Properties that use "-m <ipt module name>" (with the potential to have multiple
Expand Down Expand Up @@ -221,9 +233,10 @@ def self.iptables_save(*args)
:physdev_out, :physdev_is_bridged, :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,
:ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :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,
: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]

end
68 changes: 56 additions & 12 deletions lib/puppet/provider/firewall/iptables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
has_feature :mask
has_feature :ipset
has_feature :clusterip
has_feature :length
has_feature :string_matching
has_feature :queue_num
has_feature :queue_bypass

optional_commands({
:iptables => 'iptables',
Expand Down Expand Up @@ -73,6 +77,8 @@
: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",
Expand All @@ -86,6 +92,8 @@
: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",
Expand All @@ -110,6 +118,10 @@
: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",
Expand Down Expand Up @@ -153,9 +165,10 @@
:time_contiguous,
:kernel_timezone,
:clusterip_new,
:queue_bypass,
]

# Properties that use "-m <ipt module name>" (with the potential to have multiple
# 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.
Expand Down Expand Up @@ -254,9 +267,10 @@ def munge_resource_map_from_resource(resource_map_original, compare)
: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,
:state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :clusterip_new, :clusterip_hashmode,
:clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init,
: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,
:clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init, :queue_num, :queue_bypass,
:clamp_mss_to_pmtu, :gateway, :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
Expand Down Expand Up @@ -338,11 +352,19 @@ def self.rule_to_hash(line, table, counter)
# PRE-PARSE CLUDGING
####################

# The match for ttl
values = values.gsub(/(!\s+)?-m ttl (!\s+)?--ttl-(eq|lt|gt) [0-9]+/, '')
# --tcp-flags takes two values; we cheat by adding " around it
# so it behaves like --comment
values = values.gsub(/(!\s+)?--tcp-flags (\S*) (\S*)/, '--tcp-flags "\1\2 \3"')
# ditto for --match-set
values = values.sub(/(!\s+)?--match-set (\S*) (\S*)/, '--match-set "\1\2 \3"')
# --match-set can have multiple values with weird iptables format
if values =~ /-m set --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*)/)
values = values.gsub(/-m set --match-set (!\s+)?\S* \S* /, '')
values.insert(ind, "-m set --match-set \"#{sets.join(';')}\" ")
end
# we do a similar thing for negated address masks (source and destination).
values = values.gsub(/(-\S+) (!)\s?(\S*)/,'\1 "\2 \3"')
# the actual rule will have the ! mark before the option.
Expand Down Expand Up @@ -434,8 +456,10 @@ def self.rule_to_hash(line, table, counter)
[:dport, :sport, :port, :state, :ctstate].each do |prop|
hash[prop] = hash[prop].split(',') if ! hash[prop].nil?
end

## clean up DSCP class to HEX mappings

hash[:ipset] = hash[:ipset].split(';') if ! hash[:ipset].nil?

## clean up DSCP class to HEX mappings
valid_dscp_classes = {
'0x0a' => 'af11',
'0x0c' => 'af12',
Expand Down Expand Up @@ -484,6 +508,9 @@ def self.rule_to_hash(line, table, counter)
elem.gsub(/:/,'-')
end
end
if hash[:length]
hash[:length].gsub!(/:/,'-')
end

# Invert any rules that are prefixed with a '!'
[
Expand All @@ -493,7 +520,6 @@ def self.rule_to_hash(line, table, counter)
:dport,
:dst_range,
:dst_type,
:ipset,
:port,
:proto,
:source,
Expand Down Expand Up @@ -587,7 +613,7 @@ def update_args

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

Expand All @@ -602,6 +628,14 @@ def general_args
resource_map = self.class.instance_variable_get('@resource_map')
resource_map = munge_resource_map_from_resource(resource_map, resource)

# Always attempt to wait for a lock for iptables to prevent failures when
# puppet is running at the same time something else is managing the rules
# note: --wait wasn't added untip iptables version 1.4.20
iptables_version = Facter.value('iptables_version')
if (iptables_version && Puppet::Util::Package.versioncmp(iptables_version, '1.4.20') >= 0)
args << ['--wait']
end

resource_list.each do |res|
resource_value = nil
if (resource[res]) then
Expand Down Expand Up @@ -635,7 +669,7 @@ def general_args
#ruby 1.8.7 can't .match Symbols ------------------ ^
resource_value = resource_value.to_s.sub!(/^!\s*/, '').to_sym
args.insert(-2, '!')
elsif resource_value.is_a?(Array)
elsif resource_value.is_a?(Array) and res != :ipset
should_negate = resource_value.index do |value|
#ruby 1.8.7 can't .match symbols
value.to_s.match(/^(!)\s+/)
Expand Down Expand Up @@ -666,10 +700,20 @@ def general_args
end
end

# ipset can accept multiple values with weird iptables arguments
if res == :ipset
resource_value.join(" #{[resource_map[res]].flatten.first} ").split(' ').each do |a|
if a.sub!(/^!\s*/, '')
# Negate ipset options
args.insert(-2, '!')
end

args << a if a.length > 0
end
# our tcp_flags takes a single string with comma lists separated
# by space
# --tcp-flags expects two arguments
if res == :tcp_flags or res == :ipset
elsif res == :tcp_flags
one, two = resource_value.split(' ')
args << one
args << two
Expand Down
157 changes: 152 additions & 5 deletions lib/puppet/type/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
feature :mask, "Ability to match recent rules based on the ipv4 mask"
feature :ipset, "Match against specified ipset list"
feature :clusterip, "Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them."
feature :length, "Match the length of layer-3 payload"
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"

# provider specific features
feature :iptables, "The provider provides iptables features."
Expand Down Expand Up @@ -369,12 +373,12 @@ def should_to_s(value)
*tcp*.
EOS

newvalues(*[:tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :cbt, :sctp, :all].collect do |proto|
newvalues(*[:ip, :tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :cbt, :sctp, :pim, :all].collect do |proto|
[proto, "! #{proto}".to_sym]
end.flatten)
defaultto "tcp"
end

# tcp-specific
newproperty(:mss) do
desc <<-EOS
Expand Down Expand Up @@ -476,6 +480,40 @@ def should_to_s(value)
end
end

newproperty(:goto, :required_features => :iptables) do
desc <<-EOS
The value for the iptables --goto parameter. Normal values are:
* QUEUE
* RETURN
* DNAT
* SNAT
* LOG
* MASQUERADE
* REDIRECT
* MARK
But any valid chain name is allowed.
EOS

validate do |value|
unless value =~ /^[a-zA-Z0-9\-_]+$/
raise ArgumentError, <<-EOS
Goto destination must consist of alphanumeric characters, an
underscore or a yphen.
EOS
end

if ["accept","reject","drop"].include?(value.downcase)
raise ArgumentError, <<-EOS
Goto destination should not be one of ACCEPT, REJECT or DROP. Use
the action property instead.
EOS
end

end
end

# Interface specific matching properties
newproperty(:iniface, :required_features => :interface_match) do
desc <<-EOS
Expand Down Expand Up @@ -894,7 +932,7 @@ def insync?(is)
Set DSCP Markings.
EOS
end

newproperty(:set_dscp_class, :required_features => :iptables) do
desc <<-EOS
This sets the DSCP field according to a predefined DiffServ class.
Expand Down Expand Up @@ -1154,14 +1192,23 @@ def insync?(is)
EOS
end

newproperty(:ipset, :required_features => :ipset) do
newproperty(:ipset, :required_features => :ipset, :array_matching => :all) do
desc <<-EOS
Matches against the specified ipset list.
Requires ipset kernel module.
Requires ipset kernel module. Will accept a single element or an array.
The value is the name of the blacklist, followed by a space, and then
'src' and/or 'dst' separated by a comma.
For example: 'blacklist src,dst'
EOS

def is_to_s(value)
should_to_s(value)
end

def should_to_s(value)
value = [value] unless value.is_a?(Array)
value.join(', ')
end
end

newproperty(:checksum_fill, :required_features => :iptables) do
Expand Down Expand Up @@ -1352,6 +1399,92 @@ def insync?(is)
EOS
end

newproperty(:length, :required_features => :length) do
desc <<-EOS
Sets the length of layer-3 payload to match.
EOS

munge do |value|
match = value.to_s.match("^([0-9]+)(-)?([0-9]+)?$")
if match.nil?
raise ArgumentError, "Length value must either be an integer or a range"
end

low = match[1].to_i
if !match[3].nil?
high = match[3].to_i
end

if (low < 0 or low > 65535) or \
(!high.nil? and (high < 0 or high > 65535 or high < low))
raise ArgumentError, "Length values must be between 0 and 65535"
end

value = low.to_s
if !high.nil?
value << ":" << high.to_s
end
value
end
end

newproperty(:string, :required_features => :string_matching) do
desc <<-EOS
String matching feature. Matches the packet against the pattern
given as an argument.
EOS

munge do |value|
value = "'" + value + "'"
end
end

newproperty(:string_algo, :required_features => :string_matching) do
desc <<-EOS
String matching feature, pattern matching strategy.
EOS

newvalues(:bm, :kmp)
end

newproperty(:string_from, :required_features => :string_matching) do
desc <<-EOS
String matching feature, offset from which we start looking for any matching.
EOS
end

newproperty(:string_to, :required_features => :string_matching) do
desc <<-EOS
String matching feature, offset up to which we should scan.
EOS
end

newproperty(:queue_num, :required_features => :queue_num) do
desc <<-EOS
Used with NFQUEUE jump target.
What queue number to send packets to
EOS
munge do |value|
match = value.to_s.match("^([0-9])*$")
if match.nil?
raise ArgumentError, "queue_num must be an integer"
end

if match[1].to_i > 65535 || match[1].to_i < 0
raise ArgumentError, "queue_num must be between 0 and 65535"
end
value
end
end

newproperty(:queue_bypass, :required_features => :queue_bypass) do
desc <<-EOS
Used with NFQUEUE jump target
Allow packets to bypass :queue_num if userspace process is not listening
EOS
newvalues(:true, :false)
end


autorequire(:firewallchain) do
reqs = []
Expand Down Expand Up @@ -1394,6 +1527,14 @@ def insync?(is)
end
end

# autobefore is only provided since puppet 4.0
if Puppet.version.to_f >= 4.0
# On RHEL 7 this needs to be threaded correctly to manage SE Linux permissions after persisting the rules
autobefore(:file) do
[ '/etc/sysconfig/iptables', '/etc/sysconfig/ip6tables' ]
end
end

validate do
debug("[validate]")

Expand Down Expand Up @@ -1544,5 +1685,11 @@ def insync?(is)
end
end

if value(:queue_num) || value(:queue_bypass)
unless value(:jump).to_s == "NFQUEUE"
self.fail "Paramter queue_number and queue_bypass require jump => NFQUEUE"
end
end

end
end
4 changes: 2 additions & 2 deletions lib/puppet/util/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def persist_iptables(proto)
# Basic normalisation for older Facter
os_key = Facter.value(:osfamily)
os_key ||= case Facter.value(:operatingsystem)
when 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer'
when 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer', 'VirtuozzoLinux'
'RedHat'
when 'Debian', 'Ubuntu'
'Debian'
Expand All @@ -175,7 +175,7 @@ def persist_iptables(proto)
end

# RHEL 7 and newer also use systemd to persist iptable rules
if os_key == 'RedHat' && ['RedHat','CentOS','Scientific','SL','SLC','Ascendos','CloudLinux','PSBM','OracleLinux','OVS','OEL','XenServer'].include?(Facter.value(:operatingsystem)) && Facter.value(:operatingsystemrelease).to_i >= 7
if os_key == 'RedHat' && ['RedHat','CentOS','Scientific','SL','SLC','Ascendos','CloudLinux','PSBM','OracleLinux','OVS','OEL','XenServer','VirtuozzoLinux'].include?(Facter.value(:operatingsystem)) && Facter.value(:operatingsystemrelease).to_i >= 7
os_key = 'Fedora'
end

Expand Down
21 changes: 13 additions & 8 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
# Default: running
#
class firewall (
$ensure = running,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$package_name = $::firewall::params::package_name,
$ensure = running,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$service_name_v6 = $::firewall::params::service_name_v6,
$package_name = $::firewall::params::package_name,
) inherits ::firewall::params {
case $ensure {
/^(running|stopped)$/: {
Expand All @@ -29,11 +30,15 @@
case $::kernel {
'Linux': {
class { "${title}::linux":
ensure => $ensure,
pkg_ensure => $pkg_ensure,
service_name => $service_name,
package_name => $package_name,
ensure => $ensure,
pkg_ensure => $pkg_ensure,
service_name => $service_name,
service_name_v6 => $service_name_v6,
package_name => $package_name,
}
contain "${title}::linux"
}
'FreeBSD': {
}
default: {
fail("${title}: Kernel '${::kernel}' is not currently supported")
Expand Down
23 changes: 13 additions & 10 deletions manifests/linux.pp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
# Default: running
#
class firewall::linux (
$ensure = running,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$package_name = $::firewall::params::package_name,
$ensure = running,
$pkg_ensure = present,
$service_name = $::firewall::params::service_name,
$service_name_v6 = $::firewall::params::service_name_v6,
$package_name = $::firewall::params::package_name,
) inherits ::firewall::params {
$enable = $ensure ? {
running => true,
Expand All @@ -28,13 +29,15 @@

case $::operatingsystem {
'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos',
'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer': {
'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer',
'VirtuozzoLinux': {
class { "${title}::redhat":
ensure => $ensure,
enable => $enable,
package_name => $package_name,
service_name => $service_name,
require => Package['iptables'],
ensure => $ensure,
enable => $enable,
package_name => $package_name,
service_name => $service_name,
service_name_v6 => $service_name_v6,
require => Package['iptables'],
}
}
'Debian', 'Ubuntu': {
Expand Down
84 changes: 60 additions & 24 deletions manifests/linux/redhat.pp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@
# Default: true
#
class firewall::linux::redhat (
$ensure = running,
$enable = true,
$service_name = $::firewall::params::service_name,
$package_name = $::firewall::params::package_name,
$package_ensure = $::firewall::params::package_ensure,
$ensure = running,
$enable = true,
$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 {

# RHEL 7 and later and Fedora 15 and later require the iptables-services
# 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
# lib/puppet/util/firewall.rb.
if ($::operatingsystem != 'Amazon')
and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
or ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
or ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
service { 'firewalld':
ensure => stopped,
enable => false,
Expand All @@ -41,13 +42,13 @@
}

if ($::operatingsystem != 'Amazon')
and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
or ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
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],
unless => "/usr/bin/systemctl is-active ${service_name}",
before => Service[$service_name, $service_name_v6],
unless => "/usr/bin/systemctl is-active ${service_name} ${service_name_v6}",
}
}
}
Expand All @@ -56,27 +57,62 @@
ensure => $ensure,
enable => $enable,
hasstatus => true,
require => File["/etc/sysconfig/${service_name}"],
}
service { $service_name_v6:
ensure => $ensure,
enable => $enable,
hasstatus => true,
}

file { "/etc/sysconfig/${service_name}":
ensure => present,
owner => 'root',
group => 'root',
mode => '0600',
}
file { "/etc/sysconfig/${service_name_v6}":
ensure => present,
owner => 'root',
group => 'root',
mode => '0600',
}

# Before puppet 4, the autobefore on the firewall type does not work - therefore
# we need to keep this workaround here
if versioncmp($::puppetversion, '4.0') <= 0 {
File["/etc/sysconfig/${service_name}"] -> Service[$service_name]
File["/etc/sysconfig/${service_name_v6}"] -> Service[$service_name_v6]
}

# Redhat 7 selinux user context for /etc/sysconfig/iptables is set to unconfined_u
# Redhat 7 selinux type context for /etc/sysconfig/iptables is set to etc_t
case $::selinux {
#lint:ignore:quoted_booleans
'true',true: {
case $::operatingsystemrelease {
/^(6|7)\..*/: { $seluser = 'unconfined_u' }
default: { $seluser = 'system_u' }
/^7\..*/: {
case $::operatingsystem {
'CentOS': {
File["/etc/sysconfig/${service_name}"] { seluser => 'unconfined_u', seltype => 'system_conf_t' }
File["/etc/sysconfig/${service_name_v6}"] { seluser => 'unconfined_u', seltype => 'system_conf_t' }
}
default : {
File["/etc/sysconfig/${service_name}"] { seluser => 'unconfined_u', seltype => 'etc_t' }
File["/etc/sysconfig/${service_name_v6}"] { seluser => 'unconfined_u', seltype => 'etc_t' }
}
}
}
/^6\..*/: {
File["/etc/sysconfig/${service_name}"] { seluser => 'unconfined_u', seltype => 'system_conf_t' }
File["/etc/sysconfig/${service_name_v6}"] { seluser => 'unconfined_u', seltype => 'system_conf_t' }
}
default: {
File["/etc/sysconfig/${service_name}"] { seluser => 'system_u', seltype => 'system_conf_t' }
File["/etc/sysconfig/${service_name_v6}"] { seluser => 'unconfined_u', seltype => 'system_conf_t' }
}
}
}
default: {}
#lint:endignore
default: { $seluser = undef }
}

file { "/etc/sysconfig/${service_name}":
ensure => present,
owner => 'root',
group => 'root',
mode => '0600',
seluser => $seluser,
}
}
8 changes: 5 additions & 3 deletions manifests/params.pp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
$package_ensure = 'present'
case $::osfamily {
'RedHat': {
$service_name = 'iptables'
$service_name_v6 = 'ip6tables'
case $::operatingsystem {
'Amazon': {
$service_name = 'iptables'
$package_name = undef
}
'Fedora': {
Expand All @@ -13,19 +14,18 @@
} else {
$package_name = undef
}
$service_name = 'iptables'
}
default: {
if versioncmp($::operatingsystemrelease, '7.0') >= 0 {
$package_name = 'iptables-services'
} else {
$package_name = 'iptables-ipv6'
}
$service_name = 'iptables'
}
}
}
'Debian': {
$service_name_v6 = undef
case $::operatingsystem {
'Debian': {
if versioncmp($::operatingsystemrelease, '8.0') >= 0 {
Expand Down Expand Up @@ -55,9 +55,11 @@
}
'Gentoo': {
$service_name = ['iptables','ip6tables']
$service_name_v6 = undef
$package_name = 'net-firewall/iptables'
}
default: {
$service_name_v6 = undef
case $::operatingsystem {
'Archlinux': {
$service_name = ['iptables','ip6tables']
Expand Down
13 changes: 5 additions & 8 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "puppetlabs-firewall",
"version": "1.8.1",
"version": "1.8.2",
"author": "Puppet Labs",
"summary": "Manages Firewalls such as iptables",
"license": "Apache-2.0",
Expand Down Expand Up @@ -59,7 +59,8 @@
"operatingsystemrelease": [
"10.04",
"12.04",
"14.04"
"14.04",
"16.04"
]
},
{
Expand All @@ -70,16 +71,12 @@
}
],
"requirements": [
{
"name": "pe",
"version_requirement": ">= 3.0.0 < 2015.4.0"
},
{
"name": "puppet",
"version_requirement": ">= 3.0.0 < 5.0.0"
"version_requirement": ">= 3.5.0 < 5.0.0"
}
],
"dependencies": [

]
}
19 changes: 13 additions & 6 deletions spec/acceptance/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1531,24 +1531,31 @@ class { '::firewall': }
require => Package['ipset'],
}
class { '::firewall': }
exec { 'create ipset':
exec { 'create ipset blacklist':
command => 'ipset create blacklist hash:ip,port family inet6 maxelem 1024 hashsize 65535 timeout 120',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
require => Package['ipset'],
}
exec { 'add blacklist':
-> exec { 'create ipset honeypot':
command => 'ipset create honeypot hash:ip family inet6 maxelem 1024 hashsize 65535 timeout 120',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
}
-> exec { 'add blacklist':
command => 'ipset add blacklist 2001:db8::1,80',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
require => Exec['create ipset'],
}
-> exec { 'add honeypot':
command => 'ipset add honeypot 2001:db8::5',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
}
firewall { '612 - test':
ensure => present,
chain => 'INPUT',
proto => tcp,
action => drop,
ipset => 'blacklist src,src',
ipset => ['blacklist src,dst', '! honeypot dst'],
provider => 'ip6tables',
require => Exec['add blacklist'],
require => Exec['add honeypot'],
}
EOS

Expand All @@ -1557,7 +1564,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,src -j DROP/)
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/)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/acceptance/nodesets/centos-7-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ HOSTS:
roles:
- agent
- default
platform: redhat-7-x86_64
platform: el-7-x86_64
hypervisor: vagrant
box: puppetlabs/centos-7.2-64-nocm
CONFIG:
Expand Down
28 changes: 28 additions & 0 deletions spec/acceptance/nodesets/new/aio/ubuntu-1604-64mda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
HOSTS:
ubuntu-1604-agent:
roles:
- agent
- default
platform: ubuntu-16.04-amd64
template: Delivery/Quality Assurance/Templates/vCloud/ubuntu-1604-x86_64
hypervisor: vcloud
redhat-7-x86_64-master:
roles:
- master
- dashboard
- database
- agent
platform: el-7-x86_64
template: redhat-7-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
type: aio
ssh:
timeout: 600
27 changes: 27 additions & 0 deletions spec/acceptance/nodesets/new/pe/oracle-5-64mda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
HOSTS:
oracle-5-x86_64-agent:
roles:
- agent
- default
platform: el-5-x86_64
template: oracle-5-x86_64
hypervisor: vcloud
redhat-7-x86_64-master:
roles:
- master
- dashboard
- database
- agent
platform: el-7-x86_64
template: redhat-7-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
ssh:
timeout: 600
27 changes: 27 additions & 0 deletions spec/acceptance/nodesets/new/pe/ubuntu-1604-64mda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
HOSTS:
ubuntu-1604-agent:
roles:
- agent
- default
platform: ubuntu-16.04-amd64
template: Delivery/Quality Assurance/Templates/vCloud/ubuntu-1604-x86_64
hypervisor: vcloud
redhat-7-x86_64-master:
roles:
- master
- dashboard
- database
- agent
platform: el-7-x86_64
template: redhat-7-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
ssh:
timeout: 600
15 changes: 15 additions & 0 deletions spec/acceptance/resource_cmd_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@
end
end

context 'accepts rules with -m ttl' do
before :all do
iptables_flush_all_tables
shell('iptables -t nat -A OUTPUT -s 10.0.0.0/8 -p tcp -m ttl ! --ttl-eq 42 -j REDIRECT --to-ports 12299')
end

it do
shell('puppet resource firewall') do |r|
r.exit_code.should be_zero
# don't check stdout, testing preexisting rules, output is normal
r.stderr.should be_empty
end
end
end

# version of iptables that ships with el5 doesn't work with the
# ip6tables provider
if default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/
Expand Down
160 changes: 159 additions & 1 deletion spec/fixtures/iptables/conversion_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@
:action => nil,
},
},
'jump_goto' => {
:line => '-A w--instance-cfmhvrgpmq6 -g w--default',
:table => 'filter',
:params => {
:goto => "w--default",
:action => nil,
},

},
'source_destination_ipv4_no_cidr' => {
:line => '-A INPUT -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 source destination ipv4 no cidr"',
:table => 'filter',
Expand Down Expand Up @@ -581,6 +590,79 @@
:chain => 'foo-filter',
},
},
'length_1' => {
:line => '-A INPUT -m length --length 42000',
:table => 'filter',
:params => {
:length => '42000',
},
},
'length_2' => {
:line => '-A INPUT -m length --length 1492:65535',
:table => 'filter',
:params => {
:length => '1492-65535',
},
},
'string_matching_1' => {
:line => '-A INPUT -m string --string "GET /index.html"',
:table => 'filter',
:params => {
:string => 'GET /index.html',
},
},
'string_matching_2' => {
:line => '-A INPUT -m string --string "GET /index.html" --algo bm',
:table => 'filter',
:params => {
:string => 'GET /index.html',
:string_algo => 'bm',
},
},
'string_matching_3' => {
:line => '-A INPUT -m string --string "GET /index.html" --from 1',
:table => 'filter',
:params => {
:string => 'GET /index.html',
:string_from => '1',
},
},
'nfqueue_jump1' => {
:line => '-A INPUT -m tcp -p tcp -s 1.2.3.4/32 -d 4.3.2.1/32 -m comment --comment "000 nfqueue specify queue_num" -j NFQUEUE --queue-num 50',
:table => 'filter',
:params => {
:name => "000 nfqueue specify queue_num",
:source => "1.2.3.4/32",
:destination => "4.3.2.1/32",
:jump => "NFQUEUE",
:queue_num => "50",
:proto => "tcp",
},
},
'nfqueue_jump2' => {
:line => '-A INPUT -m tcp -p tcp -s 1.2.3.4/32 -d 4.3.2.1/32 -m comment --comment "002 nfqueue specify queue_num and queue_bypass" -j NFQUEUE --queue-num 50 --queue-bypass',
:table => "filter",
:params => {
:name => "002 nfqueue specify queue_num and queue_bypass",
:source => "1.2.3.4/32",
:destination => "4.3.2.1/32",
:jump => "NFQUEUE",
:queue_num => "50",
:queue_bypass => true,
:proto => "tcp",
},
},
'nfqueue_jump3' => {
:line => '-A INPUT -m tcp -p tcp -s 1.2.3.4/32 -d 4.3.2.1/32 -m comment --comment "003 nfqueue dont specify queue_num or queue_bypass" -j NFQUEUE',
:table => "filter",
:params => {
:name => "003 nfqueue dont specify queue_num or queue_bypass",
:source => "1.2.3.4/32",
:destination => "4.3.2.1/32",
:jump => "NFQUEUE",
:proto => "tcp",
},
},
}

# This hash is for testing converting a hash to an argument line.
Expand Down Expand Up @@ -1117,4 +1199,80 @@
},
:args => ["-t", :mangle, "-p", :tcp, "-m", "multiport", '--ports', '997', "-m", "comment", "--comment", "068 set dscp class to EF", "-j", "DSCP", "--set-dscp-class", "ef"],
},
}
'length_1' => {
:params => {
:name => '000 length',
:table => 'filter',
:length => '42000',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 length", "-m", "length", "--length", "42000"],
},
'length_2' => {
:params => {
:name => '000 length',
:table => 'filter',
:length => '1492-65535',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 length", "-m", "length", "--length", "1492:65535"],
},
'string_matching_1' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'"],
},
'string_matching_2' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
:string_algo => 'bm',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'", "--algo", :bm],
},
'string_matching_3' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
:string_from => '1',
:string_to => '65535',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'", "--from", "1", "--to", "65535"],
},
'nfqueue_jump1' => {
:params => {
:name => '000 nfqueue specify queue_num',
:table => 'filter',
:jump => 'NFQUEUE',
:source => "1.2.3.4/32",
:destination => "4.3.2.1/32",
:queue_num => "50",
},
:args => ["-t", :filter, "-s", "1.2.3.4/32", "-d", "4.3.2.1/32", "-p", :tcp, "-m", "comment", "--comment", "000 nfqueue specify queue_num", "-j", "NFQUEUE", "--queue-num", "50"]
},
'nfqueue_jump2' => {
:params => {
:name => '002 nfqueue specify queue_num and queue_bypass',
:table => 'filter',
:jump => "NFQUEUE",
:source => '1.2.3.4/32',
:destination => '4.3.2.1/32',
:queue_num => "50",
:queue_bypass => true,
},
:args => ["-t", :filter, "-s", "1.2.3.4/32", "-d", "4.3.2.1/32", "-p", :tcp, "-m", "comment", "--comment", "002 nfqueue specify queue_num and queue_bypass", "-j", "NFQUEUE", "--queue-num", "50", "--queue-bypass"]
},
'nfqueue_jump3' => {
:params => {
:name => '003 nfqueue dont specify queue_num or queue_bypass',
:table => 'filter',
:jump => "NFQUEUE",
:source => '1.2.3.4/32',
:destination => '4.3.2.1/32',
},
:args => ["-t", :filter, "-s", "1.2.3.4/32", "-d", "4.3.2.1/32", "-p", :tcp, "-m", "comment", "--comment", "003 nfqueue dont specify queue_num or queue_bypass", "-j", "NFQUEUE"]
}
}
6 changes: 0 additions & 6 deletions spec/spec.opts

This file was deleted.

9 changes: 9 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
#This file is generated by ModuleSync, do not edit.
require 'puppetlabs_spec_helper/module_spec_helper'

if Puppet.version.to_f >= 4.5
RSpec.configure do |c|
c.before :each do
Puppet.settings[:strict] = :error
end
end
end

# put local configuration and setup into spec_helper_local
begin
require 'spec_helper_local'
Expand Down
31 changes: 31 additions & 0 deletions spec/unit/classes/firewall_linux_redhat_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
:operatingsystemrelease => osrel,
:osfamily => 'RedHat',
:selinux => false,
:puppetversion => Puppet.version,
}}

it { should_not contain_service('firewalld') }
Expand All @@ -51,8 +52,38 @@
:operatingsystemrelease => osrel,
:osfamily => 'RedHat',
:selinux => false,
:puppetversion => Puppet.version,
}}

it { should contain_service('iptables').with(
:ensure => 'running',
:enable => 'true'
)}
it { should contain_service('ip6tables').with(
:ensure => 'running',
:enable => 'true'
)}

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

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

it { should contain_service('firewalld').with(
:ensure => 'stopped',
:enable => false,
Expand Down
2 changes: 2 additions & 0 deletions spec/unit/classes/firewall_linux_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
:operatingsystemrelease => osrel,
:osfamily => 'RedHat',
:selinux => false,
:puppetversion => Puppet.version,
}}
it { should contain_class('firewall::linux::redhat').with_require('Package[iptables]') }
it { should contain_package('iptables').with_ensure('present') }
Expand All @@ -33,6 +34,7 @@
:operatingsystemrelease => osrel,
:osfamily => 'Debian',
:selinux => false,
:puppetversion => Puppet.version,
}}

it { should contain_class('firewall::linux::debian').with_require('Package[iptables]') }
Expand Down
15 changes: 6 additions & 9 deletions spec/unit/facter/iptables_persistent_version_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(ver)
}
it { Facter.fact(:iptables_persistent_version).value.should == ver }
it { expect(Facter.fact(:iptables_persistent_version).value).to eql ver }
end
end

Expand All @@ -37,13 +37,13 @@
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(nil)
}
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil }
end

describe 'CentOS not supported' do
before { allow(Facter.fact(:operatingsystem)).to receive(:value).
and_return("CentOS") }
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil }
end

end
Expand Down Expand Up @@ -71,7 +71,7 @@
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(ver)
}
it { Facter.fact(:iptables_persistent_version).value.should == ver }
it { expect(Facter.fact(:iptables_persistent_version).value).to eql ver }
end
end

Expand All @@ -83,18 +83,15 @@
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
and_return(nil)
}
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil }
end

describe 'CentOS not supported' do
before { allow(Facter.fact(:operatingsystem)).to receive(:value).
and_return("CentOS") }
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil }
end

end




end
4 changes: 2 additions & 2 deletions spec/unit/facter/iptables_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
it {
allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version').
and_return('iptables v1.4.7')
Facter.fact(:iptables_version).value.should == '1.4.7'
expect(Facter.fact(:iptables_version).value).to eql '1.4.7'
}
end

describe 'ip6tables_version' do
before { allow(Facter::Util::Resolution).to receive(:exec).
with('ip6tables --version').and_return('ip6tables v1.4.7') }
it { Facter.fact(:ip6tables_version).value.should == '1.4.7' }
it { expect(Facter.fact(:ip6tables_version).value).to eql '1.4.7' }
end
end
25 changes: 12 additions & 13 deletions spec/unit/puppet/provider/iptables_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
end

it "should default to iptables provider if /sbin/iptables[-save] exists" do
it "is expected to default to iptables provider if /sbin/iptables[-save] exists" do
# Stub lookup for /sbin/iptables & /sbin/iptables-save
allow(exists).to receive(:which).with("iptables").
and_return "/sbin/iptables"
allow(exists).to receive(:which).with("iptables-save").
and_return "/sbin/iptables-save"

# Every other command should return false so we don't pick up any
# Every other command is expected to return false so we don't pick up any
# other providers
allow(exists).to receive(:which) { |value|
! ["iptables","iptables-save"].include?(value)
Expand Down Expand Up @@ -69,14 +69,14 @@
and_return "/sbin/iptables-save"
end

it 'should be able to get a list of existing rules' do
it 'is expected to be able to get a list of existing rules' do
provider.instances.each do |rule|
expect(rule).to be_instance_of(provider)
expect(rule.properties[:provider].to_s).to eq(provider.name.to_s)
end
end

it 'should ignore lines with fatal errors' do
it 'is expected to ignore lines with fatal errors' do
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/iptables-save']).
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")

Expand Down Expand Up @@ -379,17 +379,17 @@
and_return "/sbin/ip6tables-save"
end

it 'should be able to get a list of existing rules' do
it 'is expected to be able to get a list of existing rules' do
provider6.instances.each do |rule|
rule.should be_instance_of(provider6)
rule.properties[:provider6].to_s.should == provider6.name.to_s
expect(rule).to be_instance_of(provider6)
expect(rule.properties[:provider6].to_s).to eql provider6.name.to_s
end
end

it 'should ignore lines with fatal errors' do
it 'is expected to ignore lines with fatal errors' do
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/ip6tables-save']).
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
provider6.instances.length.should == 0
expect(provider6.instances.length).to eq 0
end

# Load in ruby hash for test fixtures.
Expand All @@ -403,14 +403,14 @@
# If this option is enabled, make sure the parameters exactly match
if data[:compare_all] then
it "the parameter hash keys should be the same as returned by rules_to_hash" do
resource.keys.should =~ data[:params].keys
expect(resource.keys).to match data[:params].keys
end
end

# Iterate across each parameter, creating an example for comparison
data[:params].each do |param_name, param_value|
it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
resource[param_name].should == data[:params][param_name]
expect(resource[param_name]).to eql data[:params][param_name]
end
end
end
Expand All @@ -425,10 +425,9 @@
let(:instance) { provider6.new(resource) }

it 'general_args should be valid' do
instance.general_args.flatten.should == data[:args]
expect(instance.general_args.flatten).to eql data[:args]
end
end
end
end
end

202 changes: 101 additions & 101 deletions spec/unit/puppet/type/firewall_spec.rb

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions spec/unit/puppet/type/firewallchain_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}

it 'should have :name be its namevar' do
klass.key_attributes.should == [:name]
expect(klass.key_attributes).to eql [:name]
end

describe ':name' do
Expand All @@ -40,7 +40,7 @@
it "should accept #{name} for Linux 3.7+" do
allow(Facter.fact(:kernelmajversion)).to receive(:value).and_return('3.7')
resource[:name] = name
resource[:name].should == name
expect(resource[:name]).to eql name
end
it "should fail #{name} for Linux 2.6" do
allow(Facter.fact(:kernelmajversion)).to receive(:value).and_return('2.6')
Expand All @@ -53,7 +53,7 @@
else
it "should accept name #{name}" do
resource[:name] = name
resource[:name].should == name
expect(resource[:name]).to eql name
end
end
end # chainname
Expand All @@ -71,7 +71,7 @@
if allowedinternalchains.include? internalchain
it "should allow #{name}" do
resource[:name] = name
resource[:name].should == name
expect(resource[:name]).to eql name
end
else
it "should fail #{name}" do
Expand All @@ -97,7 +97,7 @@
[:accept, :drop, :queue, :return].each do |policy|
it "should accept policy #{policy}" do
resource[:policy] = policy
resource[:policy].should == policy
expect(resource[:policy]).to eql policy
end
end

Expand All @@ -118,18 +118,18 @@

describe 'autorequire packages' do
it "provider iptables_chain should autorequire package iptables" do
resource[:provider].should == :iptables_chain
expect(resource[:provider]).to eql :iptables_chain
package = Puppet::Type.type(:package).new(:name => 'iptables')
catalog = Puppet::Resource::Catalog.new
catalog.add_resource resource
catalog.add_resource package
rel = resource.autorequire[0]
rel.source.ref.should == package.ref
rel.target.ref.should == resource.ref
expect(rel.source.ref).to eql package.ref
expect(rel.target.ref).to eql resource.ref
end

it "provider iptables_chain should autorequire packages iptables, iptables-persistent, and iptables-services" do
resource[:provider].should == :iptables_chain
expect(resource[:provider]).to eql :iptables_chain
packages = [
Puppet::Type.type(:package).new(:name => 'iptables'),
Puppet::Type.type(:package).new(:name => 'iptables-persistent'),
Expand All @@ -141,8 +141,8 @@
catalog.add_resource package
end
packages.zip(resource.autorequire) do |package, rel|
rel.source.ref.should == package.ref
rel.target.ref.should == resource.ref
expect(rel.source.ref).to eql package.ref
expect(rel.target.ref).to eql resource.ref
end
end
end
Expand Down
134 changes: 67 additions & 67 deletions spec/unit/puppet/util/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,37 @@

describe '#host_to_ip' do
subject { resource }
specify {
it {
expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51')
subject.host_to_ip('puppetlabs.com').should == '96.126.112.51/32'
expect(subject.host_to_ip('puppetlabs.com')).to eql '96.126.112.51/32'
}
specify { subject.host_to_ip('96.126.112.51').should == '96.126.112.51/32' }
specify { subject.host_to_ip('96.126.112.51/32').should == '96.126.112.51/32' }
specify { subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_ip('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
specify { subject.host_to_ip('0.0.0.0/0').should == nil }
specify { subject.host_to_ip('::/0').should == nil }
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' }
it { expect(subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334')).to eql '2001:db8:85a3::8a2e:370:7334/128' }
it { expect(subject.host_to_ip('2001:db8:1234::/48')).to eql '2001:db8:1234::/48' }
it { expect(subject.host_to_ip('0.0.0.0/0')).to eql nil }
it { expect(subject.host_to_ip('::/0')).to eql nil }
end

describe '#host_to_mask' do
subject { resource }
specify {
it {
expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51')
subject.host_to_mask('puppetlabs.com').should == '96.126.112.51/32'
subject.host_to_mask('!puppetlabs.com').should == '! 96.126.112.51/32'
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'
}
specify { subject.host_to_mask('96.126.112.51').should == '96.126.112.51/32' }
specify { subject.host_to_mask('!96.126.112.51').should == '! 96.126.112.51/32' }
specify { subject.host_to_mask('96.126.112.51/32').should == '96.126.112.51/32' }
specify { subject.host_to_mask('! 96.126.112.51/32').should == '! 96.126.112.51/32' }
specify { subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334').should == '! 2001:db8:85a3::8a2e:370:7334/128' }
specify { subject.host_to_mask('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
specify { subject.host_to_mask('! 2001:db8:1234::/48').should == '! 2001:db8:1234::/48' }
specify { subject.host_to_mask('0.0.0.0/0').should == nil }
specify { subject.host_to_mask('!0.0.0.0/0').should == nil }
specify { subject.host_to_mask('::/0').should == nil }
specify { subject.host_to_mask('! ::/0').should == nil }
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 }
end

describe '#icmp_name_to_number' do
Expand All @@ -61,54 +61,54 @@
describe 'proto IPv4' do
proto = 'inet'
subject { resource }
specify { subject.icmp_name_to_number('echo-reply', proto).should == '0' }
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '3' }
specify { subject.icmp_name_to_number('source-quench', proto).should == '4' }
specify { subject.icmp_name_to_number('redirect', proto).should == '6' }
specify { subject.icmp_name_to_number('echo-request', proto).should == '8' }
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '9' }
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '10' }
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '11' }
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '12' }
specify { subject.icmp_name_to_number('timestamp-request', proto).should == '13' }
specify { subject.icmp_name_to_number('timestamp-reply', proto).should == '14' }
specify { subject.icmp_name_to_number('address-mask-request', proto).should == '17' }
specify { subject.icmp_name_to_number('address-mask-reply', proto).should == '18' }
it { expect(subject.icmp_name_to_number('echo-reply', proto)).to eql '0' }
it { expect(subject.icmp_name_to_number('destination-unreachable', proto)).to eql '3' }
it { expect(subject.icmp_name_to_number('source-quench', proto)).to eql '4' }
it { expect(subject.icmp_name_to_number('redirect', proto)).to eql '6' }
it { expect(subject.icmp_name_to_number('echo-request', proto)).to eql '8' }
it { expect(subject.icmp_name_to_number('router-advertisement', proto)).to eql '9' }
it { expect(subject.icmp_name_to_number('router-solicitation', proto)).to eql '10' }
it { expect(subject.icmp_name_to_number('time-exceeded', proto)).to eql '11' }
it { expect(subject.icmp_name_to_number('parameter-problem', proto)).to eql '12' }
it { expect(subject.icmp_name_to_number('timestamp-request', proto)).to eql '13' }
it { expect(subject.icmp_name_to_number('timestamp-reply', proto)).to eql '14' }
it { expect(subject.icmp_name_to_number('address-mask-request', proto)).to eql '17' }
it { expect(subject.icmp_name_to_number('address-mask-reply', proto)).to eql '18' }
end

describe 'proto IPv6' do
proto = 'inet6'
subject { resource }
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '1' }
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '3' }
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '4' }
specify { subject.icmp_name_to_number('echo-request', proto).should == '128' }
specify { subject.icmp_name_to_number('echo-reply', proto).should == '129' }
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '133' }
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '134' }
specify { subject.icmp_name_to_number('neighbour-solicitation', proto).should == '135' }
specify { subject.icmp_name_to_number('neighbour-advertisement', proto).should == '136' }
specify { subject.icmp_name_to_number('redirect', proto).should == '137' }
it { expect(subject.icmp_name_to_number('destination-unreachable', proto)).to eql '1' }
it { expect(subject.icmp_name_to_number('time-exceeded', proto)).to eql '3' }
it { expect(subject.icmp_name_to_number('parameter-problem', proto)).to eql '4' }
it { expect(subject.icmp_name_to_number('echo-request', proto)).to eql '128' }
it { expect(subject.icmp_name_to_number('echo-reply', proto)).to eql '129' }
it { expect(subject.icmp_name_to_number('router-solicitation', proto)).to eql '133' }
it { expect(subject.icmp_name_to_number('router-advertisement', proto)).to eql '134' }
it { expect(subject.icmp_name_to_number('neighbour-solicitation', proto)).to eql '135' }
it { expect(subject.icmp_name_to_number('neighbour-advertisement', proto)).to eql '136' }
it { expect(subject.icmp_name_to_number('redirect', proto)).to eql '137' }
end
end

describe '#string_to_port' do
subject { resource }
specify { subject.string_to_port('80','tcp').should == '80' }
specify { subject.string_to_port(80,'tcp').should == '80' }
specify { subject.string_to_port('http','tcp').should == '80' }
specify { subject.string_to_port('domain','udp').should == '53' }
it { expect(subject.string_to_port('80','tcp')).to eql '80' }
it { expect(subject.string_to_port(80,'tcp')).to eql '80' }
it { expect(subject.string_to_port('http','tcp')).to eql '80' }
it { expect(subject.string_to_port('domain','udp')).to eql '53' }
end

describe '#to_hex32' do
subject { resource }
specify { subject.to_hex32('0').should == '0x0' }
specify { subject.to_hex32('0x32').should == '0x32' }
specify { subject.to_hex32('42').should == '0x2a' }
specify { subject.to_hex32('4294967295').should == '0xffffffff' }
specify { subject.to_hex32('4294967296').should == nil }
specify { subject.to_hex32('-1').should == nil }
specify { subject.to_hex32('bananas').should == nil }
it { expect(subject.to_hex32('0')).to eql '0x0' }
it { expect(subject.to_hex32('0x32')).to eql '0x32' }
it { expect(subject.to_hex32('42')).to eql '0x2a' }
it { expect(subject.to_hex32('4294967295')).to eql '0xffffffff' }
it { expect(subject.to_hex32('4294967296')).to eql nil }
it { expect(subject.to_hex32('-1')).to eql nil }
it { expect(subject.to_hex32('bananas')).to eql nil }
end

describe '#persist_iptables' do
Expand All @@ -118,7 +118,7 @@
describe 'when proto is IPv4' do
let(:proto) { 'IPv4' }

it 'should exec /sbin/service if running RHEL 6 or earlier' do
it 'is expected to exec /sbin/service if running RHEL 6 or earlier' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
Expand All @@ -127,7 +127,7 @@
subject.persist_iptables(proto)
end

it 'should exec for systemd if running RHEL 7 or greater' do
it 'is expected to exec for systemd if running RHEL 7 or greater' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7')
Expand All @@ -136,7 +136,7 @@
subject.persist_iptables(proto)
end

it 'should exec for systemd if running Fedora 15 or greater' do
it 'is expected to exec for systemd if running Fedora 15 or greater' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Fedora')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('15')
Expand All @@ -145,29 +145,29 @@
subject.persist_iptables(proto)
end

it 'should exec for CentOS 6 identified from operatingsystem and operatingsystemrelease' do
it 'is expected to exec for CentOS 6 identified from operatingsystem and operatingsystemrelease' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6.5')
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
subject.persist_iptables(proto)
end

it 'should exec for CentOS 7 identified from operatingsystem and operatingsystemrelease' do
it 'is expected to exec for CentOS 7 identified from operatingsystem and operatingsystemrelease' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7.0.1406')
expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
subject.persist_iptables(proto)
end

it 'should exec for Archlinux identified from osfamily' do
it 'is expected to exec for Archlinux identified from osfamily' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Archlinux')
expect(subject).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules'])
subject.persist_iptables(proto)
end

it 'should raise a warning when exec fails' do
it 'is expected to raise a warning when exec fails' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
Expand All @@ -182,23 +182,23 @@
describe 'when proto is IPv6' do
let(:proto) { 'IPv6' }

it 'should exec for newer Ubuntu' do
it 'is expected to exec for newer Ubuntu' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.5.3ubuntu2')
expect(subject).to receive(:execute).with(%w{/usr/sbin/service iptables-persistent save})
subject.persist_iptables(proto)
end

it 'should not exec for older Ubuntu which does not support IPv6' do
it 'is expected to not exec for older Ubuntu which does not support IPv6' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.0.20090701')
expect(subject).to receive(:execute).never
subject.persist_iptables(proto)
end

it 'should not exec for Suse which is not supported' do
it 'is expected to not exec for Suse which is not supported' do
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse')
expect(subject).to receive(:execute).never
subject.persist_iptables(proto)
Expand Down
Loading