puppetlabs-firewall-1.12.00040755005276200011600000000000013232340576012473 5ustar00puppetlabs-firewall-1.12.0/CHANGELOG.md0100644005276200011600000006155113232340436014363 0ustar00# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). ## Supported Release 1.12.0 ### Summary This release uses the PDK convert functionality which in return makes the module PDK compliant. It also includes a roll up of maintenance changes. #### Added - PDK convert firewall ([MODULES-6455](https://tickets.puppet.com/browse/MODULES-6455)). - Modulesync updates. ### Fixed - Set correct `seluser` for CentOS/RHEL 5.x ([MODULES-6092](https://tickets.puppet.com/browse/MODULES-6092)). - Fix error parsing rules with dashes in the chain name ([MODULES-6261](https://tickets.puppet.com/browse/MODULES-6261)). - Changes to address additional Rubocop failures. - (maint) Addressing puppet-lint doc warnings. ## Supported Release 1.11.0 ### Summary This release is to implement Rubocop changes within the module. #### Added - Rubocop has been implemented in the module. ### Changed - Module sync was updated. - Unparsable rules are now skipped with a warning. ## Supported Release 1.10.0 ### Summary This is a clean release prior to the module being run through rubocop. #### Added - Hashlimit module added. - Firewall multi notes added. - Gidd lookup now added. - Simple sanity check added to hash parser rule. ### Changed - Version requirement has been updated. - An array is no lnger accepted for icmp types. - UNTRACKED is now considered to be a valid state. - Modulesync updates. - ip6tables can be disabled. - Readme format has been fixed. - Fixes made to accomodate Puppet lint. - Fix to regex i 'connlimit_spec.rb' and 'firewall_spec.rb'. - General test fixes. - Negated match sets know properly dealt with. - Correct IP version for hostname resolution now chosen. - Unmanaged rule regex regarding iptable has been fixed. ### Removed - Ubuntu 10.04 and 12.04 removed. ## Supported Release 1.9.0 ### Summary This release includes several bugfixes and NFLOG support. #### Added - Support for NFLOG including the `NFLOG` jump target and four commandline options ([FM-4896](https://tickets.puppetlabs.com/browse/FM-4896)) - Support for the geoip module ([MODULES-4279](https://tickets.puppetlabs.com/browse/MODULES-4279)) - Management of the ebtables package #### Fixed - iptables parser fails with "Invalid address from IPAddr.new: -m" ([MODULES-4234](https://tickets.puppetlabs.com/browse/MODULES-4234)) - selinux context for iptables configuration - Replace Puppet.version.to_f with Puppet::Util::Package.versioncmp ( [MODULES-4528](https://tickets.puppetlabs.com/browse/MODULES-4528)) ## 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. #### Bugfixes - Add mcollective rule-reversal known limitation ## Supported Release 1.8.0 ### Summary This release includes numerous features, bugfixes and other improvements including better handling when trying to delete already absent rules. #### Features - Added new 'pkg_ensure' parameter to allow the updating of the iptables package. - Added new 'log_uid' property. - Added 'sctp' to the 'proto' property. - Added support for IPv6 NAT in Linux kernels >= 3.7. - Added support for the security table. #### Bugfixes - (MODULES-2783) Replaced hardcoded iptables service references with $service_name variable. - (MODULES-1341) Recover when deleting absent rules. - (MODULES-3032) Facter flush is called to clear Facter cache get up to date value for ':iptables_persistent_version'. - (MODULES-2159) Fixed idempotency issue when using connlimit. - Fixed the handling of chain names that contain '-f'. #### Improvements - Numerous unit and acceptance test improvements. - Improved handling/use of the '$::iptables_persistent_version' custom fact. - Better handling of operating systems that use SELinux. ## Supported Release 1.7.2 ### Summary Small release for support of newer PE versions. This increments the version of PE in the metadata.json file. ## 2015-08-25 - Supported Release 1.7.1 ### Summary This is a bugfix release to deprecate the port parameter. 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. #### Bugfixes - Deprecate the port parameter ## 2015-07-28 - Supported Release 1.7.0 ### Summary This release includes numerous features, bugfixes and other improvements including Puppet 4 & PE 2015.2 support as well as ClusterIP and DSCP jump target support. #### Features - Puppet 4 and PE 2015.2 official support - ClusterIP jump target (including options) now supported - DSCP jump target (including options) now supported - SLES 10 now compatible (but not supported) #### Bugfixes - (MODULES-1967) Parse escape sequences from iptables - (MODULES-1592) Allow src_type and dst_type prefixed with '!' to pass validation - (MODULES-2186) - iptables rules with -A in comment now supported - (MODULES-1976) Revise rule name validation for ruby 1.9 - Fix installation hang on Debian Jessie - Fix for physdev idempotency on EL5 #### Improvements - Documentation improvements - Enforce the seluser on selinux systems - All the relevent services are now autorequired by the firewall and firewallchain types - Replace Facter.fact().value() calls with Facter.value() to support Facter 3 ## 2015-05-19 - Supported Release 1.6.0 ### Summary This release includes support for TEE, MSS, the time ipt module, Debian 8 support, and a number of test fixes and other improvements. #### Features - Add TEE support - Add MSS support (including clamp-mss-to-pmtu support) - Add support for the time ipt module (-m time) - Add support for Debian 8 - Add support for ICMPv6 types 'neighbour-{solicitation,advertisement}' - Add support for ICMPv6 type 'too-big' - Add support for new 'match_mark' property - Added 'ipv4' and 'ipv6' options to 'proto' property #### Bugfixes - Fix for Systemd-based OSes where systemd needs restarted before being able to pick up new services (MODULES-1984) - Arch Linux package management fix ## 2015-03-31 - Supported Release 1.5.0 ### Summary This release includes physdev_is_bridged support, checksum_fill support, basic Gentoo compatibility, and a number of test fixes and improvements. #### Features - Add `physdev_is_bridged` support - Add `checksum_fill` support - Add basic Gentoo compatibility (unsupported) #### Bugfixes - Implementation for resource map munging to allow a single ipt module to be used multiple times in a single rule on older versions of iptables (MODULES-1808) - Test fixes ## 2015-01-27 - Supported Release 1.4.0 ### Summary This release includes physdev support, the ability to look up usernames from uuid, and a number of bugfixes #### Features - Add `netmap` feature - Add `physdev` support - Add ability to look up username from uuid (MODULES-753, MODULES-1688) #### Bugfixes - Sync iptables/ip6tables providers (MODULES-1612) - Fix package names for Amazon and Ubuntu 14.10 (MODULES-1029) - Fix overly aggressive gsub when `ensure => absent` (MODULES-1453) - Unable to parse `-m (tcp|udp)` rules (MODULES-1552) - Fix ip6tables provider when `iptables-ipv6` package isn't installed for EL6 (MODULES-633) - Test fixes ## 2014-12-16 - Supported Release 1.3.0 ### Summary This release includes a number of bugfixes and features, including fixing `tcp_flags` support, and added support for interface aliases, negation for iniface and outiface, and extra configurability for packages and service names. #### Features - Add support for interface aliases (eth0:0) (MODULES-1469) - Add negation for iniface, outiface (MODULES-1470) - Make package and service names configurable (MODULES-1309) #### Bugfixes - Fix test regexes for EL5 (MODULES-1565) - Fix `tcp_flags` support for ip6tables (MODULES-556) - Don't arbitrarily limit `set_mark` for certain chains ## 2014-11-04 - Supported Release 1.2.0 ### Summary This release has a number of new features and bugfixes, including rule inversion, future parser support, improved EL7 support, and the ability to purge ip6tables rules. #### Features - Documentation updates! - Test updates! - Add ipset support - Enable rule inversion - Future parser support - Improved support for EL7 - Support netfilter-persistent - Add support for statistics module - Add support for mac address source rules - Add cbt protocol #### Bugfixes - Incorrect use of `source => :iptables` in the ip6tables provider was making it impossible to purge ip6tables rules (MODULES-41) - Don't require `toports` when `jump => 'REDIRECT'` (MODULES-1086) - Don't limit which chains iniface and outiface parameters can be used in - Don't fail on rules added with ipsec/strongswan (MODULES-796) ## 2014-07-08 - Supported Release 1.1.3 ### Summary This is a supported release with test coverage enhancements. #### Bugfixes - Confine to supported kernels ## 2014-06-04 - Release 1.1.2 ### Summary This is a release of the code previously released as 1.1.1, with updated metadata. ## 2014-05-16 Release 1.1.1 ### Summary This release reverts the alphabetical ordering of 1.1.0. We found this caused a regression in the Openstack modules so in the interest of safety we have removed this for now. ## 2014-05-13 Release 1.1.0 ### Summary This release has a significant change from previous releases; we now apply the firewall resources alphabetically by default, removing the need to create pre and post classes just to enforce ordering. It only effects default ordering and further information can be found in the README about this. Please test this in development before rolling into production out of an abundance of caution. We've also added `mask` which is required for --recent in recent (no pun intended) versions of iptables, as well as connlimit and connmark. This release has been validated against Ubuntu 14.04 and RHEL7 and should be fully working on those platforms. #### Features - Apply firewall resources alphabetically. - Add support for connlimit and connmark. - Add `mask` as a parameter. (Used exclusively with the recent parameter). #### Bugfixes - Add systemd support for RHEL7. - Replace &&'s with the correct and in manifests. - Fix tests on Trusty and RHEL7 - Fix for Fedora Rawhide. - Fix boolean flag tests. - Fix DNAT->SNAT typo in an error message. #### Known Bugs * For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README. ## 2014-03-04 Supported Release 1.0.2 ### Summary This is a supported release. This release removes a testing symlink that can cause trouble on systems where /var is on a seperate filesystem from the modulepath. #### Features #### Bugfixes #### Known Bugs * For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README. ### Supported release - 2014-03-04 1.0.1 #### Summary An important bugfix was made to the offset calculation for unmanaged rules to handle rules with 9000+ in the name. #### Features #### Bugfixes - Offset calculations assumed unmanaged rules were numbered 9000+. - Gracefully fail to manage ip6tables on iptables 1.3.x #### Known Bugs * For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README. --- ### 1.0.0 - 2014-02-11 No changes, just renumbering to 1.0.0. --- ### 0.5.0 - 2014-02-10 ##### Summary: This is a bigger release that brings in "recent" connection limiting (think "port knocking"), firewall chain purging on a per-chain/per-table basis, and support for a few other use cases. This release also fixes a major bug which could cause modifications to the wrong rules when unmanaged rules are present. ##### New Features: * Add "recent" limiting via parameters `rdest`, `reap`, `recent`, `rhitcount`, `rname`, `rseconds`, `rsource`, and `rttl` * Add negation support for source and destination * Add per-chain/table purging support to `firewallchain` * IPv4 specific * Add random port forwarding support * Add ipsec policy matching via `ipsec_dir` and `ipsec_policy` * IPv6 specific * Add support for hop limiting via `hop_limit` parameter * Add fragmentation matchers via `ishasmorefrags`, `islastfrag`, and `isfirstfrag` * Add support for conntrack stateful firewall matching via `ctstate` ##### Bugfixes: - Boolean fixups allowing false values - Better detection of unmanaged rules - Fix multiport rule detection - Fix sport/dport rule detection - Make INPUT, OUTPUT, and FORWARD not autorequired for firewall chain filter - Allow INPUT with the nat table - Fix `src_range` & `dst_range` order detection - Documentation clarifications - Fixes to spec tests --------------------------------------- ### 0.4.2 - 2013-09-10 Another attempt to fix the packaging issue. We think we understand exactly what is failing and this should work properly for the first time. --------------------------------------- ### 0.4.1 - 2013-08-09 Bugfix release to fix a packaging issue that may have caused puppet module install commands to fail. --------------------------------------- ### 0.4.0 - 2013-07-11 This release adds support for address type, src/dest ip ranges, and adds additional testing and bugfixes. #### Features * Add `src_type` and `dst_type` attributes (Nick Stenning) * Add `src_range` and `dst_range` attributes (Lei Zhang) * Add SL and SLC operatingsystems as supported (Steve Traylen) #### Bugfixes * Fix parser for bursts other than 5 (Chris Rutter) * Fix parser for -f in --comment (Georg Koester) * Add doc headers to class files (Dan Carley) * Fix lint warnings/errors (Wolf Noble) --------------------------------------- ### 0.3.1 - 2013/6/10 This minor release provides some bugfixes and additional tests. #### Changes * Update tests for rspec-system-puppet 2 (Ken Barber) * Update rspec-system tests for rspec-system-puppet 1.5 (Ken Barber) * Ensure all services have 'hasstatus => true' for Puppet 2.6 (Ken Barber) * Accept pre-existing rule with invalid name (Joe Julian) * Swap log_prefix and log_level order to match the way it's saved (Ken Barber) * Fix log test to replicate bug #182 (Ken Barber) * Split argments while maintaining quoted strings (Joe Julian) * Add more log param tests (Ken Barber) * Add extra tests for logging parameters (Ken Barber) * Clarify OS support (Ken Barber) --------------------------------------- ### 0.3.0 - 2013/4/25 This release introduces support for Arch Linux and extends support for Fedora 15 and up. There are also lots of bugs fixed and improved testing to prevent regressions. ##### Changes * Fix error reporting for insane hostnames (Tomas Doran) * Support systemd on Fedora 15 and up (Eduardo Gutierrez) * Move examples to docs (Ken Barber) * Add support for Arch Linux platform (Ingmar Steen) * Add match rule for fragments (Georg Koester) * Fix boolean rules being recognized as changed (Georg Koester) * Same rules now get deleted (Anastasis Andronidis) * Socket params test (Ken Barber) * Ensure parameter can disable firewall (Marc Tardif) --------------------------------------- ### 0.2.1 - 2012/3/13 This maintenance release introduces the new README layout, and fixes a bug with iptables_persistent_version. ##### Changes * (GH-139) Throw away STDERR from dpkg-query in Fact * Update README to be consistent with module documentation template * Fix failing spec tests due to dpkg change in iptables_persistent_version --------------------------------------- ### 0.2.0 - 2012/3/3 This release introduces automatic persistence, removing the need for the previous manual dependency requirement for persistent the running rules to the OS persistence file. Previously you would have required the following in your site.pp (or some other global location): # Always persist firewall rules exec { 'persist-firewall': command => $operatingsystem ? { 'debian' => '/sbin/iptables-save > /etc/iptables/rules.v4', /(RedHat|CentOS)/ => '/sbin/iptables-save > /etc/sysconfig/iptables', }, refreshonly => true, } Firewall { notify => Exec['persist-firewall'], before => Class['my_fw::post'], require => Class['my_fw::pre'], } Firewallchain { notify => Exec['persist-firewall'], } resources { "firewall": purge => true } You only need: class { 'firewall': } Firewall { before => Class['my_fw::post'], require => Class['my_fw::pre'], } To install pre-requisites and to create dependencies on your pre & post rules. Consult the README for more information. ##### Changes * Firewall class manifests (Dan Carley) * Firewall and firewallchain persistence (Dan Carley) * (GH-134) Autorequire iptables related packages (Dan Carley) * Typo in #persist_iptables OS normalisation (Dan Carley) * Tests for #persist_iptables (Dan Carley) * (GH-129) Replace errant return in autoreq block (Dan Carley) --------------------------------------- ### 0.1.1 - 2012/2/28 This release primarily fixes changing parameters in 3.x ##### Changes * (GH-128) Change method_missing usage to define_method for 3.x compatibility * Update travis.yml gem specifications to actually test 2.6 * Change source in Gemfile to use a specific URL for Ruby 2.0.0 compatibility --------------------------------------- ### 0.1.0 - 2012/2/24 This release is somewhat belated, so no summary as there are far too many changes this time around. Hopefully we won't fall this far behind again :-). ##### Changes * Add support for MARK target and set-mark property (Johan Huysmans) * Fix broken call to super for ruby-1.9.2 in munge (Ken Barber) * simple fix of the error message for allowed values of the jump property (Daniel Black) * Adding OSPF(v3) protocol to puppetlabs-firewall (Arnoud Vermeer) * Display multi-value: port, sport, dport and state command seperated (Daniel Black) * Require jump=>LOG for log params (Daniel Black) * Reject and document icmp => "any" (Dan Carley) * add firewallchain type and iptables_chain provider (Daniel Black) * Various fixes for firewallchain resource (Ken Barber) * Modify firewallchain name to be chain:table:protocol (Ken Barber) * Fix allvalidchain iteration (Ken Barber) * Firewall autorequire Firewallchains (Dan Carley) * Tests and docstring for chain autorequire (Dan Carley) * Fix README so setup instructions actually work (Ken Barber) * Support vlan interfaces (interface containing ".") (Johan Huysmans) * Add tests for VLAN support for iniface/outiface (Ken Barber) * Add the table when deleting rules (Johan Huysmans) * Fix tests since we are now prefixing -t) * Changed 'jump' to 'action', commands to lower case (Jason Short) * Support interface names containing "+" (Simon Deziel) * Fix for when iptables-save spews out "FATAL" errors (Sharif Nassar) * Fix for incorrect limit command arguments for ip6tables provider (Michael Hsu) * Document Util::Firewall.host_to_ip (Dan Carley) * Nullify addresses with zero prefixlen (Dan Carley) * Add support for --tcp-flags (Thomas Vander Stichele) * Make tcp_flags support a feature (Ken Barber) * OUTPUT is a valid chain for the mangle table (Adam Gibbins) * Enable travis-ci support (Ken Barber) * Convert an existing test to CIDR (Dan Carley) * Normalise iptables-save to CIDR (Dan Carley) * be clearer about what distributions we support (Ken Barber) * add gre protocol to list of acceptable protocols (Jason Hancock) * Added pkttype property (Ashley Penney) * Fix mark to not repeat rules with iptables 1.4.1+ (Sharif Nassar) * Stub iptables_version for now so tests run on non-Linux hosts (Ken Barber) * Stub iptables facts for set_mark tests (Dan Carley) * Update formatting of README to meet Puppet Labs best practices (Will Hopper) * Support for ICMP6 type code resolutions (Dan Carley) * Insert order hash included chains from different tables (Ken Barber) * rspec 2.11 compatibility (Jonathan Boyett) * Add missing class declaration in README (sfozz) * array_matching is contraindicated (Sharif Nassar) * Convert port Fixnum into strings (Sharif Nassar) * Update test framework to the modern age (Ken Barber) * working with ip6tables support (wuwx) * Remove gemfile.lock and add to gitignore (William Van Hevelingen) * Update travis and gemfile to be like stdlib travis files (William Van Hevelingen) * Add support for -m socket option (Ken Barber) * Add support for single --sport and --dport parsing (Ken Barber) * Fix tests for Ruby 1.9.3 from 3e13bf3 (Dan Carley) * Mock Resolv.getaddress in #host_to_ip (Dan Carley) * Update docs for source and dest - they are not arrays (Ken Barber) --------------------------------------- ### 0.0.4 - 2011/12/05 This release adds two new parameters, 'uid' and 'gid'. As a part of the owner module, these params allow you to specify a uid, username, gid, or group got a match: firewall { '497 match uid': port => '123', proto => 'mangle', chain => 'OUTPUT', action => 'drop' uid => '123' } This release also adds value munging for the 'log_level', 'source', and 'destination' parameters. The 'source' and 'destination' now support hostnames: firewall { '498 accept from puppetlabs.com': port => '123', proto => 'tcp', source => 'puppetlabs.com', action => 'accept' } The 'log_level' parameter now supports using log level names, such as 'warn', 'debug', and 'panic': firewall { '499 logging': port => '123', proto => 'udp', log_level => 'debug', action => 'drop' } Additional changes include iptables and ip6tables version facts, general whitespace cleanup, and adding additional unit tests. ##### Changes * (#10957) add iptables_version and ip6tables_version facts * (#11093) Improve log_level property so it converts names to numbers * (#10723) Munge hostnames and IPs to IPs with CIDR * (#10718) Add owner-match support * (#10997) Add fixtures for ipencap * (#11034) Whitespace cleanup * (#10690) add port property support to ip6tables --------------------------------------- ### 0.0.3 - 2011/11/12 This release introduces a new parameter 'port' which allows you to set both source and destination ports for a match: firewall { "500 allow NTP requests": port => "123", proto => "udp", action => "accept", } We also have the limit parameter finally working: firewall { "500 limit HTTP requests": dport => 80, proto => tcp, limit => "60/sec", burst => 30, action => accept, } State ordering has been fixed now, and more characters are allowed in the namevar: * Alphabetical * Numbers * Punctuation * Whitespace ##### Changes * (#10693) Ensure -m limit is added for iptables when using 'limit' param * (#10690) Create new port property * (#10700) allow additional characters in comment string * (#9082) Sort iptables --state option values internally to keep it consistent across runs * (#10324) Remove extraneous whitespace from iptables rule line in spec tests --------------------------------------- ### 0.0.2 - 2011/10/26 This is largely a maintanence and cleanup release, but includes the ability to specify ranges of ports in the sport/dport parameter: firewall { "500 allow port range": dport => ["3000-3030","5000-5050"], sport => ["1024-65535"], action => "accept", } ##### Changes * (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppetmaster * (#10002) Change to dport and sport to handle ranges, and fix handling of name to name to port * (#10263) Fix tests on Puppet 2.6.x * (#10163) Cleanup some of the inline documentation and README file to align with general forge usage --------------------------------------- ### 0.0.1 - 2011/10/18 Initial release. ##### Changes * (#9362) Create action property and perform transformation for accept, drop, reject value for iptables jump parameter * (#10088) Provide a customised version of CONTRIBUTING.md * (#10026) Re-arrange provider and type spec files to align with Puppet * (#10026) Add aliases for test,specs,tests to Rakefile and provide -T as default * (#9439) fix parsing and deleting existing rules * (#9583) Fix provider detection for gentoo and unsupported linuxes for the iptables provider * (#9576) Stub provider so it works properly outside of Linux * (#9576) Align spec framework with Puppet core * and lots of other earlier development tasks ... puppetlabs-firewall-1.12.0/CONTRIBUTING.md0100644005276200011600000002306013202542071014770 0ustar00# Contributing to Puppet modules So you want to contribute to a Puppet module: Great! Below are some instructions to get you started doing that very thing while setting expectations around code quality as well as a few tips for making the process as easy as possible. ### Table of Contents 1. [Getting Started](#getting-started) 1. [Commit Checklist](#commit-checklist) 1. [Submission](#submission) 1. [More about commits](#more-about-commits) 1. [Testing](#testing) - [Running Tests](#running-tests) - [Writing Tests](#writing-tests) 1. [Get Help](#get-help) ## Getting Started - Fork the module repository on GitHub and clone to your workspace - Make your changes! ## Commit Checklist ### The Basics - [x] my commit is a single logical unit of work - [x] I have checked for unnecessary whitespace with "git diff --check" - [x] my commit does not include commented out code or unneeded files ### The Content - [x] my commit includes tests for the bug I fixed or feature I added - [x] my commit includes appropriate documentation changes if it is introducing a new feature or changing existing functionality - [x] my code passes existing test suites ### The Commit Message - [x] the first line of my commit message includes: - [x] an issue number (if applicable), e.g. "(MODULES-xxxx) This is the first line" - [x] a short description (50 characters is the soft limit, excluding ticket number(s)) - [x] the body of my commit message: - [x] is meaningful - [x] uses the imperative, present tense: "change", not "changed" or "changes" - [x] includes motivation for the change, and contrasts its implementation with the previous behavior ## Submission ### Pre-requisites - Make sure you have a [GitHub account](https://github.com/join) - [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for. ### Push and PR - Push your changes to your fork - [Open a Pull Request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) against the repository in the puppetlabs organization ## More about commits 1. Make separate commits for logically separate changes. Please break your commits down into logically consistent units which include new or changed tests relevant to the rest of the change. The goal of doing this is to make the diff easier to read for whoever is reviewing your code. In general, the easier your diff is to read, the more likely someone will be happy to review it and get it into the code base. If you are going to refactor a piece of code, please do so as a separate commit from your feature or bug fix changes. We also really appreciate changes that include tests to make sure the bug is not re-introduced, and that the feature is not accidentally broken. Describe the technical detail of the change(s). If your description starts to get too long, that is a good sign that you probably need to split up your commit into more finely grained pieces. Commits which plainly describe the things which help reviewers check the patch and future developers understand the code are much more likely to be merged in with a minimum of bike-shedding or requested changes. Ideally, the commit message would include information, and be in a form suitable for inclusion in the release notes for the version of Puppet that includes them. Please also check that you are not introducing any trailing whitespace or other "whitespace errors". You can do this by running "git diff --check" on your changes before you commit. 2. Sending your patches To submit your changes via a GitHub pull request, we _highly_ recommend that you have them on a topic branch, instead of directly on "master". It makes things much easier to keep track of, especially if you decide to work on another thing before your first change is merged in. GitHub has some pretty good [general documentation](http://help.github.com/) on using their site. They also have documentation on [creating pull requests](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). In general, after pushing your topic branch up to your repository on GitHub, you can switch to the branch in the GitHub UI and click "Pull Request" towards the top of the page in order to open a pull request. 3. Update the related JIRA issue. If there is a JIRA issue associated with the change you submitted, then you should update the ticket to include the location of your branch, along with any other commentary you may wish to make. # Testing ## Getting Started Our Puppet modules provide [`Gemfile`](./Gemfile)s, which can tell a Ruby package manager such as [bundler](http://bundler.io/) what Ruby packages, or Gems, are required to build, develop, and test this software. Please make sure you have [bundler installed](http://bundler.io/#getting-started) on your system, and then use it to install all dependencies needed for this project in the project root by running ```shell % bundle install --path .bundle/gems Fetching gem metadata from https://rubygems.org/........ Fetching gem metadata from https://rubygems.org/.. Using rake (10.1.0) Using builder (3.2.2) -- 8><-- many more --><8 -- Using rspec-system-puppet (2.2.0) Using serverspec (0.6.3) Using rspec-system-serverspec (1.0.0) Using bundler (1.3.5) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed. ``` NOTE: some systems may require you to run this command with sudo. If you already have those gems installed, make sure they are up-to-date: ```shell % bundle update ``` ## Running Tests With all dependencies in place and up-to-date, run the tests: ### Unit Tests ```shell % bundle exec rake spec ``` This executes all the [rspec tests](http://rspec-puppet.com/) in the directories defined [here](https://github.com/puppetlabs/puppetlabs_spec_helper/blob/699d9fbca1d2489bff1736bb254bb7b7edb32c74/lib/puppetlabs_spec_helper/rake_tasks.rb#L17) and so on. rspec tests may have the same kind of dependencies as the module they are testing. Although the module defines these dependencies in its [metadata.json](./metadata.json), rspec tests define them in [.fixtures.yml](./fixtures.yml). ### Acceptance Tests Some Puppet modules also come with acceptance tests, which use [beaker][]. These tests spin up a virtual machine under [VirtualBox](https://www.virtualbox.org/), controlled with [Vagrant](http://www.vagrantup.com/), to simulate scripted test scenarios. In order to run these, you need both Virtualbox and Vagrant installed on your system. Run the tests by issuing the following command ```shell % bundle exec rake spec_clean % bundle exec rspec spec/acceptance ``` This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), install Puppet, copy this module, and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) and then run all the tests under [spec/acceptance](./spec/acceptance). ## Writing Tests ### Unit Tests When writing unit tests for Puppet, [rspec-puppet][] is your best friend. It provides tons of helper methods for testing your manifests against a catalog (e.g. contain_file, contain_package, with_params, etc). It would be ridiculous to try and top rspec-puppet's [documentation][rspec-puppet_docs] but here's a tiny sample: Sample manifest: ```puppet file { "a test file": ensure => present, path => "/etc/sample", } ``` Sample test: ```ruby it 'does a thing' do expect(subject).to contain_file("a test file").with({:path => "/etc/sample"}) end ``` ### Acceptance Tests Writing acceptance tests for Puppet involves [beaker][] and its cousin [beaker-rspec][]. A common pattern for acceptance tests is to create a test manifest, apply it twice to check for idempotency or errors, then run expectations. ```ruby it 'does an end-to-end thing' do pp = <<-EOF file { 'a test file': ensure => present, path => "/etc/sample", content => "test string", } apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("/etc/sample") do it { is_expected.to contain "test string" } end ``` # If you have commit access to the repository Even if you have commit access to the repository, you still need to go through the process above, and have someone else review and merge in your changes. The rule is that **all changes must be reviewed by a project developer that did not write the code to ensure that all changes go through a code review process.** The record of someone performing the merge is the record that they performed the code review. Again, this should be someone other than the author of the topic branch. # Get Help ### On the web * [Puppet help messageboard](http://puppet.com/community/get-help) * [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing) * [General GitHub documentation](http://help.github.com/) * [GitHub pull request documentation](http://help.github.com/send-pull-requests/) ### On chat * Slack (slack.puppet.com) #forge-modules, #puppet-dev, #windows, #voxpupuli * IRC (freenode) #puppet-dev, #voxpupuli [rspec-puppet]: http://rspec-puppet.com/ [rspec-puppet_docs]: http://rspec-puppet.com/documentation/ [beaker]: https://github.com/puppetlabs/beaker [beaker-rspec]: https://github.com/puppetlabs/beaker-rspec puppetlabs-firewall-1.12.0/Gemfile0100644005276200011600000001350413232340436014040 0ustar00source ENV['GEM_SOURCE'] || 'https://rubygems.org' def location_for(place_or_version, fake_version = nil) if place_or_version =~ %r{\A(git[:@][^#]*)#(.*)} [fake_version, { git: Regexp.last_match(1), branch: Regexp.last_match(2), require: false }].compact elsif place_or_version =~ %r{\Afile:\/\/(.*)} ['>= 0', { path: File.expand_path(Regexp.last_match(1)), require: false }] else [place_or_version, { require: false }] end end def gem_type(place_or_version) if place_or_version =~ %r{\Agit[:@]} :git elsif !place_or_version.nil? && place_or_version.start_with?('file:') :file else :gem end end ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments minor_version = ruby_version_segments[0..1].join('.') group :development do gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') gem "puppet-module-posix-default-r#{minor_version}", require: false, platforms: [:ruby] gem "puppet-module-posix-dev-r#{minor_version}", require: false, platforms: [:ruby] gem "puppet-module-win-default-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-module-win-dev-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-blacksmith", '~> 3.4', require: false end group :system_tests do gem "puppet-module-posix-system-r#{minor_version}", require: false, platforms: [:ruby] gem "puppet-module-win-system-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '~> 3.13') gem "beaker-abs", *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1') gem "beaker-pe", require: false gem "beaker-hostgenerator" gem "beaker-rspec" end puppet_version = ENV['PUPPET_GEM_VERSION'] puppet_type = gem_type(puppet_version) facter_version = ENV['FACTER_GEM_VERSION'] hiera_version = ENV['HIERA_GEM_VERSION'] def puppet_older_than?(version) puppet_version = ENV['PUPPET_GEM_VERSION'] !puppet_version.nil? && Gem::Version.correct?(puppet_version) && Gem::Requirement.new("< #{version}").satisfied_by?(Gem::Version.new(puppet_version.dup)) end gems = {} gems['puppet'] = location_for(puppet_version) # If facter or hiera versions have been specified via the environment # variables, use those versions. If not, and if the puppet version is < 3.5.0, # use known good versions of both for puppet < 3.5.0. if facter_version gems['facter'] = location_for(facter_version) elsif puppet_type == :gem && puppet_older_than?('3.5.0') gems['facter'] = ['>= 1.6.11', '<= 1.7.5', require: false] end if hiera_version gems['hiera'] = location_for(ENV['HIERA_GEM_VERSION']) elsif puppet_type == :gem && puppet_older_than?('3.5.0') gems['hiera'] = ['>= 1.0.0', '<= 1.3.0', require: false] end if Gem.win_platform? && (puppet_type != :gem || puppet_older_than?('3.5.0')) # For Puppet gems < 3.5.0 (tested as far back as 3.0.0) on Windows if puppet_type == :gem gems['ffi'] = ['1.9.0', require: false] gems['minitar'] = ['0.5.4', require: false] gems['win32-eventlog'] = ['0.5.3', '<= 0.6.5', require: false] gems['win32-process'] = ['0.6.5', '<= 0.7.5', require: false] gems['win32-security'] = ['~> 0.1.2', '<= 0.2.5', require: false] gems['win32-service'] = ['0.7.2', '<= 0.8.8', require: false] else gems['ffi'] = ['~> 1.9.0', require: false] gems['minitar'] = ['~> 0.5.4', require: false] gems['win32-eventlog'] = ['~> 0.5', '<= 0.6.5', require: false] gems['win32-process'] = ['~> 0.6', '<= 0.7.5', require: false] gems['win32-security'] = ['~> 0.1', '<= 0.2.5', require: false] gems['win32-service'] = ['~> 0.7', '<= 0.8.8', require: false] end gems['win32-dir'] = ['~> 0.3', '<= 0.4.9', require: false] if RUBY_VERSION.start_with?('1.') gems['win32console'] = ['1.3.2', require: false] # sys-admin was removed in Puppet 3.7.0 and doesn't compile under Ruby 2.x gems['sys-admin'] = ['1.5.6', require: false] end # Puppet < 3.7.0 requires these. # Puppet >= 3.5.0 gem includes these as requirements. # The following versions are tested to work with 3.0.0 <= puppet < 3.7.0. gems['win32-api'] = ['1.4.8', require: false] gems['win32-taskscheduler'] = ['0.2.2', require: false] gems['windows-api'] = ['0.4.3', require: false] gems['windows-pr'] = ['1.2.3', require: false] elsif Gem.win_platform? # If we're using a Puppet gem on Windows which handles its own win32-xxx gem # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). gems['win32-dir'] = ['<= 0.4.9', require: false] gems['win32-eventlog'] = ['<= 0.6.5', require: false] gems['win32-process'] = ['<= 0.7.5', require: false] gems['win32-security'] = ['<= 0.2.5', require: false] gems['win32-service'] = ['<= 0.8.8', require: false] end gems.each do |gem_name, gem_params| gem gem_name, *gem_params end # Evaluate Gemfile.local and ~/.gemfile if they exist extra_gemfiles = [ "#{__FILE__}.local", File.join(Dir.home, '.gemfile'), ] extra_gemfiles.each do |gemfile| if File.file?(gemfile) && File.readable?(gemfile) eval(File.read(gemfile), binding) end end # vim: syntax=ruby puppetlabs-firewall-1.12.0/LICENSE0100644005276200011600000002613613102663532013560 0ustar00 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "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. "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. puppetlabs-firewall-1.12.0/MAINTAINERS.md0100644005276200011600000000030013107620162014625 0ustar00## Maintenance Maintainers: - Puppet Forge Modules Team `forge-modules |at| puppet |dot| com` Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `firewall`. puppetlabs-firewall-1.12.0/NOTICE0100644005276200011600000000111513232340436013444 0ustar00Puppet Module - puppetlabs-firewall Copyright 2018 Puppet, Inc. 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.puppetlabs-firewall-1.12.0/README.markdown0100644005276200011600000013574613202542071015257 0ustar00# firewall [![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-firewall.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-firewall) #### Table of Contents 1. [Overview - What is the firewall module?](#overview) 2. [Module description - What does the module do?](#module-description) 3. [Setup - The basics of getting started with firewall](#setup) * [What firewall affects](#what-firewall-affects) * [Setup requirements](#setup-requirements) * [Beginning with firewall](#beginning-with-firewall) * [Upgrading](#upgrading) 4. [Usage - Configuration and customization options](#usage) * [Default rules - Setting up general configurations for all firewalls](#default-rules) * [Application-specific rules - Options for configuring and managing firewalls across applications](#application-specific-rules) * [Additional ses for the firewall module](#other-rules) 5. [Reference - An under-the-hood peek at what the module is doing](#reference) 6. [Limitations - OS compatibility, etc.](#limitations) 7. [Firewall_multi - Arrays for certain parameters](#firewall_multi) 8. [Development - Guide for contributing to the module](#development) * [Tests - Testing your configuration](#tests) ## Overview The firewall module lets you manage firewall rules with Puppet. ## Module description PuppetLabs' firewall module introduces the `firewall` resource, which is used to manage and configure firewall rules from within the Puppet DSL. This module offers support for iptables and ip6tables. The module also introduces the `firewallchain` resource, which allows you to manage chains or firewall lists and ebtables for bridging support. At the moment, only iptables and ip6tables chains are supported. The firewall module acts on your running firewall, making immediate changes as the catalog executes. Defining default pre and post rules allows you to provide global defaults for your hosts before and after any custom rules. Defining `pre` and `post` rules is also necessary to help you avoid locking yourself out of your own boxes when Puppet runs. ## Setup ### What firewall affects * Every node running a firewall * Firewall settings in your system * Connection settings for managed nodes * Unmanaged resources (get purged) ### Setup requirements Firewall uses Ruby-based providers, so you must enable [pluginsync](http://docs.puppetlabs.com/guides/plugins_in_modules.html#enabling-pluginsync). ### Beginning with firewall In the following two sections, you create new classes and then create firewall rules related to those classes. These steps are optional but provide a framework for firewall rules, which is helpful if you’re just starting to create them. If you already have rules in place, then you don’t need to do these two sections. However, be aware of the ordering of your firewall rules. The module will dynamically apply rules in the order they appear in the catalog, meaning a deny rule could be applied before the allow rules. This might mean the module hasn’t established some of the important connections, such as the connection to the Puppet master. The following steps are designed to ensure that you keep your SSH and other connections, primarily your connection to your Puppet master. If you create the `pre` and `post` classes described in the first section, then you also need to create the rules described in the second section. #### Create the `my_fw::pre` and `my_fw::post` Classes This approach employs a whitelist setup, so you can define what rules you want and everything else is ignored rather than removed. The code in this section does the following: * The 'require' parameter in `firewall {}` ensures `my_fw::pre` is run before any other rules. * In the `my_fw::post` class declaration, the 'before' parameter ensures `my_fw::post` is run after any other rules. Therefore, the run order is: * The rules in `my_fw::pre` * Your rules (defined in code) * The rules in `my_fw::post` 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. ~~~puppet class my_fw::pre { Firewall { require => undef, } # Default firewall rules firewall { '000 accept all icmp': proto => 'icmp', action => 'accept', }-> firewall { '001 accept all to lo interface': proto => 'all', iniface => 'lo', action => 'accept', }-> firewall { '002 reject local traffic not on loopback interface': iniface => '! lo', proto => 'all', destination => '127.0.0.1/8', action => 'reject', }-> firewall { '003 accept related established rules': proto => 'all', state => ['RELATED', 'ESTABLISHED'], action => 'accept', } } ~~~ The rules in `pre` should allow basic networking (such as ICMP and TCP) and ensure that existing connections are not closed. 2.) Add the `post` class to my_fw/manifests/post.pp and include any default rules to be applied last. ~~~puppet class my_fw::post { firewall { '999 drop all': proto => 'all', action => 'drop', before => undef, } } ~~~ Alternatively, the [firewallchain](#type-firewallchain) type can be used to set the default policy: ~~~puppet firewallchain { 'INPUT:filter:IPv4': ensure => present, policy => drop, before => undef, } ~~~ #### Create firewall rules The rules you create here are helpful if you don’t have any existing rules; they help you order your firewall configurations so you don’t lock yourself out of your box. Rules are persisted automatically between reboots, although there are known issues with ip6tables on older Debian/Ubuntu distributions. There are also known issues with ebtables. 1.) In site.pp or another top-scope file, add the following code to set up a metatype to purge unmanaged firewall resources. This will clear any existing rules and make sure that only rules defined in Puppet exist on the machine. ~~~puppet resources { 'firewall': purge => true, } ~~~ To purge unmanaged firewall chains, also add: ~~~puppet resources { 'firewallchain': 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. ~~~puppet Firewall { before => Class['my_fw::post'], require => Class['my_fw::pre'], } ~~~ 3.) Then, declare the `my_fw::pre` and `my_fw::post` classes to satisfy dependencies. You can declare these classes using an External Node Classifier or the following code: ~~~puppet class { ['my_fw::pre', 'my_fw::post']: } ~~~ 4.) Include the `firewall` class to ensure the correct packages are installed. ~~~puppet class { 'firewall': } ~~~ ### Upgrading Use these steps if you already have a version of the firewall module installed. #### From version 0.2.0 and more recent Upgrade the module with the puppet module tool as normal: puppet module upgrade puppetlabs/firewall ## Usage There are two kinds of firewall rules you can use with firewall: default rules and application-specific rules. Default rules apply to general firewall settings, whereas application-specific rules manage firewall settings for a specific application, node, etc. All rules employ a numbering system in the resource's title that is used for ordering. When titling your rules, make sure you prefix the rule with a number, for example, '000 accept all icmp requests'. _000_ runs first, _999_ runs last. ### Default rules You can place default rules in either `my_fw::pre` or `my_fw::post`, depending on when you would like them to run. Rules placed in the `pre` class will run first, and rules in the `post` class, last. In iptables, the title of the rule is stored using the comment feature of the underlying firewall subsystem. Values must match '/^\d+[[:graph:][:space:]]+$/'. #### Examples of default rules Basic accept ICMP request example: ~~~puppet firewall { '000 accept all icmp requests': proto => 'icmp', action => 'accept', } ~~~ Drop all: ~~~puppet firewall { '999 drop all other requests': action => 'drop', } ~~~ #### Example of an IPv6 rule IPv6 rules can be specified using the _ip6tables_ provider: ~~~puppet firewall { '006 Allow inbound SSH (v6)': dport => 22, proto => tcp, action => accept, provider => 'ip6tables', } ~~~ ### Application-specific rules Puppet doesn't care where you define rules, and this means that you can place your firewall resources as close to the applications and services that you manage as you wish. If you use the [roles and profiles pattern](https://puppetlabs.com/learn/roles-profiles-introduction) then it makes sense to create your firewall rules in the profiles, so they remain close to the services managed by the profile. This is an example of firewall rules in a profile: ~~~puppet class profile::apache { include apache apache::vhost { 'mysite': ensure => present } firewall { '100 allow http and https access': dport => [80, 443], proto => tcp, action => accept, } } ~~~ ### Rule inversion Firewall rules may be inverted by prefixing the value of a parameter by "! ". If the value is an array, then every item in the array must be prefixed as iptables does not understand inverting a single value. Parameters that understand inversion are: connmark, ctstate, destination, dport, dst\_range, dst\_type, iniface, outiface, port, proto, source, sport, src\_range, src\_type, and state. Examples: ~~~puppet firewall { '001 disallow esp protocol': action => 'accept', proto => '! esp', } firewall { '002 drop NEW external website packets with FIN/RST/ACK set and SYN unset': chain => 'INPUT', state => 'NEW', action => 'drop', proto => 'tcp', sport => ['! http', '! 443'], source => '! 10.0.0.0/8', tcp_flags => '! FIN,SYN,RST,ACK SYN', } ~~~ ### Additional uses for the firewall module You can apply firewall rules to specific nodes. Usually, you should put the firewall rule in another class and apply that class to a node. Apply a rule to a node as follows: ~~~puppet node 'some.node.com' { firewall { '111 open port 111': dport => 111, } } ~~~ You can also do more complex things with the `firewall` resource. This example sets up static NAT for the source network 10.1.2.0/24: ~~~puppet firewall { '100 snat for network foo2': chain => 'POSTROUTING', jump => 'MASQUERADE', proto => 'all', outiface => 'eth0', source => '10.1.2.0/24', table => 'nat', } ~~~ You can also change the TCP MSS value for VPN client traffic: ~~~puppet firewall { '110 TCPMSS for VPN clients': chain => 'FORWARD', table => 'mangle', source => '10.0.2.0/24', proto => tcp, tcp_flags => 'SYN,RST SYN', mss => '1361:1541', set_mss => '1360', jump => 'TCPMSS', } ~~~ The following will mirror all traffic sent to the server to a secondary host on the LAN with the TEE target: ~~~puppet firewall { '503 Mirror traffic to IDS': proto => all, jump => 'TEE', gateway => '10.0.0.2', chain => 'PREROUTING', table => 'mangle', } ~~~ The following example creates a new chain and forwards any port 5000 access to it. ~~~puppet firewall { '100 forward to MY_CHAIN': chain => 'INPUT', jump => 'MY_CHAIN', } # The namevar here is in the format chain_name:table:protocol firewallchain { 'MY_CHAIN:filter:IPv4': ensure => present, } firewall { '100 my rule': chain => 'MY_CHAIN', action => 'accept', proto => 'tcp', dport => 5000, } ~~~ Setup NFLOG for a rule. ~~~puppet firewall {'666 for NFLOG': proto => 'all', jump => 'NFLOG', nflog_group => 3, nflog_prefix => "nflog-test", nflog_range = 256, nflog_threshold => 1, } ~~~ ### Additional information Access the inline documentation: puppet describe firewall Or puppet doc -r type (and search for firewall) ## Reference Classes: * [firewall](#class-firewall) Types: * [firewall](#type-firewall) * [firewallchain](#type-firewallchain) Facts: * [ip6tables_version](#fact-ip6tablesversion) * [iptables_version](#fact-iptablesversion) * [iptables_persistent_version](#fact-iptablespersistentversion) ### Class: firewall Performs the basic setup tasks required for using the firewall resources. At the moment this takes care of: * iptables-persistent package installation Include the `firewall` class for nodes that need to use the resources in this module: class { 'firewall': } #### ensure Parameter that controls the state of the iptables service on your system, allowing you to disable iptables if you want. `ensure` can either be 'running' or 'stopped'. Defaults to 'running'. #### 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'. #### ebtables_manage Parameter that controls whether puppet manages the ebtables package or not. If managed, the package will use the value of `pkg_ensure` as its ensure value. #### service_name Specify the name of the IPv4 iptables service. 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 This type enables you to manage firewall rules within Puppet. #### Providers **Note:** Not all features are available with all providers. * `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`, `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`, `hashlimit`. * `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`, `length`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `netmap`, `nflog_group`, `nflog_prefix`, `nflog_range`, `nflog_threshold`, `owner`, `pkttype`, `queue_bypass`, `queue_num`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `string_matching`, `tcp_flags`. **Autorequires:** If Puppet is managing the iptables or ip6tables chains specified in the `chain` or `jump` parameters, the firewall resource will autorequire those firewallchain resources. If Puppet is managing the iptables or iptables-persistent packages, and the provider is iptables or ip6tables, the firewall resource will autorequire those packages to ensure that any required binaries are installed. #### Features * `address_type`: The ability to match on source or destination address type. * `clusterip`: Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them. * `connection_limiting`: Connection limiting features. * `dnat`: Destination NATing. * `hop_limiting`: Hop limiting features. * `icmp_match`: The ability to match ICMP types. * `interface_match`: Interface matching. * `iprange`: The ability to match on source or destination IP range. * `ipsec_dir`: The ability to match IPsec policy direction. * `ipsec_policy`: The ability to match IPsec policy. * `iptables`: The provider provides iptables features. * `isfirstfrag`: The ability to match the first fragment of a fragmented ipv6 packet. * `isfragment`: The ability to match fragments. * `ishasmorefrags`: The ability to match a non-last fragment of a fragmented ipv6 packet. * `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. * `log_uid`: The ability to log the userid of the process which generated the packet. * `mark`: The ability to match or set the netfilter mark value associated with the packet. * `mask`: The ability to match recent rules based on the ipv4 mask. * `nflog_group`: The ability to set the group number for NFLOG. * `nflog_prefix`: The ability to set a prefix for nflog messages. * `nflog_range`: The ability to set nflog\_range. * `nflog_threshold`: The ability to set nflog\_threshold. * `owner`: The ability to match owners. * `pkttype`: The ability to match a packet type. * `rate_limiting`: Rate limiting features. * `recent_limiting`: The netfilter recent module. * `reject_type`: The ability to control reject messages. * `set_mss`: Set the TCP MSS of a packet. * `snat`: Source NATing. * `socket`: The ability to match open sockets. * `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. * `hashlimit`: The ability to use the hashlimit-module #### Parameters * `action`: This is the action to perform on a match. Valid values for this action are: * 'accept': The packet is accepted. * 'reject': The packet is rejected with a suitable ICMP response. * 'drop': The packet is dropped. If you specify no value it will simply match the rule but perform no action unless you provide a provider-specific parameter (such as `jump`). * `burst`: Rate limiting burst value (per second) before limit checks apply. Values must match '/^\d+$/'. Requires the `rate_limiting` feature. * `clusterip_new`: Create a new ClusterIP. You always have to set this on the first rule for a given ClusterIP. Requires the `clusterip` feature. * `clusterip_hashmode`: Specify the hashing mode. Valid values are sourceip, sourceip-sourceport, sourceip-sourceport-destport. Requires the `clusterip` feature. * `clusterip_clustermac`: Specify the ClusterIP MAC address. Has to be a link-layer multicast address. Requires the `clusterip` feature. * `clusterip_total_nodes`: Number of total nodes within this cluster. Requires the `clusterip` feature. * `clusterip_local_node`: Local node number within this cluster. Requires the `clusterip` feature. * `clusterip_hash_init`: Specify the random seed used for hash initialization. Requires the `clusterip` feature. * `chain`: Name of the chain to use. You can provide a user-based chain or use one of the following built-in chains:'INPUT','FORWARD','OUTPUT','PREROUTING', or 'POSTROUTING'. The default value is 'INPUT'. Values must match '/^[a-zA-Z0-9\-_]+$/'. Requires the `iptables` feature. * `checksum_fill`: When using a `jump` value of 'CHECKSUM', this boolean makes sure that a checksum is calculated and filled in a packet that lacks a checksum. Valid values are 'true' or 'false'. Requires the `iptables` feature. * `clamp_mss_to_pmtu`: Enables PMTU Clamping support when using a jump target of 'TCPMSS'. Valid values are 'true' or 'false'. * `connlimit_above`: Connection limiting value for matched connections above n. Values must match '/^\d+$/'. Requires the `connection_limiting` feature. * `connlimit_mask`: Connection limiting by subnet mask for matched connections. Apply a subnet mask of /0 to /32 for IPv4, and a subnet mask of /0 to /128 for IPv6. Values must match '/^\d+$/'. Requires the `connection_limiting` feature. * `connmark`: Match the Netfilter mark value associated with the packet. Accepts values `mark/mask` or `mark`. These will be converted to hex if they are not hex already. Requires the `mark` feature. * `ctstate`: Matches a packet based on its state in the firewall stateful inspection table, using the conntrack module. Valid values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED', 'UNTRACKED'. Requires the `state_match` feature. * `date_start`: Start Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' * `date_stop`: End Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' * `destination`: The destination address to match. For example: `destination => '192.168.1.0/24'`. You can also negate a mask by putting ! in front. For example: `destination => '! 192.168.2.0/24'`. The destination can also be an IPv6 address if your provider supports it. This parameter is supported by firewall_multi (see below). 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. * `dport`: The destination 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. * `dst_range`: The destination IP range. For example: `dst_range => '192.168.1.1-192.168.1.10'`. The destination IP range is must in 'IP1-IP2' format. Values in the range must be valid IPv4 or IPv6 addresses. Requires the `iprange` feature. * `dst_type`: The destination address type. For example: `dst_type => 'LOCAL'`. Valid values are: * 'UNSPEC': an unspecified address * 'UNICAST': a unicast address * 'LOCAL': a local address * 'BROADCAST': a broadcast address * 'ANYCAST': an anycast packet * 'MULTICAST': a multicast address * 'BLACKHOLE': a blackhole address * 'UNREACHABLE': an unreachable address * 'PROHIBIT': a prohibited address * 'THROW': an unroutable address * 'XRESOLVE: an unresolvable address Requires the `address_type` feature. * `ensure`: Ensures that the resource is present. Valid values are 'present', 'absent'. The default is 'present'. * `gateway`: Used with TEE target to mirror traffic of a machine to a secondary host on the LAN. * `gid`: GID or Group owner matching rule. Accepts a string argument only, as iptables does not accept multiple gid in a single statement. Requires the `owner` feature. * `hashlimit_above`: Match if the rate is above amount/quantum. A hash limit option (--hashlimit-upto, --hashlimit-above) and --hashlimit-name are required. * `hashlimit_burst`: Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not reached, up to this number; the default is 5. * `hashlimit_dstmask`: Like --hashlimit-srcmask, but for destination addresses. * `hashlimit_htable_expire`: After how many miliseconds do hash entries expire. Corresponds to --hashlimit-htable-expire. * `hashlimit_htable_gcinterval`: How many miliseconds between garbage collection intervals. Corresponds to --hashlimit-htable-gcinterval. * `hashlimit_htable_max`: Maximum entries in the hash. Corresponds to --hashlimit-htable-max. * `hashlimit_htable_size`: The number of buckets of the hash table. Corresponds to --hashlimit-htable-size. * `hashlimit_mode`: {srcip|srcport|dstip|dstport} A comma-separated list of objects to take into consideration. If no --hashlimit-mode option is given, hashlimit acts like limit, but at the expensive of doing the hash housekeeping. * `hashlimit_name`: The name for the /proc/net/ipt_hashlimit/foo entry. A hash limit option (--hashlimit-upto, --hashlimit-above) and --hashlimit-name are required. * `hashlimit_srcmask`: When --hashlimit-mode srcip is used, all source addresses encountered will be grouped according to the given prefix length and the so-created subnet will be subject to hashlimit. prefix must be between (inclusive) 0 and 32. Note that --hashlimit-srcmask 0 is basically doing the same thing as not specifying srcip for --hashlimit-mode, but is technically more expensive. * `hashlimit_upto`: Match if the rate is below or equal to amount/quantum. It is specified as a number, with an optional time quantum suffix; the default is 3/hour. A hash limit option (--hashlimit-upto, --hashlimit-above) and --hashlimit-name are required. * `hop_limit`: Hop limiting value for matched packets. Values must match '/^\d+$/'. Requires the `hop_limiting` feature. * `icmp`: When matching ICMP packets, this indicates the type of ICMP packet to match. A value of 'any' is not supported. To match any type of ICMP packet, the parameter should be omitted or undefined. Requires the `icmp_match` feature. This parameter is supported by firewall_multi (see below). * `iniface`: Input interface to filter on. Values must match '/^!?\s?[a-zA-Z0-9\-\._\+\:]+$/'. Requires the `interface_match` feature. Supports interface alias (eth0:0) and negation. * `ipsec_dir`: Sets the ipsec policy direction. Valid values are 'in', 'out'. Requires the `ipsec_dir` feature. * `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. 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. * `isfragment`: If 'true', matches when the packet is a tcp fragment of a fragmented packet. Supported by iptables only. Valid values are 'true', 'false'. Requires features `isfragment`. * `ishasmorefrags`: If 'true', matches when the packet has the 'more fragments' bit set. Supported by ipv6 only. Valid values are 'true', 'false'. Requires the `ishasmorefrags` feature. * `islastfrag`: If true, matches when the packet is the last fragment of a fragmented ipv6 packet. Supported by ipv6 only. Valid values are 'true', 'false'. Requires the `islastfrag`. * `jump`: The value for the iptables `--jump` parameter. Any valid chain name is allowed, but normal values are: 'QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK', 'TCPMSS', 'DSCP', 'NFLOG'. For the values 'ACCEPT', 'DROP', and 'REJECT', you must use the generic `action` parameter. This is to enforce the use of generic parameters where possible for maximum cross-platform modeling. If you set both `accept` and `jump` parameters, you will get an error, because only one of the options should be set. Requires the `iptables` feature. * `kernel_timezone`: Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations. * `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. * `log_level`: When combined with `jump => 'LOG'` specifies the system log level to log to. Requires the `log_level` feature. * `log_prefix`: When combined with `jump => 'LOG'` specifies the log prefix to use when logging. Requires the `log_prefix` feature. * `log_uid`: The ability to log the userid of the process which generated the packet. * `nflog_group`: When combined with `jump => 'NFLOG'` grants the ability to specify the NFLOG group number. Requires the `nflog_group` feature. * `nflog_prefix`: When combined with `jump => 'NFLOG'` grants the ability to specify a prefix for log entries. Requires the `nflog_prefix` feature. * `nflog_range`: When combined with `jump => 'NFLOG'` grants the ability to specify the number of bytes to be copied to userspace. Requires the `nflog_range` feature. * `nflog_threshold`: When combined with `jump => 'NFLOG'` grants the ability to specify the size of the NFLOG threshold. Requires the `nflog_threshold` feature. * `mask`: Sets the mask to use when `recent` is enabled. Requires the `mask` feature. * `month_days`: Only match on the given days of the month. Possible values are '1' to '31'. Note that specifying '31' will not match on months that do not have a 31st day; the same goes for 28- or 29-day February. * `match_mark`: Match the Netfilter mark value associated with the packet. Accepts either of mark/mask or mark. These will be converted to hex if they are not already. Requires the `mark` feature. * `mss`: Sets a given TCP MSS value or range to match. * `name`: The canonical name of the rule. This name is also used for ordering, so make sure you prefix the rule with a number. For example: ~~~puppet firewall { '000 this runs first': # this rule will run first } firewall { '999 this runs last': # this rule will run last } ~~~ Depending on the provider, the name of the rule can be stored using the comment feature of the underlying firewall subsystem. Values must match '/^\d+[[:graph:][:space:]]+$/'. * `outiface`: Output interface to filter on. Values must match '/^!?\s?[a-zA-Z0-9\-\._\+\:]+$/'. Requires the `interface_match` feature. Supports interface alias (eth0:0) and negation. * `physdev_in`: Match if the packet is entering a bridge from the given interface. Values must match '/^[a-zA-Z0-9\-\._\+]+$/'. * `physdev_out`: Match if the packet is leaving a bridge via the given interface. Values must match '/^[a-zA-Z0-9\-\._\+]+$/'. * `physdev_is_bridged`: Match if the packet is transversing a bridge. Valid values are true or false. * `physdev_is_in`: Match if the packet has entered through a bridge interface. Valid values are true or false. * `physdev_is_bridged`: Match if the packet will leave through a bridge interface. Valid values are true or false. * `pkttype`: Sets the packet type to match. Valid values are: 'unicast', 'broadcast', and'multicast'. Requires the `pkttype` feature. * `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. This parameter is supported by firewall_multi (see below). Valid values are: * 'ip' * 'tcp' * 'udp' * 'icmp' * 'ipv4' * 'ipv6' * 'ipv6-icmp' * 'esp' * 'ah' * 'vrrp' * 'igmp' * '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. This parameter is supported by firewall_multi (see below). * `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. * `reap`: Can only be used in conjunction with the `rseconds` parameter. If boolean 'true', this will purge entries older than 'seconds' as specified in `rseconds`. Valid values are true or false. Requires the `recent_limiting` feature and the `recent` parameter. * `recent`: Enable the recent module. Valid values are: 'set', 'update', 'rcheck', or 'remove'. For example: ~~~puppet # If anyone's appeared on the 'badguy' blacklist within # the last 60 seconds, drop their traffic, and update the timestamp. firewall { '100 Drop badguy traffic': recent => 'update', rseconds => 60, rsource => true, rname => 'badguy', action => 'DROP', chain => 'FORWARD', } # No-one should be sending us traffic on eth0 from localhost # Blacklist them firewall { '101 blacklist strange traffic': recent => 'set', rsource => true, rname => 'badguy', destination => '127.0.0.0/8', iniface => 'eth0', action => 'DROP', chain => 'FORWARD', } ~~~ Requires the `recent_limiting` feature. * `reject`: When combined with `jump => 'REJECT'`, you can specify a different ICMP response to be sent back to the packet sender. Requires the `reject_type` feature. * `rhitcount`: Used in conjunction with `recent => 'update'` or `recent => 'rcheck'`. When used, this will narrow the match to happen only when the address is in the list and packets greater than or equal to the given value have been received. Requires the `recent_limiting` feature and the `recent` parameter. * `rname`: Specify the name of the list. Takes a string argument. Requires the `recent_limiting` feature and the `recent` parameter. * `rseconds`: Used in conjunction with `recent => 'rcheck'` or `recent => 'update'`. When used, this will narrow the match to only happen when the address is in the list and was seen within the last given number of seconds. Requires the `recent_limiting` feature and the `recent` parameter. * `rsource`: If boolean 'true', adds the source IP address to the list. Valid values are 'true', 'false'. Requires the `recent_limiting` feature and the `recent` parameter. * `rttl`: May only be used in conjunction with `recent => 'rcheck'` or `recent => 'update'`. If boolean 'true', this will narrow the match to happen only when the address is in the list and the TTL of the current packet matches that of the packet that hit the `recent => 'set'` rule. If you have problems with DoS attacks via bogus packets from fake source addresses, this parameter may help. Valid values are 'true', 'false'. Requires the `recent_limiting` feature and the `recent` parameter. * `set_dscp`: When combined with `jump => 'DSCP'` specifies the dscp marking associated with the packet. * `set_dscp_class`: When combined with `jump => 'DSCP'` specifies the class associated with the packet (valid values found here: http://www.cisco.com/c/en/us/support/docs/quality-of-service-qos/qos-packet-marking/10103-dscpvalues.html#packetclassification). * `set_mark`: Set the Netfilter mark value associated with the packet. Accepts either 'mark/mask' or 'mark'. These will be converted to hex if they are not already. Requires the `mark` feature. * `set_mss`: When combined with `jump => 'TCPMSS'` specifies the value of the MSS field. * `socket`: If 'true', matches if an open socket can be found by doing a socket lookup on the packet. Valid values are 'true', 'false'. Requires the `socket` feature. * `source`: The source address. For example: `source => '192.168.2.0/24'`. You can also negate a mask by putting ! in front. For example: `source => '! 192.168.2.0/24'`. The source can also be an IPv6 address if your provider supports it. This parameter is supported by firewall_multi (see below). * `sport`: The 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. * `src_range`: The source IP range. For example: `src_range => '192.168.1.1-192.168.1.10'`. The source IP range must be in 'IP1-IP2' format. Values in the range must be valid IPv4 or IPv6 addresses. Requires the `iprange` feature. * `src_type`: Specify the source address type. For example: `src_type => 'LOCAL'`. Valid values are: * 'UNSPEC': an unspecified address. * 'UNICAST': a unicast address. * 'LOCAL': a local address. * 'BROADCAST': a broadcast address. * 'ANYCAST': an anycast packet. * 'MULTICAST': a multicast address. * 'BLACKHOLE': a blackhole address. * 'UNREACHABLE': an unreachable address. * 'PROHIBIT': a prohibited address. * 'THROW': an unroutable address. * 'XRESOLVE': an unresolvable address. Requires the `address_type` feature. * `stat_every`: Match one packet every nth packet. Requires `stat_mode => 'nth'` * `stat_mode`: Set the matching mode for statistic matching. Supported modes are `random` and `nth`. * `stat_packet`: Set the initial counter value for the nth mode. Must be between 0 and the value of `stat_every`. Defaults to 0. Requires `stat_mode => 'nth'` * `stat_probability`: Set the probability from 0 to 1 for a packet to be randomly matched. It works only with `stat_mode => 'random'`. * `state`: Matches a packet based on its state in the firewall stateful inspection table. Valid values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED', 'UNTRACKED'. 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'. Note that you specify flags in the order that iptables `--list` rules would list them to avoid having Puppet think you changed the flags. For example, 'FIN,SYN,RST,ACK SYN' matches packets with the SYN bit set and the ACK, RST and FIN bits cleared. Such packets are used to request TCP connection initiation. Requires the `tcp_flags` feature. * `time_contiguous`: When the `time_stop` value is smaller than the `time_start` value, match this as a single time period instead of distinct intervals. * `time_start`: Start time for the rule to match. The possible time range is '00:00:00' to '23:59:59'. Leading zeroes are allowed (e.g. '06:03') and correctly interpreted as base-10. * `time_stop`: End time for the rule to match. The possible time range is '00:00:00' to '23:59:59'. Leading zeroes are allowed (e.g. '06:03') and correctly interpreted as base-10. * `todest`: When using `jump => 'DNAT'`, you can specify the new destination address using this parameter. Requires the `dnat` feature. * `toports`: For DNAT this is the port that will replace the destination port. Requires the `dnat` feature. * `tosource`: When using `jump => 'SNAT'`, you can specify the new source address using this parameter. Requires the `snat` feature. * `to`: When using `jump => 'NETMAP'`, you can specify a source or destination subnet to nat to. Requires the `netmap` feature`. * `uid`: UID or Username owner matching rule. Accepts a string argument only, as iptables does not accept multiple uid in a single statement. Requires the `owner` feature. * `week_days`: Only match on the given weekdays. Possible values are 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'. ### Type: firewallchain Enables you to manage rule chains for firewalls. Currently this type supports only iptables, ip6tables, and ebtables on Linux. It also provides support for setting the default policy on chains and tables that allow it. **Autorequires**: If Puppet is managing the iptables or iptables-persistent packages, and the provider is iptables_chain, the firewall resource will autorequire those packages to ensure that any required binaries are installed. #### Providers `iptables_chain` is the only provider that supports firewallchain. #### Features * `iptables_chain`: The provider provides iptables chain features. * `policy`: Default policy (inbuilt chains only). #### Parameters * `ensure`: Ensures that the resource is present. Valid values are 'present', 'absent'. * `ignore`: Regex to perform on firewall rules to exempt unmanaged rules from purging (when enabled). This is matched against the output of iptables-save. This can be a single regex or an array of them. To support flags, use the ruby inline flag mechanism: a regex such as '/foo/i' can be written as '(?i)foo' or '(?i:foo)'. Only when purge is 'true'. Full example: ~~~puppet firewallchain { 'INPUT:filter:IPv4': purge => true, ignore => [ # ignore the fail2ban jump rule '-j fail2ban-ssh', # ignore any rules with "ignore" (case insensitive) in the comment in the rule '--comment "[^"](?i:ignore)[^"]"', ], } ~~~ * `name`: Specify the canonical name of the chain. For iptables the format must be {chain}:{table}:{protocol}. * `policy`: Set the action the packet will perform when the end of the chain is reached. It can only be set on inbuilt chains ('INPUT', 'FORWARD', 'OUTPUT', 'PREROUTING', 'POSTROUTING'). Valid values are: * 'accept': The packet is accepted. * 'drop': The packet is dropped. * 'queue': The packet is passed userspace. * 'return': The packet is returned to calling (jump) queue or to the default of inbuilt chains. * `provider`: The specific backend to use for this firewallchain resource. You will seldom need to specify this --- Puppet will usually discover the appropriate provider for your platform. The only available provider is: `iptables_chain`: iptables chain provider * Required binaries: `ebtables-save`, `ebtables`, `ip6tables-save`, `ip6tables`, `iptables-save`, `iptables`. * Default for `kernel` == `linux`. * Supported features: `iptables_chain`, `policy`. * `purge`: Purge unmanaged firewall rules in this chain. Valid values are 'false', 'true'. **Note** This `purge` is purging unmanaged rules in a firewall chain, not unmanaged firewall chains. To purge unmanaged firewall chains, use the following instead. ~~~puppet resources { 'firewallchain': purge => true, } ~~~ ### Fact: ip6tables_version A Facter fact that can be used to determine what the default version of ip6tables is for your operating system/distribution. ### Fact: iptables_version A Facter fact that can be used to determine what the default version of iptables is for your operating system/distribution. ### Fact: iptables_persistent_version Retrieves the version of iptables-persistent from your OS. This is a Debian/Ubuntu specific fact. ## Limitations ### SLES The `socket` parameter is not supported on SLES. In this release it will cause the catalog to fail with iptables failures, rather than correctly warn you that the features are unusable. ### Oracle Enterprise Linux The `socket` and `owner` parameters are unsupported on Oracle Enterprise Linux when the "Unbreakable" kernel is used. These may function correctly when using the stock RedHat kernel instead. Declaring either of these parameters on an unsupported system will result in iptable rules failing to apply. ### Debian 8 Support As Puppet Enterprise itself does not yet support Debian 8, use of this module with Puppet Enterprise under a Debian 8 system should be regarded as experimental. ## Passing firewall parameter values as arrays with `firewall_multi` module You might sometimes need to pass arrays, such as arrays of source or destination addresses, to some parameters in contexts where iptables itself does not allow arrays. A community module, [alexharvey-firewall_multi](https://forge.puppet.com/alexharvey/firewall_multi), provides a defined type wrapper to spawn firewall resources for arrays of certain inputs. For example: ~~~ puppet firewall_multi { '100 allow http and https access': source => [ '10.0.10.0/24', '10.0.12.0/24', '10.1.1.128', ], dport => [80, 443], proto => tcp, action => accept, } ~~~ For more information see the documentation at [alexharvey-firewall_multi](https://forge.puppet.com/alexharvey/firewall_multi). ### 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. If you use MCollective to kick off Puppet runs (`mco puppet runonce -I agent.example.com`) while also using the [`puppetlabs/firewall`](https://forge.puppet.com/puppetlabs/firewall) module, your firewall rules might be listed in reverse order. In many firewall configurations, the last rule drops all packets. If the rule order is reversed, this rule is listed first and network connectivity fails. To prevent this issue, do not use MCollective to kick off Puppet runs. Use any of the following instead: * Run `puppet agent -t` on the command line. * Use a cron job. * Click [Run Puppet](https://docs.puppet.com/pe/2016.1/console_classes_groups_running_puppet.html#run-puppet-on-an-individual-node) in the console. #### Reporting Issues Report found bugs in JIRA: ## Development Puppet modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. Read the module's CONTRIBUTING.md before contributing. This module supports: * iptables * ip6tables * ebtables (chains only) ### Testing Make sure you have: * rake * bundler Install the necessary gems: bundle install And run the tests from the root of the source code: rake test If you have a copy of Vagrant 1.1.0 you can also run the system tests: RS_SET=ubuntu-1404-x64 rspec spec/acceptance RS_SET=centos-64-x64 rspec spec/acceptance puppetlabs-firewall-1.12.0/Rakefile0100644005276200011600000000017713232340436014214 0ustar00require 'puppetlabs_spec_helper/rake_tasks' require 'puppet-syntax/tasks/puppet-syntax' require 'puppet_blacksmith/rake_tasks' puppetlabs-firewall-1.12.0/checksums.json0100644005276200011600000002076613232340576015442 0ustar00{ "CHANGELOG.md": "ad7fce7d5cc8c2565490a7b683f8867d", "CONTRIBUTING.md": "4d17f3c942e7c93d1577cc4438a231e4", "Gemfile": "47f2bb73e730d42a921e7bca4449f5aa", "LICENSE": "3b83ef96387f14655fc854ddc3c6bd57", "MAINTAINERS.md": "04aaaf05e794f325fd498880858fbd0f", "NOTICE": "16e399d242da32229321f743a0b27d8c", "README.markdown": "b8afd5fc6d9bd0a5873b9c14cbbb47ef", "Rakefile": "df4172642435e770c27019d9d15d59bd", "lib/facter/ip6tables_version.rb": "4ea8934f4329ab0133f803f801b61db6", "lib/facter/iptables_persistent_version.rb": "26788b3be58cd58ad47b03267a794326", "lib/facter/iptables_version.rb": "146e4e8b3655df1b77988e835ac3ba44", "lib/puppet/provider/firewall/ip6tables.rb": "7a8127d613b5ad55e624529d1b7267bc", "lib/puppet/provider/firewall/iptables.rb": "02d25b8fd5dd2af5be1301fb42713b3f", "lib/puppet/provider/firewall.rb": "d94d0ca1ac01e546fb9e0ff591f09aaf", "lib/puppet/provider/firewallchain/iptables_chain.rb": "292a7126bb9ead563ee3e1c635aeff67", "lib/puppet/type/firewall.rb": "677a366d428c940589666f5a1a33a7dd", "lib/puppet/type/firewallchain.rb": "baf368cc843e7211ff30735cd6dc00ca", "lib/puppet/util/firewall.rb": "d96f62c66d8287bfe96396fc9f232541", "lib/puppet/util/ipcidr.rb": "45fcb84e1cc295c432737e46e6a02a98", "locales/config.yaml": "92a513534d781a27f58da8e200b87b49", "manifests/init.pp": "69c22e13d3c82568f5acc5249f0c21b5", "manifests/linux/archlinux.pp": "692a236965597cfba264a2e361aa3522", "manifests/linux/debian.pp": "687dd3e1d08bb1ec28be119c73e095dd", "manifests/linux/gentoo.pp": "225a291a80afacc8d5f01a21825c0c5a", "manifests/linux/redhat.pp": "e90ee45e0c574cf89c26d1cce80f096b", "manifests/linux.pp": "391cfe691e648bcb3ce0aa97c84c6076", "manifests/params.pp": "a68a68256e5e0825b81df402b1fcc241", "metadata.json": "899af16cba6703a5c3222af3e6761e68", "spec/acceptance/change_source_spec.rb": "fbe2df21ec95bc0d3ce47c5550cfab00", "spec/acceptance/class_spec.rb": "6a4f8fc845b2ec5124c7ce0733943065", "spec/acceptance/connlimit_spec.rb": "d83757e4ee5f5ad867bcb5b92b7e8da3", "spec/acceptance/connmark_spec.rb": "63fd07132fb6081cacc81ba9fe43e3fa", "spec/acceptance/firewall_bridging_spec.rb": "1175abff7112aac80c9f1cbedb9254c3", "spec/acceptance/firewall_clusterip_spec.rb": "3f0031074e4a8f9ebde62d271ec68dda", "spec/acceptance/firewall_dscp_spec.rb": "39ff30237976b17ffb44c0592dcb8665", "spec/acceptance/firewall_gid_spec.rb": "9975e8be6147d3ec463d19138ce1f17f", "spec/acceptance/firewall_iptmodules_spec.rb": "de60038195d2975e173f38e3d6b2fbfc", "spec/acceptance/firewall_mss_spec.rb": "3588a6bcadecd45b5bee49ea4978ac6f", "spec/acceptance/firewall_spec.rb": "67b1304ea7808580399bf127fa3cc5ac", "spec/acceptance/firewall_tee_spec.rb": "c4c157b42baea7ef63bce0935fd9c8da", "spec/acceptance/firewall_time_spec.rb": "fd0dbb551f061b6e4d853052bc84ab7a", "spec/acceptance/firewall_uid_spec.rb": "ab334d700b8c6b507baf7094a561303a", "spec/acceptance/firewallchain_spec.rb": "62bf213945c854de341182db0ea27c90", "spec/acceptance/hashlimit_spec.rb": "49128462e5310265291b1538fd95a5db", "spec/acceptance/invert_spec.rb": "77718842cefb6366202ca25b3b0cf86c", "spec/acceptance/ip6_fragment_spec.rb": "db0155bccef5cc7957140f191766576a", "spec/acceptance/isfragment_spec.rb": "8c75b500412ccbb64284ea15c0b19803", "spec/acceptance/match_mark_spec.rb": "a7027fbac841de492b26789b2d986f98", "spec/acceptance/nflog_spec.rb": "96a3d9bdf12920da77732fe62fe178df", "spec/acceptance/nodesets/centos-7-x64.yml": "a713f3abd3657f0ae2878829badd23cd", "spec/acceptance/nodesets/debian-8-x64.yml": "d2d2977900989f30086ad251a14a1f39", "spec/acceptance/nodesets/default.yml": "b42da5a1ea0c964567ba7495574b8808", "spec/acceptance/nodesets/docker/centos-7.yml": "8a3892807bdd62306ae4774f41ba11ae", "spec/acceptance/nodesets/docker/debian-8.yml": "ac8e871d1068c96de5e85a89daaec6df", "spec/acceptance/nodesets/docker/ubuntu-14.04.yml": "dc42ee922a96908d85b8f0f08203ce58", "spec/acceptance/nodesets/new/aio/debian-8-64mda.yml": "3cb5b076f8ff1ce0123f7002d1132aa1", "spec/acceptance/nodesets/new/aio/redhat-6-64mda.yml": "2da8ffed4efeb44fb78b686a06195116", "spec/acceptance/nodesets/new/aio/redhat-7-64mda.yml": "200ba1439bddf26dd611b5f315e3b955", "spec/acceptance/nodesets/new/aio/ubuntu-1404-64mda.yml": "41256594850e488f033ec30327139162", "spec/acceptance/nodesets/new/aio/ubuntu-1604-64mda.yml": "9c79b040697c25f1170feaf3ea3d9700", "spec/acceptance/nodesets/new/pe/centos-5-64mda.yml": "192e4434be158fb238b8088f5d9adce0", "spec/acceptance/nodesets/new/pe/centos-6-64mda.yml": "13947041961996723a56bfa35289919a", "spec/acceptance/nodesets/new/pe/centos-7-64mda.yml": "5ff3e38e023c75ce2ace69a5ccadbf33", "spec/acceptance/nodesets/new/pe/debian-6-64mda.yml": "ff79b672c5a532409c492ad0d45dc0ad", "spec/acceptance/nodesets/new/pe/debian-7-64mda.yml": "63fefd7c9395781748a8b63d08dfd86c", "spec/acceptance/nodesets/new/pe/debian-8-64mda.yml": "ed8e721a3d96556d92a9a1806171987b", "spec/acceptance/nodesets/new/pe/oracle-5-64mda.yml": "64adf2da3fff9a6cf4b28c638f568a43", "spec/acceptance/nodesets/new/pe/oracle-6-64mda.yml": "3e0fbe6f9516023816c85884f0fdc839", "spec/acceptance/nodesets/new/pe/oracle-7-64mda.yml": "b5f568cf11baafdf98f0127220527219", "spec/acceptance/nodesets/new/pe/redhat-5-64mda.yml": "3c07dc9d83607f0f04a6903a77f5825d", "spec/acceptance/nodesets/new/pe/redhat-6-64mda.yml": "886858b5f4ddcd484da013eca85d996e", "spec/acceptance/nodesets/new/pe/redhat-7-64mda.yml": "199c73bd7860987d5af932164b5603e7", "spec/acceptance/nodesets/new/pe/scientific-5-64mda.yml": "4d23f6b5aa75033ddd9077588ee605a9", "spec/acceptance/nodesets/new/pe/scientific-6-64mda.yml": "342a75a0f2a8e45b7f317d34a35fdb77", "spec/acceptance/nodesets/new/pe/scientific-7-64mda.yml": "5952c337b5dfd11ddbc28cd7936630db", "spec/acceptance/nodesets/new/pe/sles-10-64mda.yml": "6b71985abd427432bdb2f9e8b76087fe", "spec/acceptance/nodesets/new/pe/sles-11-64mda.yml": "5ed55d2324395308cab72ec6e0545967", "spec/acceptance/nodesets/new/pe/sles-12-64mda.yml": "bc2fc9c59161c30b69fe907d65a138dc", "spec/acceptance/nodesets/new/pe/ubuntu-1004-64mda.yml": "07bef5f739c27a6a62945adbd2e8813e", "spec/acceptance/nodesets/new/pe/ubuntu-1204-64mda.yml": "c689063fd68a3c3ba3c47ced3016fa0e", "spec/acceptance/nodesets/new/pe/ubuntu-1404-64mda.yml": "d0f11e054810e240ba4efdf3d08de815", "spec/acceptance/nodesets/new/pe/ubuntu-1604-64mda.yml": "c66b70cd33f4e338ddfb54ff46f35c8e", "spec/acceptance/params_spec.rb": "f60f1a7fc8a3220452f8be9a8f75dff5", "spec/acceptance/purge_spec.rb": "dbed2bd663e16c7ec342f8c6043cf27f", "spec/acceptance/resource_cmd_spec.rb": "9ce572dfde35086363afcc4917e83844", "spec/acceptance/rules_spec.rb": "9178056223e997f9209c6e0d545efbb7", "spec/acceptance/socket_spec.rb": "faa8314766a5f45b722542aad70119e0", "spec/acceptance/standard_usage_spec.rb": "4a4fadac8e277d1380d481d07041ff08", "spec/default_facts.yml": "4de3cb611af6981a6d22bc77d7dd6f6f", "spec/fixtures/ip6tables/conversion_hash.rb": "ac76867b62fd635a85dcc7a565324491", "spec/fixtures/iptables/conversion_hash.rb": "e32f7f8fb2f1e84abc7c6a44ced35a6c", "spec/spec_helper.rb": "182136c8450f0af179fa0705ce971587", "spec/spec_helper_acceptance.rb": "5446c34b871fc9f392934d38700e6335", "spec/spec_helper_local.rb": "3fd478f37f68db2879ca92bf1237202b", "spec/unit/classes/firewall_linux_archlinux_spec.rb": "fd9ffeddd563b1030597e8289f5ba81f", "spec/unit/classes/firewall_linux_debian_spec.rb": "3b380ef3d0daa6cd9a87044560b96bcd", "spec/unit/classes/firewall_linux_gentoo_spec.rb": "9aff3cfc4194529b38b2831d904baeac", "spec/unit/classes/firewall_linux_redhat_spec.rb": "1b38b09b71daa440c01ef66682c72f34", "spec/unit/classes/firewall_linux_spec.rb": "4195e1e641e960fedb698e307a56bc53", "spec/unit/classes/firewall_spec.rb": "9f843d1b925a806f5480e9a882da1477", "spec/unit/documentation/readme_spec.rb": "ebe547b0051099281904dad3c5413de8", "spec/unit/facter/iptables_persistent_version_spec.rb": "035eef58c00edec80d913f01ff7fb5ac", "spec/unit/facter/iptables_spec.rb": "ee1ee01c6fcacdc23f9a85a3b147ee98", "spec/unit/puppet/provider/ip6tables_spec.rb": "ceee1675b92d9b391d23379064d6a343", "spec/unit/puppet/provider/iptables_chain_spec.rb": "0fca1374172197039fcdf5e50531257a", "spec/unit/puppet/provider/iptables_spec.rb": "48ea6b1030a83aac71f357e43be7a28e", "spec/unit/puppet/type/firewall_spec.rb": "f65f655d743e27662d24780497340da0", "spec/unit/puppet/type/firewallchain_spec.rb": "275c1df8e47d863cb7b8fd32b8ba4417", "spec/unit/puppet/util/firewall_spec.rb": "04cb8b0f0993ed0a03029dd8db3d1b45", "spec/unit/puppet/util/ipcidr_spec.rb": "c6c8097b4779aae250e38d8d8492ca32" }puppetlabs-firewall-1.12.0/lib0040755005276200011600000000000013232340575013240 5ustar00puppetlabs-firewall-1.12.0/lib/facter0040755005276200011600000000000013232340575014504 5ustar00puppetlabs-firewall-1.12.0/lib/facter/ip6tables_version.rb0100644005276200011600000000035313207747121020544 0ustar00Facter.add(:ip6tables_version) do confine kernel: :Linux setcode do version = Facter::Util::Resolution.exec('ip6tables --version') if version version.match(%r{\d+\.\d+\.\d+}).to_s else nil end end end puppetlabs-firewall-1.12.0/lib/facter/iptables_persistent_version.rb0100644005276200011600000000150113207747121022732 0ustar00Facter.add(:iptables_persistent_version) do confine operatingsystem: %w[Debian Ubuntu] setcode do # Throw away STDERR because dpkg >= 1.16.7 will make some noise if the # package isn't currently installed. os = Facter.value(:operatingsystem) os_release = Facter.value(:operatingsystemrelease) cmd = if (os == 'Debian' && (Puppet::Util::Package.versioncmp(os_release, '8.0') >= 0)) || (os == 'Ubuntu' && (Puppet::Util::Package.versioncmp(os_release, '14.10') >= 0)) "dpkg-query -Wf '${Version}' netfilter-persistent 2>/dev/null" else "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" end version = Facter::Util::Resolution.exec(cmd) if version.nil? || !version.match(%r{\d+\.\d+}) nil else version end end end puppetlabs-firewall-1.12.0/lib/facter/iptables_version.rb0100644005276200011600000000035113207747121020454 0ustar00Facter.add(:iptables_version) do confine kernel: :Linux setcode do version = Facter::Util::Resolution.exec('iptables --version') if version version.match(%r{\d+\.\d+\.\d+}).to_s else nil end end end puppetlabs-firewall-1.12.0/lib/puppet0040755005276200011600000000000013232340575014555 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/provider0040755005276200011600000000000013232340575016407 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/provider/firewall0040755005276200011600000000000013232340575020214 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/provider/firewall/ip6tables.rb0100644005276200011600000002252213207747121022511 0ustar00Puppet::Type.type(:firewall).provide :ip6tables, parent: :iptables, source: :ip6tables do @doc = 'Ip6tables type provider' has_feature :iptables has_feature :connection_limiting has_feature :hop_limiting has_feature :rate_limiting has_feature :recent_limiting has_feature :snat has_feature :dnat has_feature :interface_match has_feature :icmp_match has_feature :owner has_feature :state_match has_feature :reject_type has_feature :log_level has_feature :log_prefix has_feature :log_uid has_feature :mark has_feature :mss has_feature :tcp_flags has_feature :pkttype has_feature :ishasmorefrags has_feature :islastfrag has_feature :isfirstfrag has_feature :socket has_feature :address_type has_feature :iprange has_feature :ipsec_dir 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', ip6tables_save: 'ip6tables-save') confine kernel: :linux ip6tables_version = Facter.value('ip6tables_version') mark_flag = if ip6tables_version && Puppet::Util::Package.versioncmp(ip6tables_version, '1.4.1') < 0 '--set-mark' else '--set-xmark' end def initialize(*args) ip6tables_version = Facter.value('ip6tables_version') raise ArgumentError, 'The ip6tables provider is not supported on version 1.3 of iptables' if ip6tables_version && ip6tables_version.match(%r{1\.3\.\d}) super end def self.iptables(*args) ip6tables(*args) end def self.iptables_save(*args) ip6tables_save(*args) end @protocol = 'IPv6' @resource_map = { burst: '--limit-burst', checksum_fill: '--checksum-fill', clamp_mss_to_pmtu: '--clamp-mss-to-pmtu', connlimit_above: '-m connlimit --connlimit-above', connlimit_mask: '--connlimit-mask', connmark: '-m connmark --mark', ctstate: '-m conntrack --ctstate', destination: '-d', dport: ['-m multiport --dports', '--dport'], dst_range: '--dst-range', dst_type: '--dst-type', gateway: '--gateway', gid: '--gid-owner', hop_limit: '-m hl --hl-eq', icmp: '-m icmp6 --icmpv6-type', iniface: '-i', ipsec_dir: '-m policy --dir', ipsec_policy: '--pol', ipset: '-m set --match-set', isfirstfrag: '-m frag --fragid 0 --fragfirst', ishasmorefrags: '-m frag --fragid 0 --fragmore', islastfrag: '-m frag --fragid 0 --fraglast', jump: '-j', length: '-m length --length', limit: '-m limit --limit', log_level: '--log-level', log_prefix: '--log-prefix', log_uid: '--log-uid', mask: '--mask', match_mark: '-m mark --mark', name: '-m comment --comment', mac_source: ['-m mac --mac-source', '--mac-source'], mss: '-m tcpmss --mss', outiface: '-o', pkttype: '-m pkttype --pkt-type', port: '-m multiport --ports', proto: '-p', queue_num: '--queue-num', queue_bypass: '--queue-bypass', rdest: '--rdest', reap: '--reap', recent: '-m recent', reject: '--reject-with', rhitcount: '--hitcount', rname: '--name', rseconds: '--seconds', rsource: '--rsource', rttl: '--rttl', set_dscp: '--set-dscp', set_dscp_class: '--set-dscp-class', set_mark: mark_flag, set_mss: '--set-mss', socket: '-m socket', source: '-s', sport: ['-m multiport --sports', '--sport'], src_range: '--src-range', src_type: '--src-type', stat_every: '--every', stat_mode: '-m statistic --mode', stat_packet: '--packet', stat_probability: '--probability', state: '-m state --state', string: '-m string --string', string_algo: '--algo', string_from: '--from', string_to: '--to', table: '-t', tcp_flags: '-m tcp --tcp-flags', todest: '--to-destination', toports: '--to-ports', tosource: '--to-source', uid: '--uid-owner', physdev_in: '--physdev-in', physdev_out: '--physdev-out', physdev_is_bridged: '--physdev-is-bridged', physdev_is_in: '--physdev-is-in', physdev_is_out: '--physdev-is-out', date_start: '--datestart', date_stop: '--datestop', time_start: '--timestart', time_stop: '--timestop', month_days: '--monthdays', week_days: '--weekdays', time_contiguous: '--contiguous', kernel_timezone: '--kerneltz', src_cc: '--source-country', dst_cc: '--destination-country', hashlimit_name: '--hashlimit-name', hashlimit_upto: '--hashlimit-upto', hashlimit_above: '--hashlimit-above', hashlimit_burst: '--hashlimit-burst', hashlimit_mode: '--hashlimit-mode', hashlimit_srcmask: '--hashlimit-srcmask', hashlimit_dstmask: '--hashlimit-dstmask', hashlimit_htable_size: '--hashlimit-htable-size', hashlimit_htable_max: '--hashlimit-htable-max', hashlimit_htable_expire: '--hashlimit-htable-expire', hashlimit_htable_gcinterval: '--hashlimit-htable-gcinterval', } # These are known booleans that do not take a value, but we want to munge # to true if they exist. @known_booleans = [ :checksum_fill, :clamp_mss_to_pmtu, :ishasmorefrags, :islastfrag, :isfirstfrag, :log_uid, :rsource, :rdest, :reap, :rttl, :socket, :physdev_is_bridged, :physdev_is_in, :physdev_is_out, :time_contiguous, :kernel_timezone, :queue_bypass, ] # Properties that use "-m " (with the potential to have multiple # arguments against the same IPT module) must be in this hash. The keys in this # hash are the IPT module names, with the values being an array of the respective # supported arguments for this IPT module. # # ** IPT Module arguments must be in order as they would appear in iptables-save ** # # Exceptions: # => multiport: (For some reason, the multiport arguments can't be) # specified within the same "-m multiport", but works in seperate # ones. # @module_to_argument_mapping = { physdev: [:physdev_in, :physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out], addrtype: [:src_type, :dst_type], iprange: [:src_range, :dst_range], owner: [:uid, :gid], time: [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone], geoip: [:src_cc, :dst_cc], hashlimit: [:hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval], } # Create property methods dynamically (@resource_map.keys << :chain << :table << :action).each do |property| if @known_booleans.include?(property) # The boolean properties default to '' which should be read as false define_method property.to_s do @property_hash[property] = :false if @property_hash[property].nil? @property_hash[property.to_sym] end else define_method property.to_s do @property_hash[property.to_sym] end end if property == :chain define_method "#{property}=" do |value| if @property_hash[:chain] != value raise ArgumentError, 'Modifying the chain for existing rules is not supported.' end end else define_method "#{property}=" do |_value| @property_hash[:needs_change] = true end end end # This is the order of resources as they appear in iptables-save output, # we need it to properly parse and apply rules, if the order of resource # changes between puppet runs, the changed rules will be re-applied again. # This order can be determined by going through iptables source code or just tweaking and trying manually # (Note: on my CentOS 6.4 ip6tables-save returns -m frag on the place # I put it when calling the command. So compability with manual changes # not provided with current parser [georg.koester]) @resource_list = [:table, :source, :destination, :iniface, :outiface, :physdev_in, :physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type, :dst_type, :socket, :pkttype, :ipsec_dir, :ipsec_policy, :state, :ctstate, :icmp, :hop_limit, :limit, :burst, :length, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo, :string_from, :string_to, :jump, :clamp_mss_to_pmtu, :gateway, :todest, :tosource, :toports, :checksum_fill, :log_level, :log_prefix, :log_uid, :reject, :set_mss, :set_dscp, :set_dscp_class, :mss, :queue_num, :queue_bypass, :set_mark, :match_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone, :src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :name] end puppetlabs-firewall-1.12.0/lib/puppet/provider/firewall/iptables.rb0100644005276200011600000007166713232340436022435 0ustar00require 'puppet/provider/firewall' require 'digest/md5' Puppet::Type.type(:firewall).provide :iptables, parent: Puppet::Provider::Firewall do include Puppet::Util::Firewall @doc = 'Iptables type provider' has_feature :iptables has_feature :connection_limiting has_feature :rate_limiting has_feature :recent_limiting has_feature :snat has_feature :dnat has_feature :netmap has_feature :interface_match has_feature :icmp_match has_feature :owner has_feature :state_match has_feature :reject_type has_feature :log_level has_feature :log_prefix has_feature :log_uid has_feature :mark has_feature :mss has_feature :nflog_group has_feature :nflog_prefix has_feature :nflog_range has_feature :nflog_threshold has_feature :tcp_flags has_feature :pkttype has_feature :isfragment has_feature :socket has_feature :address_type has_feature :iprange has_feature :ipsec_dir has_feature :ipsec_policy 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', iptables_save: 'iptables-save') defaultfor kernel: :linux confine kernel: :linux iptables_version = Facter.value('iptables_version') mark_flag = if iptables_version && Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') < 0 '--set-mark' else '--set-xmark' end @protocol = 'IPv4' @resource_map = { burst: '--limit-burst', checksum_fill: '--checksum-fill', clamp_mss_to_pmtu: '--clamp-mss-to-pmtu', connlimit_above: '-m connlimit --connlimit-above', connlimit_mask: '--connlimit-mask', connmark: '-m connmark --mark', ctstate: '-m conntrack --ctstate', destination: '-d', dport: ['-m multiport --dports', '--dport'], dst_range: '--dst-range', dst_type: '--dst-type', gateway: '--gateway', gid: '--gid-owner', icmp: '-m icmp --icmp-type', iniface: '-i', ipsec_dir: '-m policy --dir', ipsec_policy: '--pol', ipset: '-m set --match-set', isfragment: '-f', jump: '-j', goto: '-g', length: '-m length --length', limit: '-m limit --limit', log_level: '--log-level', log_prefix: '--log-prefix', log_uid: '--log-uid', mac_source: ['-m mac --mac-source', '--mac-source'], mask: '--mask', match_mark: '-m mark --mark', mss: '-m tcpmss --mss', name: '-m comment --comment', nflog_group: '--nflog-group', nflog_prefix: '--nflog-prefix', nflog_range: '--nflog-range', nflog_threshold: '--nflog-threshold', outiface: '-o', pkttype: '-m pkttype --pkt-type', port: '-m multiport --ports', proto: '-p', queue_num: '--queue-num', queue_bypass: '--queue-bypass', random: '--random', rdest: '--rdest', reap: '--reap', recent: '-m recent', reject: '--reject-with', rhitcount: '--hitcount', rname: '--name', rseconds: '--seconds', rsource: '--rsource', rttl: '--rttl', set_dscp: '--set-dscp', set_dscp_class: '--set-dscp-class', set_mark: mark_flag, set_mss: '--set-mss', socket: '-m socket', source: '-s', sport: ['-m multiport --sports', '--sport'], src_range: '--src-range', src_type: '--src-type', stat_every: '--every', stat_mode: '-m statistic --mode', stat_packet: '--packet', stat_probability: '--probability', state: '-m state --state', string: '-m string --string', string_algo: '--algo', string_from: '--from', string_to: '--to', table: '-t', tcp_flags: '-m tcp --tcp-flags', todest: '--to-destination', toports: '--to-ports', tosource: '--to-source', to: '--to', uid: '--uid-owner', physdev_in: '--physdev-in', physdev_out: '--physdev-out', physdev_is_bridged: '--physdev-is-bridged', physdev_is_in: '--physdev-is-in', physdev_is_out: '--physdev-is-out', date_start: '--datestart', date_stop: '--datestop', time_start: '--timestart', time_stop: '--timestop', month_days: '--monthdays', week_days: '--weekdays', time_contiguous: '--contiguous', kernel_timezone: '--kerneltz', clusterip_new: '--new', clusterip_hashmode: '--hashmode', clusterip_clustermac: '--clustermac', clusterip_total_nodes: '--total-nodes', clusterip_local_node: '--local-node', clusterip_hash_init: '--hash-init', src_cc: '--source-country', dst_cc: '--destination-country', hashlimit_name: '--hashlimit-name', hashlimit_upto: '--hashlimit-upto', hashlimit_above: '--hashlimit-above', hashlimit_burst: '--hashlimit-burst', hashlimit_mode: '--hashlimit-mode', hashlimit_srcmask: '--hashlimit-srcmask', hashlimit_dstmask: '--hashlimit-dstmask', hashlimit_htable_size: '--hashlimit-htable-size', hashlimit_htable_max: '--hashlimit-htable-max', hashlimit_htable_expire: '--hashlimit-htable-expire', hashlimit_htable_gcinterval: '--hashlimit-htable-gcinterval', } # These are known booleans that do not take a value, but we want to munge # to true if they exist. @known_booleans = [ :checksum_fill, :clamp_mss_to_pmtu, :isfragment, :log_uid, :random, :rdest, :reap, :rsource, :rttl, :socket, :physdev_is_bridged, :physdev_is_in, :physdev_is_out, :time_contiguous, :kernel_timezone, :clusterip_new, :queue_bypass, ] # Properties that use "-m " (with the potential to have multiple # arguments against the same IPT module) must be in this hash. The keys in this # hash are the IPT module names, with the values being an array of the respective # supported arguments for this IPT module. # # ** IPT Module arguments must be in order as they would appear in iptables-save ** # # Exceptions: # => multiport: (For some reason, the multiport arguments can't be) # specified within the same "-m multiport", but works in seperate # ones. # @module_to_argument_mapping = { physdev: [:physdev_in, :physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out], addrtype: [:src_type, :dst_type], iprange: [:src_range, :dst_range], owner: [:uid, :gid], time: [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone], geoip: [:src_cc, :dst_cc], hashlimit: [:hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval], } def self.munge_resource_map_from_existing_values(resource_map_original, compare) resource_map_new = resource_map_original.clone @module_to_argument_mapping.each do |ipt_module, arg_array| arg_array.each do |argument| if resource_map_original[argument].is_a?(Array) if compare.include?(resource_map_original[argument].first) resource_map_new[argument] = resource_map_original[argument].clone resource_map_new[argument][0] = "-m #{ipt_module} #{resource_map_original[argument].first}" break end elsif compare.include?(resource_map_original[argument]) resource_map_new[argument] = "-m #{ipt_module} #{resource_map_original[argument]}" break end end end resource_map_new end def munge_resource_map_from_resource(resource_map_original, compare) resource_map_new = resource_map_original.clone module_to_argument_mapping = self.class.instance_variable_get('@module_to_argument_mapping') module_to_argument_mapping.each do |ipt_module, arg_array| arg_array.each do |argument| next unless compare[argument] if resource_map_original[argument].is_a?(Array) resource_map_new[argument] = resource_map_original[argument].clone resource_map_new[argument][0] = "-m #{ipt_module} #{resource_map_original[argument].first}" else resource_map_new[argument] = "-m #{ipt_module} #{resource_map_original[argument]}" end break end end resource_map_new end # Create property methods dynamically (@resource_map.keys << :chain << :table << :action).each do |property| if @known_booleans.include?(property) # The boolean properties default to '' which should be read as false define_method property.to_s do @property_hash[property] = :false if @property_hash[property].nil? @property_hash[property.to_sym] end else define_method property.to_s do @property_hash[property.to_sym] end end if property == :chain define_method "#{property}=" do |value| if @property_hash[:chain] != value raise ArgumentError, 'Modifying the chain for existing rules is not supported.' end end else define_method "#{property}=" do |_value| @property_hash[:needs_change] = true end end end # This is the order of resources as they appear in iptables-save output, # we need it to properly parse and apply rules, if the order of resource # changes between puppet runs, the changed rules will be re-applied again. # This order can be determined by going through iptables source code or just tweaking and trying manually @resource_list = [ :table, :source, :destination, :iniface, :outiface, :physdev_in, :physdev_out, :physdev_is_bridged, :physdev_is_in, :physdev_is_out, :proto, :isfragment, :stat_mode, :stat_every, :stat_packet, :stat_probability, :src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type, :dst_type, :socket, :pkttype, :ipsec_dir, :ipsec_policy, :state, :ctstate, :icmp, :limit, :burst, :length, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo, :string_from, :string_to, :jump, :goto, :clusterip_new, :clusterip_hashmode, :clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init, :queue_num, :queue_bypass, :nflog_group, :nflog_prefix, :nflog_range, :nflog_threshold, :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, :src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst, :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size, :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :name ] def insert debug 'Inserting rule %s' % resource[:name] iptables insert_args end def update debug 'Updating rule %s' % resource[:name] iptables update_args end def delete debug 'Deleting rule %s' % resource[:name] begin iptables delete_args rescue Puppet::ExecutionFailure => e # Check to see if the iptables rule is already gone. This can sometimes # happen as a side effect of other resource changes. If it's not gone, # raise the error as per usual. raise e unless resource.property(:ensure).insync?(:absent) # If it's already gone, there is no error. Still record a change, but # adjust the change message to indicate ambiguity over what work Puppet # actually did to remove the resource, vs. what could have been a side # effect of something else puppet did. resource.property(:ensure).singleton_class.send(:define_method, :change_to_s) do |_a, _b| 'ensured absent' end end end def exists? properties[:ensure] != :absent end # Flush the property hash once done. def flush debug('[flush]') if @property_hash.delete(:needs_change) notice('Properties changed - updating rule') update end persist_iptables(self.class.instance_variable_get(:@protocol)) @property_hash.clear end def self.instances debug '[instances]' table = nil rules = [] counter = 1 # String#lines would be nice, but we need to support Ruby 1.8.5 iptables_save.split("\n").each do |line| unless line =~ %r{^\#\s+|^\:\S+|^COMMIT|^FATAL} if line =~ %r{^\*} table = line.sub(%r{\*}, '') else hash = rule_to_hash(line, table, counter) if hash rules << new(hash) counter += 1 end end end end rules end def self.rule_to_hash(line, table, counter) hash = {} keys = [] values = line.dup #################### # PRE-PARSE CLUDGING #################### # The match for ttl values = values.gsub(%r{(!\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(%r{(!\s+)?--tcp-flags (\S*) (\S*)}, '--tcp-flags "\1\2 \3"') # --match-set can have multiple values with weird iptables format if values =~ %r{-m set (!\s+)?--match-set} values = values.gsub(%r{(!\s+)?--match-set (\S*) (\S*)}, '--match-set \1\2 \3') ind = values.index('-m set --match-set') sets = values.scan(%r{-m set --match-set ((?:!\s+)?\S* \S*)}) values = values.gsub(%r{-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(%r{(?<=\s)(-\S+) (!)\s?(\S*)}, '\1 "\2 \3"') # fix negated physdev rules values = values.gsub(%r{-m physdev ! (--physdev-is-\S+)}, '-m physdev \1 "!"') # the actual rule will have the ! mark before the option. values = values.gsub(%r{(!)\s*(-\S+)\s*(\S*)}, '\2 "\1 \3"') # The match extension for tcp & udp are optional and throws off the @resource_map. values = values.gsub(%r{(?!-m tcp --tcp-flags)-m (tcp|udp) }, '') # There is a bug in EL5 which puts 2 spaces before physdev, so we fix it values = values.gsub(%r{\s{2}--physdev}, ' --physdev') # '--pol ipsec' takes many optional arguments; we cheat again by adding " around them values = values.sub(%r{ --pol\sipsec (\s--strict)? (\s--reqid\s\S+)? (\s--spi\s\S+)? (\s--proto\s\S+)? (\s--mode\s\S+)? (\s--tunnel-dst\s\S+)? (\s--tunnel-src\s\S+)? (\s--next)?}x, '--pol "ipsec\1\2\3\4\5\6\7\8" ') # on some iptables versions, --connlimit-saddr switch is added after the rule is applied values = values.gsub(%r{--connlimit-saddr}, '') resource_map = munge_resource_map_from_existing_values(@resource_map, values) # Trick the system for booleans @known_booleans.each do |bool| # append "true" because all params are expected to have values values = if bool == :isfragment # -f requires special matching: # only replace those -f that are not followed by an l to # distinguish between -f and the '-f' inside of --tcp-flags. values.sub(%r{\s-f(?!l)(?=.*--comment)}, ' -f true') else # append `true` to booleans that are not already negated (followed by "!") values.sub(%r{#{resource_map[bool]}(?! "!")}, "#{resource_map[bool]} true") end end ############ # Populate parser_list with used value, in the correct order ############ map_index = {} resource_map.each_pair do |map_k, map_v| [map_v].flatten.each do |v| ind = values.index(%r{\s#{v}\s}) next unless ind map_index[map_k] = ind end end # Generate parser_list based on the index of the found option parser_list = [] map_index.sort_by { |_k, v| v }.each { |mapi| parser_list << mapi.first } ############ # MAIN PARSE ############ # Here we iterate across our values to generate an array of keys parser_list.reverse.each do |k| resource_map_key = resource_map[k] [resource_map_key].flatten.each do |opt| if values.slice!(%r{\s#{opt}}) keys << k break end end end # Manually remove chain if values =~ %r{(\s|^)-A\s} values = values.sub(%r{(\s|^)-A\s}, '\1') keys << :chain end # Manually remove table (used in some tests) if values =~ %r{^-t\s} values = values.sub(%r{^-t\s}, '') keys << :table end valrev = values.scan(%r{("([^"\\]|\\.)*"|\S+)}).transpose[0].reverse if keys.length != valrev.length warning "Skipping unparsable iptables rule: keys (#{keys.length}) and values (#{valrev.length}) count mismatch on line: #{line}" return end # Here we generate the main hash by scanning arguments off the values # string, handling any quoted characters present in the value, and then # zipping the values with the array of keys. keys.zip(valrev) do |f, v| hash[f] = if v =~ %r{^".*"$} v.sub(%r{^"(.*)"$}, '\1').gsub(%r{\\(\\|'|")}, '\1') else v.dup end end ##################### # POST PARSE CLUDGING ##################### [:dport, :sport, :port, :state, :ctstate].each do |prop| hash[prop] = hash[prop].split(',') unless hash[prop].nil? end hash[:ipset] = hash[:ipset].split(';') unless hash[:ipset].nil? ## clean up DSCP class to HEX mappings valid_dscp_classes = { '0x0a' => 'af11', '0x0c' => 'af12', '0x0e' => 'af13', '0x12' => 'af21', '0x14' => 'af22', '0x16' => 'af23', '0x1a' => 'af31', '0x1c' => 'af32', '0x1e' => 'af33', '0x22' => 'af41', '0x24' => 'af42', '0x26' => 'af43', '0x08' => 'cs1', '0x10' => 'cs2', '0x18' => 'cs3', '0x20' => 'cs4', '0x28' => 'cs5', '0x30' => 'cs6', '0x38' => 'cs7', '0x2e' => 'ef', } [:set_dscp_class].each do |prop| [:set_dscp].each do |dmark| next unless hash[dmark] hash[prop] = valid_dscp_classes[hash[dmark]] end end # Convert booleans removing the previous cludge we did @known_booleans.each do |bool| unless [nil, 'true', '!'].include?(hash[bool]) raise "Parser error: #{bool} was meant to be a boolean but received value: #{hash[bool]}." end end # Our type prefers hyphens over colons for ranges so ... # Iterate across all ports replacing colons with hyphens so that ranges match # the types expectations. [:dport, :sport, :port].each do |prop| next unless hash[prop] hash[prop] = hash[prop].map do |elem| elem.tr(':', '-') end end if hash[:length] hash[:length].tr!(':', '-') end # Invert any rules that are prefixed with a '!' [ :connmark, :ctstate, :destination, :dport, :dst_range, :dst_type, :port, :physdev_is_bridged, :physdev_is_in, :physdev_is_out, :proto, :source, :sport, :src_range, :src_type, :state, ].each do |prop| if hash[prop] && hash[prop].is_a?(Array) # find if any are negated, then negate all if so should_negate = hash[prop].index do |value| value.match(%r{^(!)\s+}) end if should_negate hash[prop] = hash[prop].map do |v| "! #{v.sub(%r{^!\s+}, '')}" end end elsif hash[prop] m = hash[prop].match(%r{^(!?)\s?(.*)}) neg = '! ' if m[1] == '!' hash[prop] = if [:source, :destination].include?(prop) # Normalise all rules to CIDR notation. "#{neg}#{Puppet::Util::IPCidr.new(m[2]).cidr}" else "#{neg}#{m[2]}" end end end # States should always be sorted. This ensures that the output from # iptables-save and user supplied resources is consistent. hash[:state] = hash[:state].sort unless hash[:state].nil? hash[:ctstate] = hash[:ctstate].sort unless hash[:ctstate].nil? # This forces all existing, commentless rules or rules with invalid comments to be moved # to the bottom of the stack. # Puppet-firewall requires that all rules have comments (resource names) and match this # regex and will fail if a rule in iptables does not have a comment. We get around this # by appending a high level if !hash[:name] num = 9000 + counter hash[:name] = "#{num} #{Digest::MD5.hexdigest(line)}" elsif not %r{^\d+[[:graph:][:space:]]+$} =~ hash[:name] # rubocop:disable Style/Not : Making this change breaks the code num = 9000 + counter hash[:name] = "#{num} #{%r{([[:graph:][:space:]]+)}.match(hash[:name])[1]}" end # Iptables defaults to log_level '4', so it is omitted from the output of iptables-save. # If the :jump value is LOG and you don't have a log-level set, we assume it to be '4'. if hash[:jump] == 'LOG' && !hash[:log_level] hash[:log_level] = '4' end # Iptables defaults to burst '5', so it is ommitted from the output of iptables-save. # If the :limit value is set and you don't have a burst set, we assume it to be '5'. if hash[:limit] && !hash[:burst] hash[:burst] = '5' end hash[:line] = line hash[:provider] = name.to_s hash[:table] = table hash[:ensure] = :present # Munge some vars here ... # Proto should equal 'all' if undefined hash[:proto] = 'all' unless hash.include?(:proto) # If the jump parameter is set to one of: ACCEPT, REJECT or DROP then # we should set the action parameter instead. if %w[ACCEPT REJECT DROP].include?(hash[:jump]) hash[:action] = hash[:jump].downcase hash.delete(:jump) end hash end def insert_args args = [] args << ['-I', resource[:chain], insert_order] args << general_args args end def update_args args = [] args << ['-R', resource[:chain], insert_order] args << general_args args end def delete_args # Split into arguments line = properties[:line].gsub(%r{^\-A }, '-D ').split(%r{\s+(?=(?:[^"]|"[^"]*")*$)}).map { |v| v.gsub(%r{^"}, '').gsub(%r{"$}, '') } line.unshift('-t', properties[:table]) end # This method takes the resource, and attempts to generate the command line # arguments for iptables. def general_args debug 'Current resource: %s' % resource.class args = [] resource_list = self.class.instance_variable_get('@resource_list') known_booleans = self.class.instance_variable_get('@known_booleans') 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 # nflog options are not available on older OSes [:nflog_group, :nflog_prefix, :nflog_threshold, :nflog_range].each do |nflog_feature| raise "#{nflog_feature} is not available on iptables version #{iptables_version}" if resource[nflog_feature] && (iptables_version && iptables_version < '1.3.7') end resource_list.each do |res| resource_value = nil if resource[res] resource_value = resource[res] # If socket is true then do not add the value as -m socket is standalone if known_booleans.include?(res) next unless resource[res] == :true && known_booleans.include?(res) resource_value = nil end elsif res == :jump && resource[:action] # In this case, we are substituting jump for action resource_value = resource[:action].to_s.upcase else next end args << [resource_map[res]].flatten.first.split(' ') args = args.flatten # On negations, the '!' has to be before the option (eg: "! -d 1.2.3.4") if resource_value.is_a?(String) && resource_value.sub!(%r{^!\s*}, '') # we do this after adding the 'dash' argument because of ones like "-m multiport --dports", where we want it before the "--dports" but after "-m multiport". # so we insert before whatever the last argument is args.insert(-2, '!') elsif resource_value.is_a?(Symbol) && resource_value.to_s.match(%r{^!}) # ruby 1.8.7 can't .match Symbols ------------------ ^ resource_value = resource_value.to_s.sub!(%r{^!\s*}, '').to_sym args.insert(-2, '!') elsif resource_value.is_a?(Array) && res != :ipset should_negate = resource_value.index do |value| # ruby 1.8.7 can't .match symbols value.to_s.match(%r{^(!)\s+}) end if should_negate resource_value, wrong_values = resource_value.map { |value| # rubocop:disable Metrics/BlockNesting if value.is_a?(String) wrong = value unless value =~ %r{^!\s+} [value.sub(%r{^!\s*}, ''), wrong] else [value, nil] end }.transpose wrong_values = wrong_values.compact unless wrong_values.empty? raise "All values of the '#{res}' property must be prefixed with a '!' when inverting, but '#{wrong_values.join("', '")}' #{(wrong_values.length > 1) ? 'are' : 'is'} not prefixed; aborting" # rubocop:disable Metrics/LineLength : Line length cannot be reduced end args.insert(-2, '!') # rubocop:enable Metrics/BlockNesting end end # For sport and dport, convert hyphens to colons since the type # expects hyphens for ranges of ports. if [:sport, :dport, :port].include?(res) resource_value = resource_value.map do |elem| elem.tr('-', ':') 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!(%r{^!\s*}, '') # Negate ipset options args.insert(-2, '!') end args << a unless a.empty? end # our tcp_flags takes a single string with comma lists separated # by space # --tcp-flags expects two arguments elsif res == :tcp_flags one, two = resource_value.split(' ') args << one args << two elsif resource_value.is_a?(Array) args << resource_value.join(',') elsif !resource_value.nil? args << resource_value end end args end def insert_order debug('[insert_order]') rules = [] # Find list of current rules based on chain and table self.class.instances.each do |rule| if rule.chain == resource[:chain].to_s && rule.table == resource[:table].to_s rules << rule.name end end # No rules at all? Just bail now. return 1 if rules.empty? # Add our rule to the end of the array of known rules my_rule = resource[:name].to_s rules << my_rule unmanaged_rule_regex = %r{^9[0-9]{3}\s.*$} # Find if this is a new rule or an existing rule, then find how many # unmanaged rules preceed it. if rules.length == rules.uniq.length # This is a new rule so find its ordered location. new_rule_location = rules.sort.uniq.index(my_rule) offset_rule = if new_rule_location.zero? # The rule will be the first rule in the chain because nothing came # before it. rules[0] else # This rule will come after other managed rules, so find the rule # immediately preceeding it. rules.sort.uniq[new_rule_location - 1] end else # This is a pre-existing rule, so find the offset from the original # ordering. offset_rule = my_rule end # Count how many unmanaged rules are ahead of the target rule so we know # how much to add to the insert order unnamed_offset = rules[0..rules.index(offset_rule)].reduce(0) do |sum, rule| # This regex matches the names given to unmanaged rules (a number # 9000-9999 followed by an MD5 hash). sum + (rule.match(unmanaged_rule_regex) ? 1 : 0) end # We want our rule to come before unmanaged rules if it's not a 9-rule if offset_rule.match(unmanaged_rule_regex) && !my_rule.match(%r{^9}) unnamed_offset -= 1 end # Insert our new or updated rule in the correct order of named rules, but # offset for unnamed rules. rules.reject { |r| r.match(unmanaged_rule_regex) }.sort.index(my_rule) + 1 + unnamed_offset end end puppetlabs-firewall-1.12.0/lib/puppet/provider/firewall.rb0100644005276200011600000000203513207747121020615 0ustar00# # firewall.rb # class Puppet::Provider::Firewall < Puppet::Provider # Prefetch our rule list. This is ran once every time before any other # action (besides initialization of each object). def self.prefetch(resources) debug('[prefetch(resources)]') instances.each do |prov| resource = resources[prov.name] || resources[prov.name.downcase] if resource resource.provider = prov end end end # Look up the current status. This allows us to conventiently look up # existing status with properties[:foo]. def properties if @property_hash.empty? @property_hash = query || { ensure: :absent } @property_hash[:ensure] = :absent if @property_hash.empty? end @property_hash.dup end # Pull the current state of the list from the full list. We're # getting some double entendre here.... def query self.class.instances.each do |instance| if instance.name == name || instance.name.downcase == name return instance.properties end end nil end end puppetlabs-firewall-1.12.0/lib/puppet/provider/firewallchain0040755005276200011600000000000013232340575021217 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/provider/firewallchain/iptables_chain.rb0100644005276200011600000001206613207747121024572 0ustar00Puppet::Type.type(:firewallchain).provide :iptables_chain do include Puppet::Util::Firewall @doc = 'Iptables chain provider' has_feature :iptables_chain has_feature :policy optional_commands(iptables: 'iptables', iptables_save: 'iptables-save', ip6tables: 'ip6tables', ip6tables_save: 'ip6tables-save', ebtables: 'ebtables', ebtables_save: 'ebtables-save') defaultfor kernel: :linux confine kernel: :linux # chain name is greedy so we anchor from the end. # [\d+:\d+] doesn't exist on ebtables MAPPING = { IPv4: { tables: method(:iptables), save: method(:iptables_save), re: %r{^:(.+)\s(\S+)\s\[\d+:\d+\]$}, }, IPv6: { tables: method(:ip6tables), save: method(:ip6tables_save), re: %r{^:(.+)\s(\S+)\s\[\d+:\d+\]$}, }, ethernet: { tables: method(:ebtables), save: method(:ebtables_save), re: %r{^:(.+)\s(\S+)$}, }, }.freeze INTERNAL_CHAINS = %r{^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$} TABLES = 'nat|mangle|filter|raw|rawpost|broute|security'.freeze NAME_FORMAT = %r{^(.+):(#{TABLES}):(IP(v[46])?|ethernet)$} def create allvalidchains do |t, chain, table, protocol| if chain =~ INTERNAL_CHAINS # can't create internal chains warning "Attempting to create internal chain #{@resource[:name]}" end if properties[:ensure] == protocol debug "Skipping Inserting chain #{chain} on table #{table} (#{protocol}) already exists" else debug "Inserting chain #{chain} on table #{table} (#{protocol}) using #{t}" t.call ['-t', table, '-N', chain] unless @resource[:policy].nil? t.call ['-t', table, '-P', chain, @resource[:policy].to_s.upcase] end end end end def destroy allvalidchains do |t, chain, table| if chain =~ INTERNAL_CHAINS # can't delete internal chains warning "Attempting to destroy internal chain #{@resource[:name]}" end debug "Deleting chain #{chain} on table #{table}" t.call ['-t', table, '-X', chain] end end def exists? allvalidchains do |_t, chain| if chain =~ INTERNAL_CHAINS # If the chain isn't present, it's likely because the module isn't loaded. # If this is true, then we fall into 2 cases # 1) It'll be loaded on demand # 2) It won't be loaded on demand, and we throw an error # This is the intended behavior as it's not the provider's job to load kernel modules # So we pretend it exists... return true end end properties[:ensure] == :present end def policy=(value) return if value == :empty allvalidchains do |t, chain, table| p = ['-t', table, '-P', chain, value.to_s.upcase] debug "[set policy] #{t} #{p}" t.call p end end def policy debug "[get policy] #{@resource[:name]} =#{@property_hash[:policy].to_s.downcase}" @property_hash[:policy].to_s.downcase end def self.prefetch(resources) debug('[prefetch(resources)]') instances.each do |prov| resource = resources[prov.name] if resource resource.provider = prov end end end def flush debug('[flush]') persist_iptables(@resource[:name].match(NAME_FORMAT)[3]) # Clear the property hash so we re-initialize with updated values @property_hash.clear end # Look up the current status. This allows us to conventiently look up # existing status with properties[:foo]. def properties if @property_hash.empty? @property_hash = query || { ensure: :absent } end @property_hash.dup end # Pull the current state of the list from the full list. def query self.class.instances.each do |instance| if instance.name == name debug "query found #{name}" % instance.properties.inspect return instance.properties end end nil end def self.instances debug '[instances]' table = nil chains = [] MAPPING.each do |p, c| begin c[:save].call.each_line do |line| if line =~ c[:re] name = Regexp.last_match(1) + ':' + ((table == 'filter') ? 'filter' : table) + ':' + p.to_s policy = (Regexp.last_match(2) == '-') ? nil : Regexp.last_match(2).downcase.to_sym chains << new(name: name, policy: policy, ensure: :present) debug "[instance] '#{name}' #{policy}" elsif line =~ %r{^\*(\S+)} table = Regexp.last_match(1) else next end end rescue Puppet::Error # rubocop:disable Lint/HandleExceptions # ignore command not found for ebtables or anything that doesn't exist end end chains end def allvalidchains @resource[:name].match(NAME_FORMAT) chain = Regexp.last_match(1) table = Regexp.last_match(2) protocol = Regexp.last_match(3) yield MAPPING[protocol.to_sym][:tables], chain, table, protocol.to_sym end end puppetlabs-firewall-1.12.0/lib/puppet/type0040755005276200011600000000000013232340575015536 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/type/firewall.rb0100644005276200011600000016053513232340436017752 0ustar00# See: #10295 for more details. # # This is a workaround for bug: #4248 whereby ruby files outside of the normal # provider/type path do not load until pluginsync has occured on the puppetmaster # # In this case I'm trying the relative path first, then falling back to normal # mechanisms. This should be fixed in future versions of puppet but it looks # like we'll need to maintain this for some time perhaps. $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..')) require 'puppet/util/firewall' Puppet::Type.newtype(:firewall) do include Puppet::Util::Firewall @doc = <<-PUPPETCODE This type provides the capability to manage firewall rules within puppet. **Autorequires:** If Puppet is managing the iptables or ip6tables chains specified in the `chain` or `jump` parameters, the firewall resource will autorequire those firewallchain resources. If Puppet is managing the iptables, iptables-persistent, or iptables-services packages, and the provider is iptables or ip6tables, the firewall resource will autorequire those packages to ensure that any required binaries are installed. PUPPETCODE feature :connection_limiting, 'Connection limiting features.' feature :hop_limiting, 'Hop limiting features.' feature :rate_limiting, 'Rate limiting features.' feature :recent_limiting, 'The netfilter recent module' feature :snat, 'Source NATing' feature :dnat, 'Destination NATing' feature :netmap, 'NET MAPping' feature :interface_match, 'Interface matching' feature :icmp_match, 'Matching ICMP types' feature :owner, 'Matching owners' feature :state_match, 'Matching stateful firewall states' feature :reject_type, 'The ability to control reject messages' feature :log_level, 'The ability to control the log level' feature :log_prefix, 'The ability to add prefixes to log messages' feature :log_uid, 'Add UIDs to log messages' feature :mark, 'Match or Set the netfilter mark value associated with the packet' feature :mss, 'Match a given TCP MSS value or range.' feature :tcp_flags, 'The ability to match on particular TCP flag settings' feature :pkttype, 'Match a packet type' feature :socket, 'Match open sockets' feature :isfragment, 'Match fragments' feature :address_type, 'The ability match on source or destination address type' feature :iprange, 'The ability match on source or destination IP range ' feature :ishasmorefrags, 'Match a non-last fragment of a fragmented ipv6 packet - might be first' feature :islastfrag, 'Match the last fragment of an ipv6 packet' feature :isfirstfrag, 'Match the first fragment of a fragmented ipv6 packet' feature :ipsec_policy, 'Match IPsec policy' feature :ipsec_dir, 'Match IPsec policy direction' feature :mask, 'Ability to match recent rules based on the ipv4 mask' feature :nflog_group, 'netlink group to subscribe to for logging' feature :nflog_prefix, '' feature :nflog_range, '' feature :nflog_threshold, '' 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' feature :hashlimit, 'Hashlimit features' # provider specific features feature :iptables, 'The provider provides iptables features.' ensurable do desc <<-PUPPETCODE Manage the state of this rule. The default action is *present*. PUPPETCODE newvalue(:present) do provider.insert end newvalue(:absent) do provider.delete end defaultto :present end newparam(:name) do desc <<-PUPPETCODE The canonical name of the rule. This name is also used for ordering so make sure you prefix the rule with a number: 000 this runs first 999 this runs last Depending on the provider, the name of the rule can be stored using the comment feature of the underlying firewall subsystem. PUPPETCODE isnamevar # Keep rule names simple - they must start with a number newvalues(%r{^\d+[[:graph:][:space:]]+$}) end newproperty(:action) do desc <<-PUPPETCODE This is the action to perform on a match. Can be one of: * accept - the packet is accepted * reject - the packet is rejected with a suitable ICMP response * drop - the packet is dropped If you specify no value it will simply match the rule but perform no action unless you provide a provider specific parameter (such as *jump*). PUPPETCODE newvalues(:accept, :reject, :drop) end # Generic matching properties newproperty(:source) do desc <<-PUPPETCODE The source address. For example: source => '192.168.2.0/24' You can also negate a mask by putting ! in front. For example: source => '! 192.168.2.0/24' The source can also be an IPv6 address if your provider supports it. PUPPETCODE munge do |value| case @resource[:provider] when :iptables protocol = :IPv4 when :ip6tables protocol = :IPv6 else raise('cannot work out protocol family') end begin @resource.host_to_mask(value, protocol) rescue StandardError => e raise("host_to_ip failed for #{value}, exception #{e}") end end end # Source IP range newproperty(:src_range, required_features: :iprange) do desc <<-PUPPETCODE The source IP range. For example: src_range => '192.168.1.1-192.168.1.10' The source IP range must be in 'IP1-IP2' format. PUPPETCODE validate do |value| matches = %r{^([^\-\/]+)-([^\-\/]+)$}.match(value) raise(ArgumentError, "The source IP range must be in 'IP1-IP2' format.") unless matches start_addr = matches[1] end_addr = matches[2] [start_addr, end_addr].each do |addr| begin @resource.host_to_ip(addr) rescue StandardError raise("Invalid IP address \"#{addr}\" in range \"#{value}\"") end end end end newproperty(:destination) do desc <<-PUPPETCODE The destination address to match. For example: destination => '192.168.1.0/24' You can also negate a mask by putting ! in front. For example: destination => '! 192.168.2.0/24' The destination can also be an IPv6 address if your provider supports it. PUPPETCODE munge do |value| case @resource[:provider] when :iptables protocol = :IPv4 when :ip6tables protocol = :IPv6 else raise('cannot work out protocol family') end begin @resource.host_to_mask(value, protocol) rescue StandardError => e raise("host_to_ip failed for #{value}, exception #{e}") end end end # Destination IP range newproperty(:dst_range, required_features: :iprange) do desc <<-PUPPETCODE The destination IP range. For example: dst_range => '192.168.1.1-192.168.1.10' The destination IP range must be in 'IP1-IP2' format. PUPPETCODE validate do |value| matches = %r{^([^\-\/]+)-([^\-\/]+)$}.match(value) raise(ArgumentError, "The destination IP range must be in 'IP1-IP2' format.") unless matches start_addr = matches[1] end_addr = matches[2] [start_addr, end_addr].each do |addr| begin @resource.host_to_ip(addr) rescue StandardError raise("Invalid IP address \"#{addr}\" in range \"#{value}\"") end end end end newproperty(:sport, array_matching: :all) do desc <<-PUPPETCODE The 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: - For example: 1-1024 This would cover ports 1 to 1024. PUPPETCODE munge do |value| @resource.string_to_port(value, :proto) end def 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(:dport, array_matching: :all) do desc <<-PUPPETCODE The destination 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: - For example: 1-1024 This would cover ports 1 to 1024. PUPPETCODE munge do |value| @resource.string_to_port(value, :proto) end def 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(:port, array_matching: :all) do desc <<-PUPPETCODE DEPRECATED 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: - For example: 1-1024 This would cover ports 1 to 1024. PUPPETCODE validate do |_value| Puppet.warning('Passing port to firewall is deprecated and will be removed. Use dport and/or sport instead.') end munge do |value| @resource.string_to_port(value, :proto) end def 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(:dst_type, required_features: :address_type) do desc <<-PUPPETCODE The destination address type. For example: dst_type => 'LOCAL' Can be one of: * UNSPEC - an unspecified address * UNICAST - a unicast address * LOCAL - a local address * BROADCAST - a broadcast address * ANYCAST - an anycast packet * MULTICAST - a multicast address * BLACKHOLE - a blackhole address * UNREACHABLE - an unreachable address * PROHIBIT - a prohibited address * THROW - undocumented * NAT - undocumented * XRESOLVE - undocumented PUPPETCODE newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].map { |address_type| [address_type, "! #{address_type}".to_sym] }.flatten) end newproperty(:src_type, required_features: :address_type) do desc <<-PUPPETCODE The source address type. For example: src_type => 'LOCAL' Can be one of: * UNSPEC - an unspecified address * UNICAST - a unicast address * LOCAL - a local address * BROADCAST - a broadcast address * ANYCAST - an anycast packet * MULTICAST - a multicast address * BLACKHOLE - a blackhole address * UNREACHABLE - an unreachable address * PROHIBIT - a prohibited address * THROW - undocumented * NAT - undocumented * XRESOLVE - undocumented PUPPETCODE newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].map { |address_type| [address_type, "! #{address_type}".to_sym] }.flatten) end newproperty(:proto) do desc <<-PUPPETCODE The specific protocol to match for this rule. By default this is *tcp*. PUPPETCODE newvalues(*[:ip, :tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :cbt, :sctp, :pim, :all].map { |proto| [proto, "! #{proto}".to_sym] }.flatten) defaultto 'tcp' end # tcp-specific newproperty(:mss) do desc <<-PUPPETCODE Match a given TCP MSS value or range. PUPPETCODE end # tcp-specific newproperty(:tcp_flags, required_features: :tcp_flags) do desc <<-PUPPETCODE Match when the TCP flags are as specified. Is 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 Note that you specify them in the order that iptables --list-rules would list them to avoid having puppet think you changed the flags. Example: FIN,SYN,RST,ACK SYN matches packets with the SYN bit set and the ACK,RST and FIN bits cleared. Such packets are used to request TCP connection initiation. PUPPETCODE end # Iptables specific newproperty(:chain, required_features: :iptables) do desc <<-PUPPETCODE Name of the chain to use. Can be one of the built-ins: * INPUT * FORWARD * OUTPUT * PREROUTING * POSTROUTING Or you can provide a user-based chain. The default value is 'INPUT'. PUPPETCODE defaultto 'INPUT' newvalue(%r{^[a-zA-Z0-9\-_]+$}) end newproperty(:table, required_features: :iptables) do desc <<-PUPPETCODE Table to use. Can be one of: * nat * mangle * filter * raw * rawpost By default the setting is 'filter'. PUPPETCODE newvalues(:nat, :mangle, :filter, :raw, :rawpost) defaultto 'filter' end newproperty(:jump, required_features: :iptables) do desc <<-PUPPETCODE The value for the iptables --jump parameter. Normal values are: * QUEUE * RETURN * DNAT * SNAT * LOG * NFLOG * MASQUERADE * REDIRECT * MARK But any valid chain name is allowed. For the values ACCEPT, DROP and REJECT you must use the generic 'action' parameter. This is to enfore the use of generic parameters where possible for maximum cross-platform modelling. If you set both 'accept' and 'jump' parameters, you will get an error as only one of the options should be set. PUPPETCODE validate do |value| unless value =~ %r{^[a-zA-Z0-9\-_]+$} raise ArgumentError, <<-PUPPETCODE Jump destination must consist of alphanumeric characters, an underscore or a yphen. PUPPETCODE end if %w[accept reject drop].include?(value.downcase) raise ArgumentError, <<-PUPPETCODE Jump destination should not be one of ACCEPT, REJECT or DROP. Use the action property instead. PUPPETCODE end end end newproperty(:goto, required_features: :iptables) do desc <<-PUPPETCODE 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. PUPPETCODE validate do |value| unless value =~ %r{^[a-zA-Z0-9\-_]+$} raise ArgumentError, <<-PUPPETCODE Goto destination must consist of alphanumeric characters, an underscore or a yphen. PUPPETCODE end if %w[accept reject drop].include?(value.downcase) raise ArgumentError, <<-PUPPETCODE Goto destination should not be one of ACCEPT, REJECT or DROP. Use the action property instead. PUPPETCODE end end end # Interface specific matching properties newproperty(:iniface, required_features: :interface_match) do desc <<-PUPPETCODE Input interface to filter on. Supports interface alias like eth0:0. To negate the match try this: iniface => '! lo', PUPPETCODE newvalues(%r{^!?\s?[a-zA-Z0-9\-\._\+\:]+$}) end newproperty(:outiface, required_features: :interface_match) do desc <<-PUPPETCODE Output interface to filter on. Supports interface alias like eth0:0. To negate the match try this: outiface => '! lo', PUPPETCODE newvalues(%r{^!?\s?[a-zA-Z0-9\-\._\+\:]+$}) end # NAT specific properties newproperty(:tosource, required_features: :snat) do desc <<-PUPPETCODE When using jump => "SNAT" you can specify the new source address using this parameter. PUPPETCODE end newproperty(:todest, required_features: :dnat) do desc <<-PUPPETCODE When using jump => "DNAT" you can specify the new destination address using this paramter. PUPPETCODE end newproperty(:toports, required_features: :dnat) do desc <<-PUPPETCODE For DNAT this is the port that will replace the destination port. PUPPETCODE end newproperty(:to, required_features: :netmap) do desc <<-PUPPETCODE For NETMAP this will replace the destination IP PUPPETCODE end newproperty(:random, required_features: :dnat) do desc <<-PUPPETCODE When using a jump value of "MASQUERADE", "DNAT", "REDIRECT", or "SNAT" this boolean will enable randomized port mapping. PUPPETCODE newvalues(:true, :false) end # Reject ICMP type newproperty(:reject, required_features: :reject_type) do desc <<-PUPPETCODE When combined with jump => "REJECT" you can specify a different icmp response to be sent back to the packet sender. PUPPETCODE end # Logging properties newproperty(:log_level, required_features: :log_level) do desc <<-PUPPETCODE When combined with jump => "LOG" specifies the system log level to log to. PUPPETCODE munge do |value| if value.is_a?(String) value = @resource.log_level_name_to_number(value) else value end if value.nil? && value != '' raise('Unable to determine log level') end value end end newproperty(:log_prefix, required_features: :log_prefix) do desc <<-PUPPETCODE When combined with jump => "LOG" specifies the log prefix to use when logging. PUPPETCODE end newproperty(:log_uid, required_features: :log_uid) do desc <<-PUPPETCODE When combined with jump => "LOG" specifies the uid of the process making the connection. PUPPETCODE newvalues(:true, :false) end newproperty(:nflog_group, required_features: :nflog_group) do desc <<-PUPPETCODE Used with the jump target NFLOG. The netlink group (0 - 2^16-1) to which packets are (only applicable for nfnetlink_log). Defaults to 0. PUPPETCODE validate do |value| if value.to_i > (2**16) - 1 || value.to_i < 0 raise ArgumentError, 'nflog_group must be between 0 and 2^16-1' end end munge do |value| if value.is_a?(String) && value =~ %r{^[-0-9]+$} Integer(value) else value end end end newproperty(:nflog_prefix, required_features: :nflog_prefix) do desc <<-PUPPETCODE Used with the jump target NFLOG. A prefix string to include in the log message, up to 64 characters long, useful for distinguishing messages in the logs. PUPPETCODE validate do |value| if value.length > 64 raise ArgumentError, 'nflog_prefix must be less than 64 characters.' end end end newproperty(:nflog_range, required_features: :nflog_range) do desc <<-PUPPETCODE Used with the jump target NFLOG. The number of bytes to be copied to userspace (only applicable for nfnetlink_log). nfnetlink_log instances may specify their own range, this option overrides it. PUPPETCODE end newproperty(:nflog_threshold, required_features: :nflog_threshold) do desc <<-PUPPETCODE Used with the jump target NFLOG. Number of packets to queue inside the kernel before sending them to userspace (only applicable for nfnetlink_log). Higher values result in less overhead per packet, but increase delay until the packets reach userspace. Defaults to 1. PUPPETCODE munge do |value| if value.is_a?(String) && value =~ %r{^[-0-9]+$} Integer(value) else value end end end # ICMP matching property newproperty(:icmp, required_features: :icmp_match) do desc <<-PUPPETCODE When matching ICMP packets, this is the type of ICMP packet to match. A value of "any" is not supported. To achieve this behaviour the parameter should simply be omitted or undefined. An array of values is also not supported. To match against multiple ICMP types, please use separate rules for each ICMP type. PUPPETCODE validate do |value| if value == 'any' raise ArgumentError, "Value 'any' is not valid. This behaviour should be achieved " \ 'by omitting or undefining the ICMP parameter.' end if value.is_a?(Array) raise ArgumentError, 'Argument must not be an array of values. To match multiple ' \ 'ICMP types, please use separate rules for each ICMP type.' end end munge do |value| if value.is_a?(String) # ICMP codes differ between IPv4 and IPv6. case @resource[:provider] when :iptables protocol = 'inet' when :ip6tables protocol = 'inet6' else raise('cannot work out protocol family') end value = @resource.icmp_name_to_number(value, protocol) else value end if value.nil? && value != '' raise('cannot work out icmp type') end value end end newproperty(:state, array_matching: :all, required_features: :state_match) do desc <<-PUPPETCODE Matches a packet based on its state in the firewall stateful inspection table. Values can be: * INVALID * ESTABLISHED * NEW * RELATED * UNTRACKED PUPPETCODE newvalues(:INVALID, :ESTABLISHED, :NEW, :RELATED, :UNTRACKED) # States should always be sorted. This normalizes the resource states to # keep it consistent with the sorted result from iptables-save. def should=(values) @should = super(values).sort_by { |sym| sym.to_s } end def 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(:ctstate, array_matching: :all, required_features: :state_match) do desc <<-PUPPETCODE Matches a packet based on its state in the firewall stateful inspection table, using the conntrack module. Values can be: * INVALID * ESTABLISHED * NEW * RELATED * UNTRACKED PUPPETCODE newvalues(:INVALID, :ESTABLISHED, :NEW, :RELATED, :UNTRACKED) # States should always be sorted. This normalizes the resource states to # keep it consistent with the sorted result from iptables-save. def should=(values) @should = super(values).sort_by { |sym| sym.to_s } end def to_s?(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end # Connection mark newproperty(:connmark, required_features: :mark) do desc <<-PUPPETCODE Match the Netfilter mark value associated with the packet. Accepts either of: mark/mask or mark. These will be converted to hex if they are not already. PUPPETCODE munge do |value| int_or_hex = '[a-fA-F0-9x]' match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?") mark = @resource.to_hex32(match[1]) # Values that can't be converted to hex. # Or contain a trailing slash with no mask. if mark.nil? || (mark && match[2] && match[3].nil?) raise ArgumentError, 'MARK value must be integer or hex between 0 and 0xffffffff' end # There should not be a mask on connmark unless match[3].nil? raise ArgumentError, 'iptables does not support masks on MARK match rules' end value = mark value end end # Connection limiting properties newproperty(:connlimit_above, required_features: :connection_limiting) do desc <<-PUPPETCODE Connection limiting value for matched connections above n. PUPPETCODE newvalue(%r{^\d+$}) end newproperty(:connlimit_mask, required_features: :connection_limiting) do desc <<-PUPPETCODE Connection limiting by subnet mask for matched connections. IPv4: 0-32 IPv6: 0-128 PUPPETCODE newvalue(%r{^\d+$}) end # Hop limiting properties newproperty(:hop_limit, required_features: :hop_limiting) do desc <<-PUPPETCODE Hop limiting value for matched packets. PUPPETCODE newvalue(%r{^\d+$}) end # Rate limiting properties newproperty(:limit, required_features: :rate_limiting) do desc <<-PUPPETCODE 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'." PUPPETCODE end newproperty(:burst, required_features: :rate_limiting) do desc <<-PUPPETCODE Rate limiting burst value (per second) before limit checks apply. PUPPETCODE newvalue(%r{^\d+$}) end newproperty(:uid, required_features: :owner) do desc <<-PUPPETCODE UID or Username owner matching rule. Accepts a string argument only, as iptables does not accept multiple uid in a single statement. PUPPETCODE def insync?(is) require 'etc' # The following code allow us to take into consideration unix mappings # between string usernames and UIDs (integers). We also need to ignore # spaces as they are irrelevant with respect to rule sync. # Remove whitespace is = is.gsub(%r{\s+}, '') should = @should.first.to_s.gsub(%r{\s+}, '') # Keep track of negation, but remove the '!' is_negate = '' should_negate = '' if is.start_with?('!') is = is.gsub(%r{^!}, '') is_negate = '!' end if should.start_with?('!') should = should.gsub(%r{^!}, '') should_negate = '!' end # If 'should' contains anything other than digits, # we assume that we have to do a lookup to convert # to UID unless should[%r{[0-9]+}] == should should = Etc.getpwnam(should).uid end # If 'is' contains anything other than digits, # we assume that we have to do a lookup to convert # to UID unless is[%r{[0-9]+}] == is is = Etc.getpwnam(is).uid end "#{is_negate}#{is}" == "#{should_negate}#{should}" end end newproperty(:gid, required_features: :owner) do desc <<-PUPPETCODE GID or Group owner matching rule. Accepts a string argument only, as iptables does not accept multiple gid in a single statement. PUPPETCODE def insync?(is) require 'etc' # The following code allow us to take into consideration unix mappings # between string group names and GIDs (integers). We also need to ignore # spaces as they are irrelevant with respect to rule sync. # Remove whitespace is = is.gsub(%r{\s+}, '') should = @should.first.to_s.gsub(%r{\s+}, '') # Keep track of negation, but remove the '!' is_negate = '' should_negate = '' if is.start_with?('!') is = is.gsub(%r{^!}, '') is_negate = '!' end if should.start_with?('!') should = should.gsub(%r{^!}, '') should_negate = '!' end # If 'should' contains anything other than digits, # we assume that we have to do a lookup to convert # to UID unless should[%r{[0-9]+}] == should should = Etc.getgrnam(should).gid end # If 'is' contains anything other than digits, # we assume that we have to do a lookup to convert # to UID unless is[%r{[0-9]+}] == is is = Etc.getgrnam(is).gid end "#{is_negate}#{is}" == "#{should_negate}#{should}" end end # match mark newproperty(:match_mark, required_features: :mark) do desc <<-PUPPETCODE Match the Netfilter mark value associated with the packet. Accepts either of: mark/mask or mark. These will be converted to hex if they are not already. PUPPETCODE munge do |value| mark_regex = %r{\A((?:0x)?[0-9A-F]+)(/)?((?:0x)?[0-9A-F]+)?\z}i match = value.to_s.match(mark_regex) if match.nil? raise ArgumentError, 'Match MARK value must be integer or hex between 0 and 0xffffffff' end mark = @resource.to_hex32(match[1]) # Values that can't be converted to hex. # Or contain a trailing slash with no mask. if mark.nil? || (mark && match[2] && match[3].nil?) raise ArgumentError, 'Match MARK value must be integer or hex between 0 and 0xffffffff' end # There should not be a mask on match_mark unless match[3].nil? raise ArgumentError, 'iptables does not support masks on MARK match rules' end value = mark value end end newproperty(:set_mark, required_features: :mark) do desc <<-PUPPETCODE Set the Netfilter mark value associated with the packet. Accepts either of: mark/mask or mark. These will be converted to hex if they are not already. PUPPETCODE munge do |value| int_or_hex = '[a-fA-F0-9x]' match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?") mark = @resource.to_hex32(match[1]) # Values that can't be converted to hex. # Or contain a trailing slash with no mask. if mark.nil? || (mark && match[2] && match[3].nil?) raise ArgumentError, 'MARK value must be integer or hex between 0 and 0xffffffff' end # Old iptables does not support a mask. New iptables will expect one. iptables_version = Facter.value('iptables_version') mask_required = (iptables_version && Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') >= 0) if mask_required if match[3].nil? value = "#{mark}/0xffffffff" else mask = @resource.to_hex32(match[3]) if mask.nil? raise ArgumentError, 'MARK mask must be integer or hex between 0 and 0xffffffff' end value = "#{mark}/#{mask}" end else unless match[3].nil? raise ArgumentError, "iptables version #{iptables_version} does not support masks on MARK rules" end value = mark end value end end newproperty(:clamp_mss_to_pmtu, required_features: :iptables) do desc <<-PUPPETCODE Sets the clamp mss to pmtu flag. PUPPETCODE newvalues(:true, :false) end newproperty(:set_dscp, required_features: :iptables) do desc <<-PUPPETCODE Set DSCP Markings. PUPPETCODE end newproperty(:set_dscp_class, required_features: :iptables) do desc <<-PUPPETCODE This sets the DSCP field according to a predefined DiffServ class. PUPPETCODE # iptables uses the cisco DSCP classes as the basis for this flag. Values may be found here: # 'http://www.cisco.com/c/en/us/support/docs/quality-of-service-qos/qos-packet-marking/10103-dscpvalues.html' valid_codes = %w[ af11 af12 af13 af21 af22 af23 af31 af32 af33 af41 af42 af43 cs1 cs2 cs3 cs4 cs5 cs6 cs7 ef ] munge do |value| unless valid_codes.include? value.downcase raise ArgumentError, "#{value} is not a valid DSCP Class" end value.downcase end end newproperty(:set_mss, required_features: :iptables) do desc <<-PUPPETCODE Sets the TCP MSS value for packets. PUPPETCODE end newproperty(:pkttype, required_features: :pkttype) do desc <<-PUPPETCODE Sets the packet type to match. PUPPETCODE newvalues(:unicast, :broadcast, :multicast) end newproperty(:isfragment, required_features: :isfragment) do desc <<-PUPPETCODE Set to true to match tcp fragments (requires type to be set to tcp) PUPPETCODE newvalues(:true, :false) end newproperty(:recent, required_features: :recent_limiting) do desc <<-PUPPETCODE Enable the recent module. Takes as an argument one of set, update, rcheck or remove. For example: # If anyone's appeared on the 'badguy' blacklist within # the last 60 seconds, drop their traffic, and update the timestamp. firewall { '100 Drop badguy traffic': recent => 'update', rseconds => 60, rsource => true, rname => 'badguy', action => 'DROP', chain => 'FORWARD', } # No-one should be sending us traffic on eth0 from localhost # Blacklist them firewall { '101 blacklist strange traffic': recent => 'set', rsource => true, rname => 'badguy', destination => '127.0.0.0/8', iniface => 'eth0', action => 'DROP', chain => 'FORWARD', } PUPPETCODE newvalues(:set, :update, :rcheck, :remove) munge do |value| _value = '--' + value end end newproperty(:rdest, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; add the destination IP address to the list. Must be boolean true. PUPPETCODE newvalues(:true, :false) end newproperty(:rsource, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; add the source IP address to the list. Must be boolean true. PUPPETCODE newvalues(:true, :false) end newproperty(:rname, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; The name of the list. Takes a string argument. PUPPETCODE end newproperty(:rseconds, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; used in conjunction with one of `recent => 'rcheck'` or `recent => 'update'`. When used, this will narrow the match to only happen when the address is in the list and was seen within the last given number of seconds. PUPPETCODE end newproperty(:reap, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; can only be used in conjunction with the `rseconds` attribute. When used, this will cause entries older than 'seconds' to be purged. Must be boolean true. PUPPETCODE newvalues(:true, :false) end newproperty(:rhitcount, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; used in conjunction with `recent => 'update'` or `recent => 'rcheck'. When used, this will narrow the match to only happen when the address is in the list and packets had been received greater than or equal to the given value. PUPPETCODE end newproperty(:rttl, required_features: :recent_limiting) do desc <<-PUPPETCODE Recent module; may only be used in conjunction with one of `recent => 'rcheck'` or `recent => 'update'`. When used, this will narrow the match to only happen when the address is in the list and the TTL of the current packet matches that of the packet which hit the `recent => 'set'` rule. This may be useful if you have problems with people faking their source address in order to DoS you via this module by disallowing others access to your site by sending bogus packets to you. Must be boolean true. PUPPETCODE newvalues(:true, :false) end newproperty(:socket, required_features: :socket) do desc <<-PUPPETCODE If true, matches if an open socket can be found by doing a coket lookup on the packet. PUPPETCODE newvalues(:true, :false) end newproperty(:ishasmorefrags, required_features: :ishasmorefrags) do desc <<-PUPPETCODE If true, matches if the packet has it's 'more fragments' bit set. ipv6. PUPPETCODE newvalues(:true, :false) end newproperty(:islastfrag, required_features: :islastfrag) do desc <<-PUPPETCODE If true, matches if the packet is the last fragment. ipv6. PUPPETCODE newvalues(:true, :false) end newproperty(:isfirstfrag, required_features: :isfirstfrag) do desc <<-PUPPETCODE If true, matches if the packet is the first fragment. Sadly cannot be negated. ipv6. PUPPETCODE newvalues(:true, :false) end newproperty(:ipsec_policy, required_features: :ipsec_policy) do desc <<-PUPPETCODE Sets the ipsec policy type. May take a combination of arguments for any flags that can be passed to `--pol ipsec` such as: `--strict`, `--reqid 100`, `--next`, `--proto esp`, etc. PUPPETCODE newvalues(:none, :ipsec) end newproperty(:ipsec_dir, required_features: :ipsec_dir) do desc <<-PUPPETCODE Sets the ipsec policy direction PUPPETCODE newvalues(:in, :out) end newproperty(:stat_mode) do desc <<-PUPPETCODE Set the matching mode for statistic matching. Supported modes are `random` and `nth`. PUPPETCODE newvalues(:nth, :random) end newproperty(:stat_every) do desc <<-PUPPETCODE Match one packet every nth packet. Requires `stat_mode => 'nth'` PUPPETCODE validate do |value| unless value =~ %r{^\d+$} raise ArgumentError, <<-PUPPETCODE stat_every value must be a digit PUPPETCODE end unless value.to_i > 0 raise ArgumentError, <<-PUPPETCODE stat_every value must be larger than 0 PUPPETCODE end end end newproperty(:stat_packet) do desc <<-PUPPETCODE Set the initial counter value for the nth mode. Must be between 0 and the value of `stat_every`. Defaults to 0. Requires `stat_mode => 'nth'` PUPPETCODE newvalues(%r{^\d+$}) end newproperty(:stat_probability) do desc <<-PUPPETCODE Set the probability from 0 to 1 for a packet to be randomly matched. It works only with `stat_mode => 'random'`. PUPPETCODE validate do |value| unless value =~ %r{^([01])\.(\d+)$} raise ArgumentError, <<-PUPPETCODE stat_probability must be between 0.0 and 1.0 PUPPETCODE end if Regexp.last_match(1).to_i == 1 && Regexp.last_match(2).to_i != 0 raise ArgumentError, <<-PUPPETCODE start_probability must be between 0.0 and 1.0 PUPPETCODE end end end newproperty(:mask, required_features: :mask) do desc <<-PUPPETCODE Sets the mask to use when `recent` is enabled. PUPPETCODE end newproperty(:gateway, required_features: :iptables) do desc <<-PUPPETCODE The TEE target will clone a packet and redirect this clone to another machine on the local network segment. gateway is the target host's IP. PUPPETCODE end newproperty(:ipset, required_features: :ipset, array_matching: :all) do desc <<-PUPPETCODE Matches against the specified ipset list. 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' PUPPETCODE def 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 desc <<-PUPPETCODE Compute and fill missing packet checksums. PUPPETCODE newvalues(:true, :false) end newparam(:line) do desc <<-PUPPETCODE Read-only property for caching the rule line. PUPPETCODE end newproperty(:mac_source) do desc <<-PUPPETCODE MAC Source PUPPETCODE newvalues(%r{^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$}i) end newproperty(:physdev_in, required_features: :iptables) do desc <<-PUPPETCODE Match if the packet is entering a bridge from the given interface. PUPPETCODE newvalues(%r{^[a-zA-Z0-9\-\._\+]+$}) end newproperty(:physdev_out, required_features: :iptables) do desc <<-PUPPETCODE Match if the packet is leaving a bridge via the given interface. PUPPETCODE newvalues(%r{^[a-zA-Z0-9\-\._\+]+$}) end newproperty(:physdev_is_bridged, required_features: :iptables) do desc <<-PUPPETCODE Match if the packet is transversing a bridge. PUPPETCODE newvalues(:true, :false) end newproperty(:physdev_is_in, required_features: :iptables) do desc <<-PUPPETCODE Matches if the packet has entered through a bridge interface. PUPPETCODE newvalues(:true, :false) end newproperty(:physdev_is_out, required_features: :iptables) do desc <<-PUPPETCODE Matches if the packet will leave through a bridge interface. PUPPETCODE newvalues(:true, :false) end newproperty(:date_start, required_features: :iptables) do desc <<-PUPPETCODE Only match during the given time, which must be in ISO 8601 "T" notation. The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 PUPPETCODE end newproperty(:date_stop, required_features: :iptables) do desc <<-PUPPETCODE Only match during the given time, which must be in ISO 8601 "T" notation. The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 PUPPETCODE end newproperty(:time_start, required_features: :iptables) do desc <<-PUPPETCODE Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. PUPPETCODE munge do |value| if value =~ %r{^([0-9]):} value = "0#{value}" end if value =~ %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$} value = "#{value}:00" end value end end newproperty(:time_stop, required_features: :iptables) do desc <<-PUPPETCODE Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. PUPPETCODE munge do |value| if value =~ %r{^([0-9]):} value = "0#{value}" end if value =~ %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$} value = "#{value}:00" end value end end newproperty(:month_days, required_features: :iptables) do desc <<-PUPPETCODE Only match on the given days of the month. Possible values are 1 to 31. Note that specifying 31 will of course not match on months which do not have a 31st day; the same goes for 28- or 29-day February. PUPPETCODE validate do |value| month = value.to_i if month >= 1 && month <= 31 value else raise ArgumentError, 'month_days must be in the range of 1-31' end end end newproperty(:week_days, required_features: :iptables) do desc <<-PUPPETCODE Only match on the given weekdays. Possible values are Mon, Tue, Wed, Thu, Fri, Sat, Sun. PUPPETCODE newvalues(:Mon, :Tue, :Wed, :Thu, :Fri, :Sat, :Sun) end newproperty(:time_contiguous, required_features: :iptables) do desc <<-PUPPETCODE When time_stop is smaller than time_start value, match this as a single time period instead distinct intervals. PUPPETCODE newvalues(:true, :false) end newproperty(:kernel_timezone, required_features: :iptables) do desc <<-PUPPETCODE Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations. PUPPETCODE newvalues(:true, :false) end newproperty(:clusterip_new, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Create a new ClusterIP. You always have to set this on the first rule for a given ClusterIP. PUPPETCODE newvalues(:true, :false) end newproperty(:clusterip_hashmode, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Specify the hashing mode. Valid values: sourceip, sourceip-sourceport, sourceip-sourceport-destport. PUPPETCODE newvalues(:sourceip, :'sourceip-sourceport', :'sourceip-sourceport-destport') end newproperty(:clusterip_clustermac, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Specify the ClusterIP MAC address. Has to be a link-layer multicast address. PUPPETCODE newvalues(%r{^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$}i) end newproperty(:clusterip_total_nodes, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Number of total nodes within this cluster. PUPPETCODE newvalues(%r{\d+}) end newproperty(:clusterip_local_node, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Specify the random seed used for hash initialization. PUPPETCODE newvalues(%r{\d+}) end newproperty(:clusterip_hash_init, required_features: :clusterip) do desc <<-PUPPETCODE Used with the CLUSTERIP jump target. Specify the random seed used for hash initialization. PUPPETCODE end newproperty(:length, required_features: :length) do desc <<-PUPPETCODE Sets the length of layer-3 payload to match. PUPPETCODE 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 unless match[3].nil? high = match[3].to_i end if (low < 0 || low > 65_535) || \ (!high.nil? && (high < 0 || high > 65_535 || high < low)) raise ArgumentError, 'Length values must be between 0 and 65535' end value = low.to_s unless high.nil? value << ':' << high.to_s end value end end newproperty(:string, required_features: :string_matching) do desc <<-PUPPETCODE String matching feature. Matches the packet against the pattern given as an argument. PUPPETCODE munge do |value| _value = "'" + value + "'" end end newproperty(:string_algo, required_features: :string_matching) do desc <<-PUPPETCODE String matching feature, pattern matching strategy. PUPPETCODE newvalues(:bm, :kmp) end newproperty(:string_from, required_features: :string_matching) do desc <<-PUPPETCODE String matching feature, offset from which we start looking for any matching. PUPPETCODE end newproperty(:string_to, required_features: :string_matching) do desc <<-PUPPETCODE String matching feature, offset up to which we should scan. PUPPETCODE end newproperty(:queue_num, required_features: :queue_num) do desc <<-PUPPETCODE Used with NFQUEUE jump target. What queue number to send packets to PUPPETCODE 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 > 65_535 || 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 <<-PUPPETCODE Used with NFQUEUE jump target Allow packets to bypass :queue_num if userspace process is not listening PUPPETCODE newvalues(:true, :false) end newproperty(:src_cc) do desc <<-PUPPETCODE src attribute for the module geoip PUPPETCODE newvalues(%r{^[A-Z]{2}(,[A-Z]{2})*$}) end newproperty(:dst_cc) do desc <<-PUPPETCODE dst attribute for the module geoip PUPPETCODE newvalues(%r{^[A-Z]{2}(,[A-Z]{2})*$}) end newproperty(:hashlimit_name) do desc <<-PUPPETCODE The name for the /proc/net/ipt_hashlimit/foo entry. This parameter is required. PUPPETCODE end newproperty(:hashlimit_upto) do desc <<-PUPPETCODE Match if the rate is below or equal to amount/quantum. It is specified either as a number, with an optional time quantum suffix (the default is 3/hour), or as amountb/second (number of bytes per second). This parameter or hashlimit_above is required. Allowed forms are '40','40/second','40/minute','40/hour','40/day'. PUPPETCODE end newproperty(:hashlimit_above) do desc <<-PUPPETCODE Match if the rate is above amount/quantum. This parameter or hashlimit_upto is required. Allowed forms are '40','40/second','40/minute','40/hour','40/day'. PUPPETCODE end newproperty(:hashlimit_burst) do desc <<-PUPPETCODE Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not reached, up to this number; the default is 5. When byte-based rate matching is requested, this option specifies the amount of bytes that can exceed the given rate. This option should be used with caution -- if the entry expires, the burst value is reset too. PUPPETCODE newvalue(%r{^\d+$}) end newproperty(:hashlimit_mode) do desc <<-PUPPETCODE A comma-separated list of objects to take into consideration. If no --hashlimit-mode option is given, hashlimit acts like limit, but at the expensive of doing the hash housekeeping. Allowed values are: srcip, srcport, dstip, dstport PUPPETCODE end newproperty(:hashlimit_srcmask) do desc <<-PUPPETCODE When --hashlimit-mode srcip is used, all source addresses encountered will be grouped according to the given prefix length and the so-created subnet will be subject to hashlimit. prefix must be between (inclusive) 0 and 32. Note that --hashlimit-srcmask 0 is basically doing the same thing as not specifying srcip for --hashlimit-mode, but is technically more expensive. PUPPETCODE end newproperty(:hashlimit_dstmask) do desc <<-PUPPETCODE Like --hashlimit-srcmask, but for destination addresses. PUPPETCODE end newproperty(:hashlimit_htable_size) do desc <<-PUPPETCODE The number of buckets of the hash table PUPPETCODE end newproperty(:hashlimit_htable_max) do desc <<-PUPPETCODE Maximum entries in the hash. PUPPETCODE end newproperty(:hashlimit_htable_expire) do desc <<-PUPPETCODE After how many milliseconds do hash entries expire. PUPPETCODE end newproperty(:hashlimit_htable_gcinterval) do desc <<-PUPPETCODE How many milliseconds between garbage collection intervals. PUPPETCODE end autorequire(:firewallchain) do reqs = [] protocol = nil case value(:provider) when :iptables protocol = 'IPv4' when :ip6tables protocol = 'IPv6' end unless protocol.nil? table = value(:table) [value(:chain), value(:jump)].each do |chain| reqs << "#{chain}:#{table}:#{protocol}" unless chain.nil? || (%w[INPUT OUTPUT FORWARD].include?(chain) && table == :filter) end end reqs end # Classes would be a better abstraction, pending: # http://projects.puppetlabs.com/issues/19001 autorequire(:package) do case value(:provider) when :iptables, :ip6tables %w[iptables iptables-persistent iptables-services] else [] end end autorequire(:service) do case value(:provider) when :iptables, :ip6tables %w[firewalld iptables ip6tables iptables-persistent netfilter-persistent] else [] end end # autobefore is only provided since puppet 4.0 if Puppet::Util::Package.versioncmp(Puppet.version, '4.0') >= 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]') # TODO: this is put here to skip validation if ensure is not set. This # is because there is a revalidation stage called later where the values # are not set correctly. I tried tracing it - but have put in this # workaround instead to skip. Must get to the bottom of this. unless value(:ensure) return end # First we make sure the chains and tables are valid combinations if value(:table).to_s == 'filter' && value(:chain) =~ %r{PREROUTING|POSTROUTING} raise "PREROUTING and POSTROUTING cannot be used in table 'filter'" end if value(:table).to_s == 'nat' && value(:chain) =~ %r{INPUT|FORWARD} raise "INPUT and FORWARD cannot be used in table 'nat'" end if value(:table).to_s == 'raw' && value(:chain) =~ %r{INPUT|FORWARD|POSTROUTING} raise 'INPUT, FORWARD and POSTROUTING cannot be used in table raw' end # Now we analyse the individual properties to make sure they apply to # the correct combinations. if value(:uid) unless value(:chain).to_s =~ %r{OUTPUT|POSTROUTING} raise 'Parameter uid only applies to chains ' \ 'OUTPUT,POSTROUTING' end end if value(:gid) unless value(:chain).to_s =~ %r{OUTPUT|POSTROUTING} raise 'Parameter gid only applies to chains ' \ 'OUTPUT,POSTROUTING' end end if value(:set_mark) unless value(:jump).to_s =~ %r{MARK} && value(:table).to_s =~ %r{mangle} raise 'Parameter set_mark only applies to ' \ 'the mangle table and when jump => MARK' end end if value(:dport) unless value(:proto).to_s =~ %r{tcp|udp|sctp} raise '[%s] Parameter dport only applies to sctp, tcp and udp ' \ 'protocols. Current protocol is [%s] and dport is [%s]' % [value(:name), should(:proto), should(:dport)] end end if value(:jump).to_s == 'DSCP' unless value(:set_dscp) || value(:set_dscp_class) raise 'When using jump => DSCP, the set_dscp or set_dscp_class property is required' end end if value(:jump).to_s == 'TCPMSS' unless value(:set_mss) || value(:clamp_mss_to_pmtu) raise 'When using jump => TCPMSS, the set_mss or clamp_mss_to_pmtu property is required' end end if value(:jump).to_s == 'TEE' unless value(:gateway) raise 'When using jump => TEE, the gateway property is required' end end if value(:jump).to_s == 'DNAT' unless value(:table).to_s =~ %r{nat} raise 'Parameter jump => DNAT only applies to table => nat' end unless value(:todest) raise 'Parameter jump => DNAT must have todest parameter' end end if value(:jump).to_s == 'SNAT' unless value(:table).to_s =~ %r{nat} raise 'Parameter jump => SNAT only applies to table => nat' end unless value(:tosource) raise 'Parameter jump => SNAT must have tosource parameter' end end if value(:jump).to_s == 'MASQUERADE' unless value(:table).to_s =~ %r{nat} raise 'Parameter jump => MASQUERADE only applies to table => nat' end end if value(:log_prefix) || value(:log_level) || value(:log_uid) unless value(:jump).to_s == 'LOG' raise 'Parameter log_prefix, log_level and log_uid require jump => LOG' end end if value(:burst) && !value(:limit) raise 'burst makes no sense without limit' end if value(:action) && value(:jump) raise "Only one of the parameters 'action' and 'jump' can be set" end if value(:connlimit_mask) && !value(:connlimit_above) raise "Parameter 'connlimit_mask' requires 'connlimit_above'" end if value(:mask) && !value(:recent) raise 'Mask can only be set if recent is enabled.' end [:stat_packet, :stat_every, :stat_probability].each do |param| if value(param) && !value(:stat_mode) raise "Parameter '#{param}' requires 'stat_mode' to be set" end end if value(:stat_packet) && value(:stat_mode) != :nth raise "Parameter 'stat_packet' requires 'stat_mode' to be set to 'nth'" end if value(:stat_every) && value(:stat_mode) != :nth raise "Parameter 'stat_every' requires 'stat_mode' to be set to 'nth'" end if value(:stat_probability) && value(:stat_mode) != :random raise "Parameter 'stat_probability' requires 'stat_mode' to be set to 'random'" end if value(:checksum_fill) unless value(:jump).to_s == 'CHECKSUM' && value(:table).to_s == 'mangle' raise 'Parameter checksum_fill requires jump => CHECKSUM and table => mangle' end end if value(:queue_num) || value(:queue_bypass) unless value(:jump).to_s == 'NFQUEUE' raise 'Paramter queue_number and queue_bypass require jump => NFQUEUE' end end if value(:hashlimit_name) unless value(:hashlimit_upto) || value(:hashlimit_above) raise 'Either hashlimit_upto or hashlimit_above are required' end end end end puppetlabs-firewall-1.12.0/lib/puppet/type/firewallchain.rb0100644005276200011600000002107413232340436020747 0ustar00# This is a workaround for bug: #4248 whereby ruby files outside of the normal # provider/type path do not load until pluginsync has occured on the puppetmaster # # In this case I'm trying the relative path first, then falling back to normal # mechanisms. This should be fixed in future versions of puppet but it looks # like we'll need to maintain this for some time perhaps. $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..')) require 'puppet/util/firewall' Puppet::Type.newtype(:firewallchain) do include Puppet::Util::Firewall @doc = <<-PUPPETCODE This type provides the capability to manage rule chains for firewalls. Currently this supports only iptables, ip6tables and ebtables on Linux. And provides support for setting the default policy on chains and tables that allow it. **Autorequires:** If Puppet is managing the iptables, iptables-persistent, or iptables-services packages, and the provider is iptables_chain, the firewall resource will autorequire those packages to ensure that any required binaries are installed. PUPPETCODE feature :iptables_chain, 'The provider provides iptables chain features.' feature :policy, 'Default policy (inbuilt chains only)' ensurable do defaultvalues defaultto :present end newparam(:name) do desc <<-PUPPETCODE The canonical name of the chain. For iptables the format must be {chain}:{table}:{protocol}. PUPPETCODE isnamevar validate do |value| if value !~ NAME_FORMAT raise ArgumentError, 'Inbuilt chains must be in the form {chain}:{table}:{protocol} where {table} is one of FILTER,' \ ' NAT, MANGLE, RAW, RAWPOST, BROUTE, SECURITY or empty (alias for filter), chain can be anything without colons' \ ' or one of PREROUTING, POSTROUTING, BROUTING, INPUT, FORWARD, OUTPUT for the inbuilt chains, and {protocol} being' \ " IPv4, IPv6, ethernet (ethernet bridging) got '#{value}' table:'#{Regexp.last_match(1)}' chain:'#{Regexp.last_match(2)}' protocol:'#{Regexp.last_match(3)}'" else chain = Regexp.last_match(1) table = Regexp.last_match(2) protocol = Regexp.last_match(3) case table when 'filter' if chain =~ %r{^(PREROUTING|POSTROUTING|BROUTING)$} raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'filter'" end when 'mangle' if chain =~ INTERNAL_CHAINS && chain == 'BROUTING' raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, FORWARD and OUTPUT are the only inbuilt chains that can be used in table 'mangle'" end when 'nat' if chain =~ %r{^(BROUTING|FORWARD)$} raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, and OUTPUT are the only inbuilt chains that can be used in table 'nat'" end if Gem::Version.new(Facter['kernelmajversion'].value.dup) < Gem::Version.new('3.7') && protocol =~ %r{^(IP(v6)?)?$} raise ArgumentError, "table nat isn't valid in IPv6. You must specify ':IPv4' as the name suffix" end when 'raw' if chain =~ %r{^(POSTROUTING|BROUTING|INPUT|FORWARD)$} raise ArgumentError, 'PREROUTING and OUTPUT are the only inbuilt chains in the table \'raw\'' end when 'broute' if protocol != 'ethernet' raise ArgumentError, 'BROUTE is only valid with protocol \'ethernet\'' end if chain =~ %r{^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$} raise ArgumentError, 'BROUTING is the only inbuilt chain allowed on on table \'broute\'' end when 'security' if chain =~ %r{^(PREROUTING|POSTROUTING|BROUTING)$} raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'security'" end end if chain == 'BROUTING' && (protocol != 'ethernet' || table != 'broute') raise ArgumentError, 'BROUTING is the only inbuilt chain allowed on on table \'BROUTE\' with protocol \'ethernet\' i.e. \'broute:BROUTING:enternet\'' end end end end newproperty(:policy) do desc <<-PUPPETCODE This is the action to when the end of the chain is reached. It can only be set on inbuilt chains (INPUT, FORWARD, OUTPUT, PREROUTING, POSTROUTING) and can be one of: * accept - the packet is accepted * drop - the packet is dropped * queue - the packet is passed userspace * return - the packet is returned to calling (jump) queue or the default of inbuilt chains PUPPETCODE newvalues(:accept, :drop, :queue, :return) defaultto do # ethernet chain have an ACCEPT default while other haven't got an # allowed value if @resource[:name] =~ %r{:ethernet$} :accept else nil end end end newparam(:purge, boolean: true) do desc <<-PUPPETCODE Purge unmanaged firewall rules in this chain PUPPETCODE newvalues(false, true) defaultto false end newparam(:ignore) do desc <<-PUPPETCODE Regex to perform on firewall rules to exempt unmanaged rules from purging (when enabled). This is matched against the output of `iptables-save`. This can be a single regex, or an array of them. To support flags, use the ruby inline flag mechanism. Meaning a regex such as /foo/i can be written as '(?i)foo' or '(?i:foo)' Full example: firewallchain { 'INPUT:filter:IPv4': purge => true, ignore => [ '-j fail2ban-ssh', # ignore the fail2ban jump rule '--comment "[^"]*(?i:ignore)[^"]*"', # ignore any rules with "ignore" (case insensitive) in the comment in the rule ], } PUPPETCODE validate do |value| unless value.is_a?(Array) || value.is_a?(String) || value == false devfail 'Ignore must be a string or an Array' end end munge do |patterns| # convert into an array of {Regex}es patterns = [patterns] if patterns.is_a?(String) patterns.map { |p| Regexp.new(p) } end end # Classes would be a better abstraction, pending: # http://projects.puppetlabs.com/issues/19001 autorequire(:package) do case value(:provider) when :iptables_chain %w[iptables iptables-persistent iptables-services] else [] end end autorequire(:service) do case value(:provider) when :iptables, :ip6tables %w[firewalld iptables ip6tables iptables-persistent netfilter-persistent] else [] end end validate do debug('[validate]') value(:name).match(NAME_FORMAT) chain = Regexp.last_match(1) table = Regexp.last_match(2) protocol = Regexp.last_match(3) # Check that we're not removing an internal chain if chain =~ INTERNAL_CHAINS && value(:ensure) == :absent raise 'Cannot remove in-built chains' end if value(:policy).nil? && protocol == 'ethernet' raise 'you must set a non-empty policy on all ethernet table chains' end # Check that we're not setting a policy on a user chain if chain !~ INTERNAL_CHAINS && !value(:policy).nil? && protocol != 'ethernet' raise "policy can only be set on in-built chains (with the exception of ethernet chains) (table:#{table} chain:#{chain} protocol:#{protocol})" end # no DROP policy on nat table if table == 'nat' && value(:policy) == :drop raise 'The "nat" table is not intended for filtering, the use of DROP is therefore inhibited' end end def generate return [] unless purge? value(:name).match(NAME_FORMAT) chain = Regexp.last_match(1) table = Regexp.last_match(2) protocol = Regexp.last_match(3) provider = case protocol when 'IPv4' :iptables when 'IPv6' :ip6tables end # gather a list of all rules present on the system rules_resources = Puppet::Type.type(:firewall).instances # Keep only rules in this chain rules_resources.delete_if { |res| (res[:provider] != provider || res.provider.properties[:table].to_s != table || res.provider.properties[:chain] != chain) } # Remove rules which match our ignore filter rules_resources.delete_if { |res| value(:ignore).find_index { |f| res.provider.properties[:line].match(f) } } if value(:ignore) # We mark all remaining rules for deletion, and then let the catalog override us on rules which should be present rules_resources.each { |res| res[:ensure] = :absent } rules_resources end end puppetlabs-firewall-1.12.0/lib/puppet/util0040755005276200011600000000000013232340575015532 5ustar00puppetlabs-firewall-1.12.0/lib/puppet/util/firewall.rb0100644005276200011600000002007113207747121017740 0ustar00require 'socket' require 'resolv' require 'puppet/util/ipcidr' # Util module for puppetlabs-firewall module Puppet::Util::Firewall # Translate the symbolic names for icmp packet types to integers def icmp_name_to_number(value_icmp, protocol) if value_icmp =~ %r{\d{1,2}$} value_icmp elsif protocol == 'inet' case value_icmp when 'echo-reply' then '0' when 'destination-unreachable' then '3' when 'source-quench' then '4' when 'redirect' then '6' when 'echo-request' then '8' when 'router-advertisement' then '9' when 'router-solicitation' then '10' when 'time-exceeded' then '11' when 'parameter-problem' then '12' when 'timestamp-request' then '13' when 'timestamp-reply' then '14' when 'address-mask-request' then '17' when 'address-mask-reply' then '18' else nil end elsif protocol == 'inet6' case value_icmp when 'destination-unreachable' then '1' when 'too-big' then '2' when 'time-exceeded' then '3' when 'parameter-problem' then '4' when 'echo-request' then '128' when 'echo-reply' then '129' when 'router-solicitation' then '133' when 'router-advertisement' then '134' when 'neighbour-solicitation' then '135' when 'neighbour-advertisement' then '136' when 'redirect' then '137' else nil end else raise ArgumentError, "unsupported protocol family '#{protocol}'" end end # Convert log_level names to their respective numbers def log_level_name_to_number(value) # TODO: make this 0-7 only if value =~ %r{\d} value else case value when 'panic' then '0' when 'alert' then '1' when 'crit' then '2' when 'err' then '3' when 'error' then '3' when 'warn' then '4' when 'warning' then '4' when 'not' then '5' when 'notice' then '5' when 'info' then '6' when 'debug' then '7' else nil end end end # This method takes a string and a protocol and attempts to convert # it to a port number if valid. # # If the string already contains a port number or perhaps a range of ports # in the format 22:1000 for example, it simply returns the string and does # nothing. def string_to_port(value, proto) proto = proto.to_s unless proto =~ %r{^(tcp|udp)$} proto = 'tcp' end m = value.to_s.match(%r{^(!\s+)?(\S+)}) return "#{m[1]}#{m[2]}" if m[2] =~ %r{^\d+(-\d+)?$} "#{m[1]}#{Socket.getservbyname(m[2], proto)}" end # Takes an address and protocol and returns the address in CIDR notation. # # The protocol is only used when the address is a hostname. # # If the address is: # # - A hostname: # It will be resolved # - An IPv4 address: # It will be qualified with a /32 CIDR notation # - An IPv6 address: # It will be qualified with a /128 CIDR notation # - An IP address with a CIDR notation: # It will be normalised # - An IP address with a dotted-quad netmask: # It will be converted to CIDR notation # - Any address with a resulting prefix length of zero: # It will return nil which is equivilent to not specifying an address # def host_to_ip(value, proto = nil) begin value = Puppet::Util::IPCidr.new(value) rescue family = case proto when :IPv4 Socket::AF_INET when :IPv6 Socket::AF_INET6 when nil raise ArgumentError, 'Proto must be specified for a hostname' else raise ArgumentError, "Unsupported address family: #{proto}" end new_value = nil Resolv.each_address(value) do |addr| begin new_value = Puppet::Util::IPCidr.new(addr, family) break rescue # rubocop:disable Lint/HandleExceptions end end raise "Failed to resolve hostname #{value}" if new_value.nil? value = new_value end return nil if value.prefixlen.zero? value.cidr end # Takes an address mask and protocol and converts the host portion to CIDR # notation. # # This takes into account you can negate a mask but follows all rules # defined in host_to_ip for the host/address part. # def host_to_mask(value, proto) match = value.match %r{(!)\s?(.*)$} return host_to_ip(value, proto) unless match cidr = host_to_ip(match[2], proto) return nil if cidr.nil? "#{match[1]} #{cidr}" end # Validates the argument is int or hex, and returns valid hex # conversion of the value or nil otherwise. def to_hex32(value) begin value = Integer(value) if value.between?(0, 0xffffffff) return '0x' + value.to_s(16) end rescue ArgumentError # rubocop:disable Lint/HandleExceptions # pass end nil end def persist_iptables(proto) debug('[persist_iptables]') # 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', 'VirtuozzoLinux' 'RedHat' when 'Debian', 'Ubuntu' 'Debian' else Facter.value(:operatingsystem) end # Older iptables-persistent doesn't provide save action. if os_key == 'Debian' # We need to call flush to clear Facter cache as it's possible the cached value will be nil due to the fact # that the iptables-persistent package was potentially installed after the initial Fact gathering. Facter.fact(:iptables_persistent_version).flush persist_ver = Facter.value(:iptables_persistent_version) if persist_ver && Puppet::Util::Package.versioncmp(persist_ver, '0.5.0') < 0 os_key = 'Debian_manual' end end # Fedora 15 and newer use systemd to persist iptable rules if os_key == 'RedHat' && Facter.value(:operatingsystem) == 'Fedora' && Facter.value(:operatingsystemrelease).to_i >= 15 os_key = 'Fedora' end # RHEL 7 and newer also use systemd to persist iptable rules if os_key == 'RedHat' && %w[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 cmd = case os_key.to_sym when :RedHat case proto.to_sym when :IPv4 %w[/sbin/service iptables save] when :IPv6 %w[/sbin/service ip6tables save] end when :Fedora case proto.to_sym when :IPv4 %w[/usr/libexec/iptables/iptables.init save] when :IPv6 %w[/usr/libexec/iptables/ip6tables.init save] end when :Debian case proto.to_sym when :IPv4, :IPv6 if persist_ver && Puppet::Util::Package.versioncmp(persist_ver, '1.0') > 0 %w[/usr/sbin/service netfilter-persistent save] else %w[/usr/sbin/service iptables-persistent save] end end when :Debian_manual case proto.to_sym when :IPv4 ['/bin/sh', '-c', '/sbin/iptables-save > /etc/iptables/rules'] end when :Archlinux case proto.to_sym when :IPv4 ['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules'] when :IPv6 ['/bin/sh', '-c', '/usr/sbin/ip6tables-save > /etc/iptables/ip6tables.rules'] end end # Catch unsupported OSs from the case statement above. if cmd.nil? debug('firewall: Rule persistence is not supported for this type/OS') return end begin execute(cmd) rescue Puppet::ExecutionFailure => detail warning("Unable to persist firewall rules: #{detail}") end end end puppetlabs-firewall-1.12.0/lib/puppet/util/ipcidr.rb0100644005276200011600000000150213207747121017403 0ustar00 require 'ipaddr' module Puppet::Util # IPCidr object wrapper for IPAddr class IPCidr < IPAddr def initialize(ipaddr, family = Socket::AF_UNSPEC) super(ipaddr, family) rescue ArgumentError => e raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}" if e.message =~ %r{invalid address} raise e end def netmask _to_string(@mask_addr) end def prefixlen m = case @family when Socket::AF_INET IN4MASK when Socket::AF_INET6 IN6MASK else raise 'unsupported address family' end return Regexp.last_match(1).length if %r{\A(1*)(0*)\z} =~ (@mask_addr & m).to_s(2) raise 'bad addr_mask format' end def cidr cidr = '%s/%s' % [to_s, prefixlen] cidr end end end puppetlabs-firewall-1.12.0/locales0040755005276200011600000000000013232340576014115 5ustar00puppetlabs-firewall-1.12.0/locales/config.yaml0100644005276200011600000000205013202542071016306 0ustar00--- # This is the project-specific configuration file for setting up # fast_gettext for your project. gettext: # This is used for the name of the .pot and .po files; they will be # called .pot? project_name: puppetlabs-firewall # This is used in comments in the .pot and .po files to indicate what # project the files belong to and should bea little more desctiptive than # package_name: puppetlabs-firewall # The locale that the default messages in the .pot file are in default_locale: en # The email used for sending bug reports. bugs_address: docs@puppet.com # The holder of the copyright. copyright_holder: Puppet, Inc. # This determines which comments in code should be eligible for translation. # Any comments that start with this string will be externalized. (Leave # empty to include all.) comments_tag: TRANSLATOR # Patterns for +Dir.glob+ used to find all files that might contain # translatable content, relative to the project root directory source_files: - './lib/**/*.rb' puppetlabs-firewall-1.12.0/manifests0040755005276200011600000000000013232340576014464 5ustar00puppetlabs-firewall-1.12.0/manifests/init.pp0100644005276200011600000000305413202542071016035 0ustar00# = Class: firewall # # Manages packages and services required by the firewall type/provider. # # This class includes the appropriate sub-class for your operating system, # where supported. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # class firewall ( $ensure = running, $ensure_v6 = undef, $pkg_ensure = present, $service_name = $::firewall::params::service_name, $service_name_v6 = $::firewall::params::service_name_v6, $package_name = $::firewall::params::package_name, $ebtables_manage = false, ) inherits ::firewall::params { $_ensure_v6 = pick($ensure_v6, $ensure) case $ensure { /^(running|stopped)$/: { # Do nothing. } default: { fail("${title}: Ensure value '${ensure}' is not supported") } } if $ensure_v6 { case $ensure_v6 { /^(running|stopped)$/: { # Do nothing. } default: { fail("${title}: ensure_v6 value '${ensure_v6}' is not supported") } } } case $::kernel { 'Linux': { class { "${title}::linux": ensure => $ensure, ensure_v6 => $_ensure_v6, pkg_ensure => $pkg_ensure, service_name => $service_name, service_name_v6 => $service_name_v6, package_name => $package_name, ebtables_manage => $ebtables_manage, } contain "${title}::linux" } 'FreeBSD': { } default: { fail("${title}: Kernel '${::kernel}' is not currently supported") } } } puppetlabs-firewall-1.12.0/manifests/linux0040755005276200011600000000000013232340576015623 5ustar00puppetlabs-firewall-1.12.0/manifests/linux/archlinux.pp0100644005276200011600000000204213102663532020227 0ustar00# = Class: firewall::linux::archlinux # # Manages `iptables` and `ip6tables` services, and creates files used for # persistence, on Arch Linux systems. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*enable*] # Enable parameter passed onto Service[] resources. # Default: true # class firewall::linux::archlinux ( $ensure = 'running', $enable = true, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, $package_ensure = $::firewall::params::package_ensure, ) inherits ::firewall::params { if $package_name { package { $package_name: ensure => $package_ensure, } } service { $service_name: ensure => $ensure, enable => $enable, hasstatus => true, } file { '/etc/iptables/iptables.rules': ensure => present, before => Service[$service_name], } file { '/etc/iptables/ip6tables.rules': ensure => present, before => Service[$service_name], } } puppetlabs-firewall-1.12.0/manifests/linux/debian.pp0100644005276200011600000000401113232340436017451 0ustar00# = Class: firewall::linux::debian # # Installs the `iptables-persistent` package for Debian-alike systems. This # allows rules to be stored to file and restored on boot. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*enable*] # Enable parameter passed onto Service[] resources. # Default: true # class firewall::linux::debian ( $ensure = running, $enable = true, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, $package_ensure = $::firewall::params::package_ensure, ) inherits ::firewall::params { if $package_name { #Fixes hang while installing iptables-persistent on debian 8 exec {'iptables-persistent-debconf': command => "/bin/echo \"${package_name} ${package_name}/autosave_v4 boolean false\" | /usr/bin/debconf-set-selections && /bin/echo \"${package_name} ${package_name}/autosave_v6 boolean false\" | /usr/bin/debconf-set-selections", refreshonly => true, } package { $package_name: ensure => $package_ensure, require => Exec['iptables-persistent-debconf'], } } if($::operatingsystemrelease =~ /^6\./ and $enable == true and $::iptables_persistent_version and versioncmp($::iptables_persistent_version, '0.5.0') < 0) { # This fixes a bug in the iptables-persistent LSB headers in 6.x, without it # we lose idempotency exec { 'iptables-persistent-enable': logoutput => on_failure, command => '/usr/sbin/update-rc.d iptables-persistent enable', unless => '/usr/bin/test -f /etc/rcS.d/S*iptables-persistent', require => Package[$package_name], } } else { # This isn't a real service/daemon. The start action loads rules, so just # needs to be called on system boot. service { $service_name: ensure => undef, enable => $enable, hasstatus => true, require => Package[$package_name], } } } puppetlabs-firewall-1.12.0/manifests/linux/gentoo.pp0100644005276200011600000000203613102663532017530 0ustar00# = Class: firewall::linux::gentoo # # Manages `iptables` and `ip6tables` services, and creates files used for # persistence, on Gentoo Linux systems. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*enable*] # Enable parameter passed onto Service[] resources. # Default: true # class firewall::linux::gentoo ( $ensure = 'running', $enable = true, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, $package_ensure = $::firewall::params::package_ensure, ) inherits ::firewall::params { if $package_name { package { $package_name: ensure => $package_ensure, } } service { $service_name: ensure => $ensure, enable => $enable, hasstatus => true, } file { '/var/lib/iptables/rules-save': ensure => present, before => Service[$service_name], } file { '/var/lib/iptables/rules-save6': ensure => present, before => Service[$service_name], } } puppetlabs-firewall-1.12.0/manifests/linux/redhat.pp0100644005276200011600000001123013232340436017477 0ustar00# = Class: firewall::linux::redhat # # Manages the `iptables` service on RedHat-alike systems. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*ensure_v6*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*enable*] # Enable parameter passed onto Service[] resources. # Default: true # # [*enable_v6*] # Enable parameter passed onto Service[] resources. # Default: true # # class firewall::linux::redhat ( $ensure = running, $ensure_v6 = undef, $enable = true, $enable_v6 = undef, $service_name = $::firewall::params::service_name, $service_name_v6 = $::firewall::params::service_name_v6, $package_name = $::firewall::params::package_name, $package_ensure = $::firewall::params::package_ensure, ) inherits ::firewall::params { $_ensure_v6 = pick($ensure_v6, $ensure) $_enable_v6 = pick($enable_v6, $enable) # RHEL 7 / CentOS 7 and later and Fedora 15 and later require the iptables-services # package, which provides the /usr/libexec/iptables/iptables.init used by # 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)) { service { 'firewalld': ensure => stopped, enable => false, before => [Package[$package_name], Service[$service_name]], } } if $package_name { package { $package_name: ensure => $package_ensure, before => Service[$service_name], } } if ($::operatingsystem != 'Amazon') 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, $service_name_v6], subscribe => Package[$package_name], refreshonly => true, } } } service { $service_name: ensure => $ensure, enable => $enable, hasstatus => true, } service { $service_name_v6: ensure => $_ensure_v6, enable => $_enable_v6, 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 system_u # Redhat 7 selinux type context for /etc/sysconfig/iptables is set to system_conf_t case $::selinux { #lint:ignore:quoted_booleans 'true',true: { case $::operatingsystem { 'CentOS': { case $::operatingsystemrelease { /^5\..*/: { File["/etc/sysconfig/${service_name}"] { seluser => 'system_u', seltype => 'etc_t' } File["/etc/sysconfig/${service_name_v6}"] { seluser => 'system_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' } } /^7\..*/: { File["/etc/sysconfig/${service_name}"] { seluser => 'system_u', seltype => 'system_conf_t' } File["/etc/sysconfig/${service_name_v6}"] { seluser => 'system_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' } } } } # Fedora uses the same SELinux context as Redhat 'Fedora': { File["/etc/sysconfig/${service_name}"] { seluser => 'system_u', seltype => 'system_conf_t' } File["/etc/sysconfig/${service_name_v6}"] { seluser => 'system_u', seltype => 'system_conf_t' } } default: {} } } default: {} #lint:endignore } } puppetlabs-firewall-1.12.0/manifests/linux.pp0100644005276200011600000000512313202542071016230 0ustar00# = Class: firewall::linux # # Installs the `iptables` package for Linux operating systems and includes # the appropriate sub-class for any distribution specific services and # additional packages. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. When `running` the # service will be started on boot, and when `stopped` it will not. # Default: running # # [*ensure_v6*] # Ensure parameter passed onto Service[] resources. When `running` the # service will be started on boot, and when `stopped` it will not. # Default: running # class firewall::linux ( $ensure = running, $ensure_v6 = undef, $pkg_ensure = present, $service_name = $::firewall::params::service_name, $service_name_v6 = $::firewall::params::service_name_v6, $package_name = $::firewall::params::package_name, $ebtables_manage = false, ) inherits ::firewall::params { $enable = $ensure ? { 'running' => true, 'stopped' => false, } $_ensure_v6 = pick($ensure_v6, $ensure) $_enable_v6 = $_ensure_v6 ? { running => true, stopped => false, } package { 'iptables': ensure => $pkg_ensure, } if $ebtables_manage { package { 'ebtables': ensure => $pkg_ensure, } } case $::operatingsystem { 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer', 'VirtuozzoLinux': { class { "${title}::redhat": ensure => $ensure, ensure_v6 => $_ensure_v6, enable => $enable, enable_v6 => $_enable_v6, package_name => $package_name, service_name => $service_name, service_name_v6 => $service_name_v6, require => Package['iptables'], } } 'Debian', 'Ubuntu': { class { "${title}::debian": ensure => $ensure, enable => $enable, package_name => $package_name, service_name => $service_name, require => Package['iptables'], } } 'Archlinux': { class { "${title}::archlinux": ensure => $ensure, enable => $enable, package_name => $package_name, service_name => $service_name, require => Package['iptables'], } } 'Gentoo': { class { "${title}::gentoo": ensure => $ensure, enable => $enable, package_name => $package_name, service_name => $service_name, require => Package['iptables'], } } default: {} } } puppetlabs-firewall-1.12.0/manifests/params.pp0100644005276200011600000000402413232340436016357 0ustar00# Manifest containing module parameters class firewall::params { $package_ensure = 'present' case $::osfamily { 'RedHat': { $service_name = 'iptables' $service_name_v6 = 'ip6tables' case $::operatingsystem { 'Amazon': { $package_name = undef } 'Fedora': { if versioncmp($::operatingsystemrelease, '15') >= 0 { $package_name = 'iptables-services' } else { $package_name = undef } } default: { if versioncmp($::operatingsystemrelease, '7.0') >= 0 { $package_name = 'iptables-services' } else { $package_name = 'iptables-ipv6' } } } } 'Debian': { $service_name_v6 = undef case $::operatingsystem { 'Debian': { if versioncmp($::operatingsystemrelease, '8.0') >= 0 { $service_name = 'netfilter-persistent' $package_name = 'iptables-persistent' } else { $service_name = 'iptables-persistent' $package_name = 'iptables-persistent' } } 'Ubuntu': { if versioncmp($::operatingsystemrelease, '14.10') >= 0 { $service_name = 'netfilter-persistent' $package_name = 'iptables-persistent' } else { $service_name = 'iptables-persistent' $package_name = 'iptables-persistent' } } default: { $service_name = 'iptables-persistent' $package_name = 'iptables-persistent' } } } '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'] $package_name = undef } default: { $service_name = 'iptables' $package_name = undef } } } } } puppetlabs-firewall-1.12.0/metadata.json0100644005276200011600000000332713232340576015227 0ustar00{ "name": "puppetlabs-firewall", "version": "1.12.0", "author": "Puppet Labs", "summary": "Manages Firewalls such as iptables", "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-firewall", "project_page": "http://github.com/puppetlabs/puppetlabs-firewall", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.0.0 < 5.0.0" } ], "data_provider": null, "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "SLES", "operatingsystemrelease": [ "11 SP1", "12" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "6", "7", "8" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04" ] }, { "operatingsystem": "Gentoo", "operatingsystemrelease": [ "1.0" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 4.7.0 < 6.0.0" } ], "template-url": "file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git", "template-ref": "1.3.2-0-g07678c8" } puppetlabs-firewall-1.12.0/spec0040755005276200011600000000000013232340576013425 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance0040755005276200011600000000000013232340576015513 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/change_source_spec.rb0100644005276200011600000000550513232340436021733 0ustar00require 'spec_helper_acceptance' describe 'changing the source' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'when unmanaged rules exist' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '101 test source changes': proto => tcp, port => '101', action => accept, source => '8.0.0.1', } firewall { '100 test source static': proto => tcp, port => '100', action => accept, source => '8.0.0.2', } PUPPETCODE it 'applies with 8.0.0.1 first' do apply_manifest(pp1, catch_failures: true) end it 'adds a unmanaged rule without a comment' do shell('iptables -A INPUT -t filter -s 8.0.0.3/32 -p tcp -m multiport --ports 102 -j ACCEPT') expect(shell('iptables-save').stdout).to match(%r{-A INPUT -s 8\.0\.0\.3(\/32)? -p tcp -m multiport --ports 102 -j ACCEPT}) end it 'contains the changable 8.0.0.1 rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 8\.0\.0\.1(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT}) end end it 'contains the static 8.0.0.2 rule' do # rubocop:disable RSpec/RepeatedExample : The values being matched differ shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT}) end end pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '101 test source changes': proto => tcp, port => '101', action => accept, source => '8.0.0.4', } PUPPETCODE it 'changes to 8.0.0.4 second' do expect(apply_manifest(pp2, catch_failures: true).stdout) .to match(%r{Notice: \/Stage\[main\]\/Main\/Firewall\[101 test source changes\]\/source: source changed '8\.0\.0\.1\/32' to '8\.0\.0\.4\/32'}) end it 'does not contain the old changing 8.0.0.1 rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{8\.0\.0\.1}) end end it 'contains the staic 8.0.0.2 rule' do # rubocop:disable RSpec/RepeatedExample : The values being matched differ shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT}) end end it 'contains the changing new 8.0.0.4 rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 8\.0\.0\.4(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT}) end end end end puppetlabs-firewall-1.12.0/spec/acceptance/class_spec.rb0100644005276200011600000000160613207747121020235 0ustar00require 'spec_helper_acceptance' describe 'firewall class' do it 'runs successfully' do pp = "class { 'firewall': }" # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) if do_catch_changes expect(apply_manifest(pp, catch_failures: true).exit_code).to be_zero end end it 'ensure => stopped:' do pp = "class { 'firewall': ensure => stopped }" # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) if do_catch_changes expect(apply_manifest(pp, catch_failures: true).exit_code).to be_zero end end it 'ensure => running:' do pp = "class { 'firewall': ensure => running }" # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) if do_catch_changes expect(apply_manifest(pp, catch_failures: true).exit_code).to be_zero end end end puppetlabs-firewall-1.12.0/spec/acceptance/connlimit_spec.rb0100644005276200011600000000427513232340436021125 0ustar00require 'spec_helper_acceptance' describe 'connlimit property' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end if default['platform'] !~ %r{sles-10} describe 'connlimit_above' do context 'when 10' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '500 - test': proto => tcp, dport => '2222', connlimit_above => '10', action => reject, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| # connlimit-saddr is added in Ubuntu 14.04. expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --dports 2222 -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-m comment --comment "500 - test" -j REJECT --reject-with icmp-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to required size end end end end describe 'connlimit_mask' do context 'when 24' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '501 - test': proto => tcp, dport => '2222', connlimit_above => '10', connlimit_mask => '24', action => reject, } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| # connlimit-saddr is added in Ubuntu 14.04. expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --dports 2222 -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-m comment --comment "501 - test" -j REJECT --reject-with icmp-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to required size end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/connmark_spec.rb0100644005276200011600000000124613232340436020734 0ustar00require 'spec_helper_acceptance' describe 'connmark property' do describe 'connmark' do context 'when 50' do pp = <<-PUPPETCODE class { '::firewall': } firewall { '502 - test': proto => 'all', connmark => '0x1', action => reject, } PUPPETCODE it 'applies' do apply_manifest(pp, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -m connmark --mark 0x1 -m comment --comment "502 - test" -j REJECT --reject-with icmp-port-unreachable}) end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_bridging_spec.rb0100644005276200011600000003262313232340436022601 0ustar00require 'spec_helper_acceptance' describe 'firewall bridging' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'iptables physdev tests' do context 'when physdev_in eth0' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '701 - test': chain => 'FORWARD', proto => tcp, port => '701', action => accept, physdev_in => 'eth0', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 -m multiport --ports 701 -m comment --comment "701 - test" -j ACCEPT}) end end end context 'when physdev_out eth1' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '702 - test': chain => 'FORWARD', proto => tcp, port => '702', action => accept, physdev_out => 'eth1', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 -m multiport --ports 702 -m comment --comment "702 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_out eth1' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '703 - test': chain => 'FORWARD', proto => tcp, port => '703', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) apply_manifest(pp3, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 -m multiport --ports 703 -m comment --comment "703 - test" -j ACCEPT}) end end end context 'when physdev_is_bridged' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '704 - test': chain => 'FORWARD', proto => tcp, port => '704', action => accept, physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) apply_manifest(pp4, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_is_bridged' do pp5 = <<-PUPPETCODE class { '::firewall': } firewall { '705 - test': chain => 'FORWARD', proto => tcp, port => '705', action => accept, physdev_in => 'eth0', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp5, catch_failures: true) apply_manifest(pp5, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-is-bridged -m multiport --ports 705 -m comment --comment "705 - test" -j ACCEPT}) end end end context 'when physdev_out eth1 and physdev_is_bridged' do pp6 = <<-PUPPETCODE class { '::firewall': } firewall { '706 - test': chain => 'FORWARD', proto => tcp, port => '706', action => accept, physdev_out => 'eth1', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp6, catch_failures: true) apply_manifest(pp6, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m multiport --ports 706 -m comment --comment "706 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do pp7 = <<-PUPPETCODE class { '::firewall': } firewall { '707 - test': chain => 'FORWARD', proto => tcp, port => '707', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp7, catch_failures: true) apply_manifest(pp7, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m multiport --ports 707 -m comment --comment "707 - test" -j ACCEPT}) end end end end # iptables version 1.3.5 is not suppored by the ip6tables provider if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'ip6tables physdev tests' do context 'when physdev_in eth0' do pp8 = <<-PUPPETCODE class { '::firewall': } firewall { '701 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '701', action => accept, physdev_in => 'eth0', } PUPPETCODE it 'applies' do apply_manifest(pp8, catch_failures: true) apply_manifest(pp8, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 -m multiport --ports 701 -m comment --comment "701 - test" -j ACCEPT}) end end end context 'when physdev_out eth1' do pp9 = <<-PUPPETCODE class { '::firewall': } firewall { '702 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '702', action => accept, physdev_out => 'eth1', } PUPPETCODE it 'applies' do apply_manifest(pp9, catch_failures: true) apply_manifest(pp9, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 -m multiport --ports 702 -m comment --comment "702 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_out eth1' do pp10 = <<-PUPPETCODE class { '::firewall': } firewall { '703 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '703', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', } PUPPETCODE it 'applies' do apply_manifest(pp10, catch_failures: true) apply_manifest(pp10, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 -m multiport --ports 703 -m comment --comment "703 - test" -j ACCEPT}) end end end context 'when physdev_is_bridged' do pp11 = <<-PUPPETCODE class { '::firewall': } firewall { '704 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '704', action => accept, physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp11, catch_failures: true) apply_manifest(pp11, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_is_bridged' do pp12 = <<-PUPPETCODE class { '::firewall': } firewall { '705 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '705', action => accept, physdev_in => 'eth0', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp12, catch_failures: true) apply_manifest(pp12, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-is-bridged -m multiport --ports 705 -m comment --comment "705 - test" -j ACCEPT}) end end end context 'when physdev_out eth1 and physdev_is_bridged' do pp13 = <<-PUPPETCODE class { '::firewall': } firewall { '706 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '706', action => accept, physdev_out => 'eth1', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp13, catch_failures: true) apply_manifest(pp13, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m multiport --ports 706 -m comment --comment "706 - test" -j ACCEPT}) end end end context 'when physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do pp14 = <<-PUPPETCODE class { '::firewall': } firewall { '707 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '707', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp14, catch_failures: true) apply_manifest(pp14, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m multiport --ports 707 -m comment --comment "707 - test" -j ACCEPT}) end end end context 'when physdev_is_in' do pp15 = <<-PUPPETCODE class { '::firewall': } firewall { '708 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '708', action => accept, physdev_is_in => true, } PUPPETCODE it 'applies' do apply_manifest(pp15, catch_failures: true) apply_manifest(pp15, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-is-in -m multiport --ports 708 -m comment --comment "708 - test" -j ACCEPT}) end end end context 'when physdev_is_out' do pp16 = <<-PUPPETCODE class { '::firewall': } firewall { '709 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '709', action => accept, physdev_is_out => true, } PUPPETCODE it 'applies' do apply_manifest(pp16, catch_failures: true) apply_manifest(pp16, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m physdev\s+--physdev-is-out -m multiport --ports 709 -m comment --comment "709 - test" -j ACCEPT}) end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_clusterip_spec.rb0100644005276200011600000000407113207747121023026 0ustar00 # These tests have been commented out, as there are suspicions that the clusterIP ipt module is causing system reboots. # require 'spec_helper_acceptance' # describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do # before(:all) do # shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') # shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') # end # # SLES doesn't have the CLUSTERIP module # if default['platform'] !~ /sles/ # describe 'clusterip' do # context 'cluster ipv4 test' do # it 'applies' do # pending("MODULES-2124 should be resolved for clusterip RHEL7 support") if default['platform'] =~ /el-7/ # pp = <<-EOS # class { '::firewall': } # firewall { # '830 - clusterip test': # chain => 'FORWARD', # jump => 'CLUSTERIP', # destination => '1.1.1.1', # iniface => 'eth0', # clusterip_new => true, # clusterip_hashmode => "sourceip", # clusterip_clustermac => "01:00:5E:00:00:00", # clusterip_total_nodes => "2", # clusterip_local_node => "1", # clusterip_hash_init => "1337", # } # EOS # apply_manifest(pp, :catch_failures => true) # end # it 'should contain the rule' do # pending("MODULES-2124 should be resolved for clusterip RHEL7 support") if default['platform'] =~ /el-7/ # shell('iptables-save') do |r| # expect(r.stdout).to match(/-A FORWARD -d (1.1.1.1\/32|1.1.1.1) -i eth0 -p tcp -m comment --comment "830 - clusterip test" -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5E:00:00:00 --total-nodes 2 --local-node 1 --hash-init 1337/) # rubocop:disable Metrics/LineLength : Cannot reduce length to required size # end # end # end # end # end # end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_dscp_spec.rb0100644005276200011600000000663613232340436021752 0ustar00require 'spec_helper_acceptance' describe 'firewall DSCP' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'dscp ipv4 tests' do context 'when set_dscp 0x01' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '1000 - set_dscp': proto => 'tcp', jump => 'DSCP', set_dscp => '0x01', port => '997', chain => 'OUTPUT', table => 'mangle', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1000 - set_dscp" -j DSCP --set-dscp 0x01}) end end end context 'when set_dscp_class EF' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '1001 EF - set_dscp_class': proto => 'tcp', jump => 'DSCP', port => '997', set_dscp_class => 'EF', chain => 'OUTPUT', table => 'mangle', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1001 EF - set_dscp_class" -j DSCP --set-dscp 0x2e}) end end end end if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'dscp ipv6 tests' do context 'when set_dscp 0x01' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '1002 - set_dscp': proto => 'tcp', jump => 'DSCP', set_dscp => '0x01', port => '997', chain => 'OUTPUT', table => 'mangle', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1002 - set_dscp" -j DSCP --set-dscp 0x01}) end end end context 'when set_dscp_class EF' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '1003 EF - set_dscp_class': proto => 'tcp', jump => 'DSCP', port => '997', set_dscp_class => 'EF', chain => 'OUTPUT', table => 'mangle', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1003 EF - set_dscp_class" -j DSCP --set-dscp 0x2e}) end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_gid_spec.rb0100644005276200011600000000532113232340436021552 0ustar00require 'spec_helper_acceptance' describe 'firewall gid' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'gid tests' do context 'when gid set to root' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - test': chain => 'OUTPUT', action => accept, gid => 'root', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner --gid-owner (0|root) -m comment --comment "801 - test" -j ACCEPT}) end end end context 'when gid set to !root' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - test': chain => 'OUTPUT', action => accept, gid => '!root', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner ! --gid-owner (0|root) -m comment --comment "802 - test" -j ACCEPT}) end end end context 'when gid set to 0' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '803 - test': chain => 'OUTPUT', action => accept, gid => '0', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) apply_manifest(pp3, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner --gid-owner (0|root) -m comment --comment "803 - test" -j ACCEPT}) end end end context 'when gid set to !0' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '804 - test': chain => 'OUTPUT', action => accept, gid => '!0', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) apply_manifest(pp4, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner ! --gid-owner (0|root) -m comment --comment "804 - test" -j ACCEPT}) end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_iptmodules_spec.rb0100644005276200011600000002166513232340436023205 0ustar00require 'spec_helper_acceptance' describe 'firewall iptmodules' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'iptables ipt_modules tests' do context 'when all the modules with multiple args' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', uid => 0, gid => 404, src_range => "90.0.0.1-90.0.0.2", dst_range => "100.0.0.1-100.0.0.2", src_type => 'LOCAL', dst_type => 'UNICAST', physdev_in => "eth0", physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 90.0.0.1-90.0.0.2\s+--dst-range 100.0.0.1-100.0.0.2 -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m addrtype --src-type LOCAL --dst-type UNICAST -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end context 'when all the modules with single args' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', gid => 404, dst_range => "100.0.0.1-100.0.0.2", dst_type => 'UNICAST', physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 100.0.0.1-100.0.0.2 -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end end # iptables version 1.3.5 is not suppored by the ip6tables provider if default['platform'] =~ %r{debian-7} || default['platform'] =~ %r{ubuntu-14\.04} describe 'ip6tables ipt_modules tests' do context 'when all the modules with multiple args' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', uid => 0, gid => 404, src_range => "2001::-2002::", dst_range => "2003::-2004::", src_type => 'LOCAL', dst_type => 'UNICAST', physdev_in => "eth0", physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) apply_manifest(pp3, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 2001::-2002::\s+--dst-range 2003::-2004:: -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m addrtype --src-type LOCAL --dst-type UNICAST -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end context 'when all the modules with single args' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', gid => 404, dst_range => "2003::-2004::", dst_type => 'UNICAST', physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) apply_manifest(pp4, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end end # Older OSes don't have addrtype so we leave those properties out. # el-5 doesn't support ipv6 by default elsif default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'ip6tables ipt_modules tests' do context 'when all the modules with multiple args' do pp5 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', uid => 0, gid => 404, src_range => "2001::-2002::", dst_range => "2003::-2004::", physdev_in => "eth0", physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp5, catch_failures: true) apply_manifest(pp5, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-in eth0 --physdev-out eth1 --physdev-is-bridged -m iprange --src-range 2001::-2002::\s+--dst-range 2003::-2004:: -m owner --uid-owner (0|root) --gid-owner 404 -m multiport --dports 8080 -m comment --comment "801 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end context 'when all the modules with single args' do pp6 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', gid => 404, dst_range => "2003::-2004::", physdev_out => "eth1", physdev_is_bridged => true, } PUPPETCODE it 'applies' do apply_manifest(pp6, catch_failures: true) apply_manifest(pp6, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable}) # rubocop:disable Metrics/LineLength : Cannot reduce length to the required size end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_mss_spec.rb0100644005276200011600000000704413232340436021615 0ustar00require 'spec_helper_acceptance' describe 'firewall MSS' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'mss ipv4 tests' do context 'when 1360' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '502 - set_mss': proto => 'tcp', tcp_flags => 'SYN,RST SYN', jump => 'TCPMSS', set_mss => '1360', mss => '1361:1541', chain => 'FORWARD', table => 'mangle', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1541 -m comment --comment "502 - set_mss" -j TCPMSS --set-mss 1360}) end end end context 'when clamp_mss_to_pmtu' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '503 - clamp_mss_to_pmtu': proto => 'tcp', chain => 'FORWARD', tcp_flags => 'SYN,RST SYN', jump => 'TCPMSS', clamp_mss_to_pmtu => true, } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "503 - clamp_mss_to_pmtu" -j TCPMSS --clamp-mss-to-pmtu}) end end end end if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'mss ipv6 tests' do context 'when 1360' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '502 - set_mss': proto => 'tcp', tcp_flags => 'SYN,RST SYN', jump => 'TCPMSS', set_mss => '1360', mss => '1361:1541', chain => 'FORWARD', table => 'mangle', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1541 -m comment --comment "502 - set_mss" -j TCPMSS --set-mss 1360}) end end end context 'when clamp_mss_to_pmtu' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '503 - clamp_mss_to_pmtu': proto => 'tcp', chain => 'FORWARD', tcp_flags => 'SYN,RST SYN', jump => 'TCPMSS', clamp_mss_to_pmtu => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "503 - clamp_mss_to_pmtu" -j TCPMSS --clamp-mss-to-pmtu}) end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_spec.rb0100644005276200011600000021701013232340436020727 0ustar00require 'spec_helper_acceptance' describe 'firewall basics', docker: true do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'name' do context 'when valid' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '001 - test': ensure => present } PUPPETCODE it 'applies cleanly' do apply_manifest(pp1, catch_failures: true) end end context 'when invalid' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { 'test': ensure => present } PUPPETCODE it 'fails' do apply_manifest(pp2, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "test".}) end end end end describe 'ensure' do context 'when default' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '555 - test': proto => tcp, port => '555', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT}) end end end context 'when present' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '555 - test': ensure => present, proto => tcp, port => '555', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT}) end end end context 'when absent' do pp5 = <<-PUPPETCODE class { '::firewall': } firewall { '555 - test': ensure => absent, proto => tcp, port => '555', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp5, catch_failures: true) end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT}) end end end end describe 'source' do context 'when 192.168.2.0/24' do pp7 = <<-PUPPETCODE class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '192.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp7, catch_failures: true) apply_manifest(pp7, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT}) end end end context 'when ! 192.168.2.0/24' do pp8 = <<-PUPPETCODE class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '! 192.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp8, catch_failures: true) apply_manifest(pp8, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT (! -s|-s !) 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT}) end end end # Invalid address context 'when 256.168.2.0/24' do pp9 = <<-PUPPETCODE class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '256.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp9, expect_failures: true) do |r| expect(r.stderr).to match(%r{host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -s 256.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT}) end end end end describe 'src_range' do context 'when 192.168.1.1-192.168.1.10' do pp10 = <<-PUPPETCODE class { '::firewall': } firewall { '557 - test': proto => tcp, port => '557', action => accept, src_range => '192.168.1.1-192.168.1.10', } PUPPETCODE it 'applies' do apply_manifest(pp10, catch_failures: true) apply_manifest(pp10, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m iprange --src-range 192.168.1.1-192.168.1.10 -m multiport --ports 557 -m comment --comment "557 - test" -j ACCEPT}) end end end # Invalid IP context 'when 392.168.1.1-192.168.1.10' do pp11 = <<-PUPPETCODE class { '::firewall': } firewall { '557 - test': proto => tcp, port => '557', action => accept, src_range => '392.168.1.1-192.168.1.10', } PUPPETCODE it 'applies' do apply_manifest(pp11, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid IP address "392.168.1.1" in range "392.168.1.1-192.168.1.10"}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m iprange --src-range 392.168.1.1-192.168.1.10 -m multiport --ports 557 -m comment --comment "557 - test" -j ACCEPT}) end end end end describe 'destination' do context 'when 192.168.2.0/24' do pp12 = <<-PUPPETCODE class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '192.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp12, catch_failures: true) apply_manifest(pp12, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT}) end end end context 'when ! 192.168.2.0/24' do pp13 = <<-PUPPETCODE class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '! 192.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp13, catch_failures: true) apply_manifest(pp13, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT (! -d|-d !) 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT}) end end end # Invalid address context 'when 256.168.2.0/24' do pp14 = <<-PUPPETCODE class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '256.168.2.0/24', } PUPPETCODE it 'applies' do apply_manifest(pp14, expect_failures: true) do |r| expect(r.stderr).to match(%r{host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -d 256.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT}) end end end end describe 'dst_range' do context 'when 192.168.1.1-192.168.1.10' do pp15 = <<-PUPPETCODE class { '::firewall': } firewall { '559 - test': proto => tcp, port => '559', action => accept, dst_range => '192.168.1.1-192.168.1.10', } PUPPETCODE it 'applies' do apply_manifest(pp15, catch_failures: true) apply_manifest(pp15, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m iprange --dst-range 192.168.1.1-192.168.1.10 -m multiport --ports 559 -m comment --comment "559 - test" -j ACCEPT}) end end end # Invalid IP context 'when 392.168.1.1-192.168.1.10' do pp16 = <<-PUPPETCODE class { '::firewall': } firewall { '559 - test': proto => tcp, port => '559', action => accept, dst_range => '392.168.1.1-192.168.1.10', } PUPPETCODE it 'applies' do apply_manifest(pp16, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid IP address "392.168.1.1" in range "392.168.1.1-192.168.1.10"}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m iprange --dst-range 392.168.1.1-192.168.1.10 -m multiport --ports 559 -m comment --comment "559 - test" -j ACCEPT}) end end end end describe 'sport' do context 'when single port' do pp17 = <<-PUPPETCODE class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '560', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp17, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --sports 560 -m comment --comment "560 - test" -j ACCEPT}) end end end context 'when multiple ports' do pp18 = <<-PUPPETCODE class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '560-561', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp18, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --sports 560:561 -m comment --comment "560 - test" -j ACCEPT}) end end end context 'when invalid ports' do pp19 = <<-PUPPETCODE class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '9999560-561', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp19, expect_failures: true) do |r| expect(r.stderr).to match(%r{invalid port\/service `9999560' specified}) end end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --sports 9999560-561 -m comment --comment "560 - test" -j ACCEPT}) end end end end describe 'dport' do context 'when single port' do pp20 = <<-PUPPETCODE class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '561', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp20, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --dports 561 -m comment --comment "561 - test" -j ACCEPT}) end end end context 'when multiple ports' do pp21 = <<-PUPPETCODE class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '561-562', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp21, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --dports 561:562 -m comment --comment "561 - test" -j ACCEPT}) end end end context 'when invalid ports' do pp22 = <<-PUPPETCODE class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '9999561-562', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp22, expect_failures: true) do |r| expect(r.stderr).to match(%r{invalid port\/service `9999561' specified}) end end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --dports 9999561-562 -m comment --comment "560 - test" -j ACCEPT}) end end end end describe 'port' do context 'when single port' do pp23 = <<-PUPPETCODE class { '::firewall': } firewall { '562 - test': proto => tcp, port => '562', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp23, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 562 -m comment --comment "562 - test" -j ACCEPT}) end end end context 'when multiple ports' do pp24 = <<-PUPPETCODE class { '::firewall': } firewall { '562 - test': proto => tcp, port => '562-563', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp24, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 562:563 -m comment --comment "562 - test" -j ACCEPT}) end end end context 'when invalid ports' do pp25 = <<-PUPPETCODE class { '::firewall': } firewall { '562 - test': proto => tcp, port => '9999562-563', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp25, expect_failures: true) do |r| expect(r.stderr).to match(%r{invalid port\/service `9999562' specified}) end end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --ports 9999562-563 -m comment --comment "562 - test" -j ACCEPT}) end end end end %w[dst_type src_type].each do |type| describe type.to_s do context 'when MULTICAST' do pp26 = <<-PUPPETCODE class { '::firewall': } firewall { '563 - test': proto => tcp, action => accept, #{type} => 'MULTICAST', } PUPPETCODE it 'applies' do apply_manifest(pp26, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype\s.*\sMULTICAST -m comment --comment "563 - test" -j ACCEPT}) end end end context 'when ! MULTICAST' do pp27 = <<-PUPPETCODE class { '::firewall': } firewall { '563 - test inversion': proto => tcp, action => accept, #{type} => '! MULTICAST', } PUPPETCODE it 'applies' do apply_manifest(pp27, catch_failures: true) apply_manifest(pp27, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype( !\s.*\sMULTICAST|\s.*\s! MULTICAST) -m comment --comment "563 - test inversion" -j ACCEPT}) end end end context 'when BROKEN' do pp28 = <<-PUPPETCODE class { '::firewall': } firewall { '563 - test': proto => tcp, action => accept, #{type} => 'BROKEN', } PUPPETCODE it 'fails' do apply_manifest(pp28, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "BROKEN".}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype\s.*\sBROKEN -m comment --comment "563 - test" -j ACCEPT}) end end end end end describe 'tcp_flags' do context 'when FIN,SYN ACK' do pp29 = <<-PUPPETCODE class { '::firewall': } firewall { '564 - test': proto => tcp, action => accept, tcp_flags => 'FIN,SYN ACK', } PUPPETCODE it 'applies' do apply_manifest(pp29, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN ACK -m comment --comment "564 - test" -j ACCEPT}) end end end end describe 'chain' do context 'when INPUT' do pp30 = <<-PUPPETCODE class { '::firewall': } firewall { '565 - test': proto => tcp, action => accept, chain => 'FORWARD', } PUPPETCODE it 'applies' do apply_manifest(pp30, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m comment --comment "565 - test" -j ACCEPT}) end end end end describe 'table' do context 'when mangle' do pp31 = <<-PUPPETCODE class { '::firewall': } firewall { '566 - test': proto => tcp, action => accept, table => 'mangle', } PUPPETCODE it 'applies' do apply_manifest(pp31, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m comment --comment "566 - test" -j ACCEPT}) end end end context 'when nat' do pp32 = <<-PUPPETCODE class { '::firewall': } firewall { '566 - test2': proto => tcp, action => accept, table => 'nat', chain => 'OUTPUT', } PUPPETCODE it 'applies' do apply_manifest(pp32, catch_failures: true) end it 'does not contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m comment --comment "566 - test2" -j ACCEPT}) end end end end describe 'jump' do after :all do iptables_flush_all_tables end context 'when MARK' do pp33 = <<-PUPPETCODE class { '::firewall': } firewallchain { 'TEST:filter:IPv4': ensure => present, } firewall { '567 - test': proto => tcp, chain => 'INPUT', jump => 'TEST', } PUPPETCODE it 'applies' do apply_manifest(pp33, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m comment --comment "567 - test" -j TEST}) end end end context 'when jump and apply' do pp34 = <<-PUPPETCODE class { '::firewall': } firewallchain { 'TEST:filter:IPv4': ensure => present, } firewall { '568 - test': proto => tcp, chain => 'INPUT', action => 'accept', jump => 'TEST', } PUPPETCODE it 'applies' do apply_manifest(pp34, expect_failures: true) do |r| expect(r.stderr).to match(%r{Only one of the parameters 'action' and 'jump' can be set}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m comment --comment "568 - test" -j TEST}) end end end end describe 'tosource' do context 'when 192.168.1.1' do pp35 = <<-PUPPETCODE class { '::firewall': } firewall { '568 - test': proto => tcp, table => 'nat', chain => 'POSTROUTING', jump => 'SNAT', tosource => '192.168.1.1', } PUPPETCODE it 'applies' do apply_manifest(pp35, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{A POSTROUTING -p tcp -m comment --comment "568 - test" -j SNAT --to-source 192.168.1.1}) end end end end describe 'todest' do context 'when 192.168.1.1' do pp36 = <<-PUPPETCODE class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'PREROUTING', jump => 'DNAT', source => '200.200.200.200', todest => '192.168.1.1', } PUPPETCODE it 'applies' do apply_manifest(pp36, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A PREROUTING -s 200.200.200.200(\/32)? -p tcp -m comment --comment "569 - test" -j DNAT --to-destination 192.168.1.1}) end end end end describe 'toports' do context 'when 192.168.1.1' do pp37 = <<-PUPPETCODE class { '::firewall': } firewall { '570 - test': proto => icmp, table => 'nat', chain => 'PREROUTING', jump => 'REDIRECT', toports => '2222', } PUPPETCODE it 'applies' do apply_manifest(pp37, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A PREROUTING -p icmp -m comment --comment "570 - test" -j REDIRECT --to-ports 2222}) end end end end if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{ubuntu-10\.04} && default['platform'] !~ %r{debian-6} && default['platform'] !~ %r{sles} describe 'checksum_fill' do context 'when virbr' do pp38 = <<-PUPPETCODE class { '::firewall': } firewall { '576 - test': proto => udp, table => 'mangle', outiface => 'virbr0', chain => 'POSTROUTING', dport => '68', jump => 'CHECKSUM', checksum_fill => true, provider => iptables, } PUPPETCODE it 'applies' do apply_manifest(pp38, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A POSTROUTING -o virbr0 -p udp -m multiport --dports 68 -m comment --comment "576 - test" -j CHECKSUM --checksum-fill}) end end end end describe 'checksum_fill6' do context 'when virbr' do pp39 = <<-PUPPETCODE class { '::firewall': } firewall { '576 - test': proto => udp, table => 'mangle', outiface => 'virbr0', chain => 'POSTROUTING', dport => '68', jump => 'CHECKSUM', checksum_fill => true, provider => ip6tables, } PUPPETCODE it 'applies' do apply_manifest(pp39, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A POSTROUTING -o virbr0 -p udp -m multiport --dports 68 -m comment --comment "576 - test" -j CHECKSUM --checksum-fill}) end end end end end # RHEL5 does not support --random if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'random' do context 'when 192.168.1.1' do pp40 = <<-PUPPETCODE class { '::firewall': } firewall { '570 - test 2': proto => all, table => 'nat', chain => 'POSTROUTING', jump => 'MASQUERADE', source => '172.30.0.0/16', random => true } PUPPETCODE it 'applies' do apply_manifest(pp40, catch_failures: true) apply_manifest(pp40, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A POSTROUTING -s 172\.30\.0\.0\/16 -m comment --comment "570 - test 2" -j MASQUERADE --random}) end end end end end describe 'icmp' do context 'when any' do pp41 = <<-PUPPETCODE class { '::firewall': } firewall { '571 - test': proto => icmp, icmp => 'any', } PUPPETCODE it 'fails' do apply_manifest(pp41, expect_failures: true) do |r| expect(r.stderr).to match(%r{This behaviour should be achieved by omitting or undefining the ICMP parameter}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p icmp -m comment --comment "570 - test" -m icmp --icmp-type 11}) end end end end # iptables version 1.3.5 is not suppored by the ip6tables provider # iptables version 1.4.7 fails for multiple hl entries if default['platform'] !~ %r{(el-5|el-6|sles-10|sles-11)} describe 'hop_limit' do context 'when 5' do pp42 = <<-PUPPETCODE class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, hop_limit => '5', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp42, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 571 -m hl --hl-eq 5 -m comment --comment "571 - test" -j ACCEPT}) end end end context 'when invalid' do pp43 = <<-PUPPETCODE class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, hop_limit => 'invalid', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp43, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "invalid".}) end end it 'does not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --ports 571 -m comment --comment "571 - test" -m hl --hl-eq invalid -j ACCEPT}) end end end end describe 'ishasmorefrags' do context 'when true' do pp44 = <<-PUPPETCODE class { '::firewall': } firewall { '587 - test': ensure => present, proto => tcp, port => '587', action => accept, ishasmorefrags => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp44, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{A INPUT -p tcp -m frag --fragid 0 --fragmore -m multiport --ports 587 -m comment --comment "587 - test" -j ACCEPT}) end end end context 'when false' do pp45 = <<-PUPPETCODE class { '::firewall': } firewall { '588 - test': ensure => present, proto => tcp, port => '588', action => accept, ishasmorefrags => false, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp45, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 588 -m comment --comment "588 - test" -j ACCEPT}) end end end end describe 'islastfrag' do context 'when true' do pp46 = <<-PUPPETCODE class { '::firewall': } firewall { '589 - test': ensure => present, proto => tcp, port => '589', action => accept, islastfrag => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp46, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m frag --fragid 0 --fraglast -m multiport --ports 589 -m comment --comment "589 - test" -j ACCEPT}) end end end context 'when false' do pp47 = <<-PUPPETCODE class { '::firewall': } firewall { '590 - test': ensure => present, proto => tcp, port => '590', action => accept, islastfrag => false, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp47, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 590 -m comment --comment "590 - test" -j ACCEPT}) end end end end describe 'isfirstfrag' do context 'when true' do pp48 = <<-PUPPETCODE class { '::firewall': } firewall { '591 - test': ensure => present, proto => tcp, port => '591', action => accept, isfirstfrag => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp48, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m frag --fragid 0 --fragfirst -m multiport --ports 591 -m comment --comment "591 - test" -j ACCEPT}) end end end context 'when false' do pp49 = <<-PUPPETCODE class { '::firewall': } firewall { '592 - test': ensure => present, proto => tcp, port => '592', action => accept, isfirstfrag => false, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp49, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 592 -m comment --comment "592 - test" -j ACCEPT}) end end end end describe 'tcp_flags' do context 'when FIN,SYN ACK' do pp50 = <<-PUPPETCODE class { '::firewall': } firewall { '593 - test': proto => tcp, action => accept, tcp_flags => 'FIN,SYN ACK', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp50, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN ACK -m comment --comment "593 - test" -j ACCEPT}) end end end end describe 'src_range' do context 'when 2001:db8::1-2001:db8::ff' do pp51 = <<-PUPPETCODE class { '::firewall': } firewall { '601 - test': proto => tcp, port => '601', action => accept, src_range => '2001:db8::1-2001:db8::ff', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp51, catch_failures: true) apply_manifest(pp51, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m iprange --src-range 2001:db8::1-2001:db8::ff -m multiport --ports 601 -m comment --comment "601 - test" -j ACCEPT}) end end end # Invalid IP context 'when 2001::db8::1-2001:db8::ff' do pp52 = <<-PUPPETCODE class { '::firewall': } firewall { '601 - test': proto => tcp, port => '601', action => accept, provider => 'ip6tables', src_range => '2001::db8::1-2001:db8::ff', } PUPPETCODE it 'applies' do apply_manifest(pp52, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid IP address "2001::db8::1" in range "2001::db8::1-2001:db8::ff"}) end end it 'does not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m iprange --src-range 2001::db8::1-2001:db8::ff -m multiport --ports 601 -m comment --comment "601 - test" -j ACCEPT}) end end end end describe 'dst_range' do context 'when 2001:db8::1-2001:db8::ff' do pp53 = <<-PUPPETCODE class { '::firewall': } firewall { '602 - test': proto => tcp, port => '602', action => accept, dst_range => '2001:db8::1-2001:db8::ff', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp53, catch_failures: true) apply_manifest(pp53, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m iprange --dst-range 2001:db8::1-2001:db8::ff -m multiport --ports 602 -m comment --comment "602 - test" -j ACCEPT}) end end end # Invalid IP context 'when 2001::db8::1-2001:db8::ff' do pp54 = <<-PUPPETCODE class { '::firewall': } firewall { '602 - test': proto => tcp, port => '602', action => accept, provider => 'ip6tables', dst_range => '2001::db8::1-2001:db8::ff', } PUPPETCODE it 'applies' do apply_manifest(pp54, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid IP address "2001::db8::1" in range "2001::db8::1-2001:db8::ff"}) end end it 'does not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m iprange --dst-range 2001::db8::1-2001:db8::ff -m multiport --ports 602 -m comment --comment "602 - test" -j ACCEPT}) end end end end describe 'mac_source' do context 'when 0A:1B:3C:4D:5E:6F' do pp55 = <<-PUPPETCODE class { '::firewall': } firewall { '604 - test': ensure => present, source => '2001:db8::1/128', mac_source => '0A:1B:3C:4D:5E:6F', chain => 'INPUT', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp55, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -s 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -p tcp -m mac --mac-source 0A:1B:3C:4D:5E:6F -m comment --comment "604 - test"}) end end end end # ip6tables has limited `-m socket` support if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{ubuntu-10\.04} && default['platform'] !~ %r{debian-6} && default['platform'] !~ %r{sles} describe 'socket' do context 'when true' do pp56 = <<-PUPPETCODE class { '::firewall': } firewall { '605 - test': ensure => present, proto => tcp, port => '605', action => accept, chain => 'INPUT', socket => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp56, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 605 -m socket -m comment --comment "605 - test" -j ACCEPT}) end end end context 'when false' do pp57 = <<-PUPPETCODE class { '::firewall': } firewall { '606 - test': ensure => present, proto => tcp, port => '606', action => accept, chain => 'INPUT', socket => false, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp57, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 606 -m comment --comment "606 - test" -j ACCEPT}) end end end end end describe 'ipsec_policy' do context 'when ipsec' do pp58 = <<-PUPPETCODE class { '::firewall': } firewall { '607 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '2001:db8::1/128', ipsec_dir => 'out', ipsec_policy => 'ipsec', proto => 'all', reject => 'icmp6-adm-prohibited', table => 'filter', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp58, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol ipsec -m comment --comment "607 - test" -j REJECT --reject-with icmp6-adm-prohibited}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end context 'when none' do pp59 = <<-PUPPETCODE class { '::firewall': } firewall { '608 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '2001:db8::1/128', ipsec_dir => 'out', ipsec_policy => 'none', proto => 'all', reject => 'icmp6-adm-prohibited', table => 'filter', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp59, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol none -m comment --comment "608 - test" -j REJECT --reject-with icmp6-adm-prohibited}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end end describe 'ipsec_dir' do context 'when out' do pp60 = <<-PUPPETCODE class { '::firewall': } firewall { '609 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '2001:db8::1/128', ipsec_dir => 'out', ipsec_policy => 'ipsec', proto => 'all', reject => 'icmp6-adm-prohibited', table => 'filter', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp60, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir out --pol ipsec -m comment --comment "609 - test" -j REJECT --reject-with icmp6-adm-prohibited}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end context 'when in' do pp61 = <<-PUPPETCODE class { '::firewall': } firewall { '610 - test': ensure => 'present', action => 'reject', chain => 'INPUT', destination => '2001:db8::1/128', ipsec_dir => 'in', ipsec_policy => 'none', proto => 'all', reject => 'icmp6-adm-prohibited', table => 'filter', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp61, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m policy --dir in --pol none -m comment --comment "610 - test" -j REJECT --reject-with icmp6-adm-prohibited}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end end describe 'set_mark' do context 'when 0x3e8/0xffffffff' do pp62 = <<-PUPPETCODE class { '::firewall': } firewall { '611 - test': ensure => present, chain => 'OUTPUT', proto => tcp, port => '611', jump => 'MARK', table => 'mangle', set_mark => '0x3e8/0xffffffff', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp62, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 611 -m comment --comment "611 - test" -j MARK --set-xmark 0x3e8\/0xffffffff}) end end end end # ip6tables only supports ipset, addrtype, and mask on a limited set of platforms if default['platform'] =~ %r{el-7} || default['platform'] =~ %r{debian-7} || default['platform'] =~ %r{ubuntu-14\.04} # ipset is really difficult to test, just testing on one platform if default['platform'] =~ %r{ubuntu-14\.04} describe 'ipset' do pp63 = <<-PUPPETCODE exec { 'hackery pt 1': command => 'service iptables-persistent flush', path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } package { 'ipset': ensure => present, require => Exec['hackery pt 1'], } exec { 'hackery pt 2': command => 'service iptables-persistent start', path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', require => Package['ipset'], } class { '::firewall': } 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 { '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', } -> 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,dst', '! honeypot dst'], provider => 'ip6tables', require => Exec['add honeypot'], } PUPPETCODE it 'applies' do apply_manifest(pp63, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m set --match-set blacklist src,dst -m set ! --match-set honeypot dst -m comment --comment "612 - test" -j DROP}) end end end end # mask isn't supported on deb7 if default['platform'] !~ %r{debian-7} describe 'mask' do pp64 = <<-PUPPETCODE class { '::firewall': } firewall { '613 - test': recent => 'update', rseconds => 60, rsource => true, rname => 'test', action => 'drop', chain => 'FORWARD', mask => 'ffff::', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp64, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A FORWARD -p tcp -m recent --update --seconds 60 --name test --mask ffff:: --rsource -m comment --comment "613 - test" -j DROP}) end end end end %w[dst_type src_type].each do |type| describe type.to_s do context 'when MULTICAST' do pp65 = <<-PUPPETCODE class { '::firewall': } firewall { '603 - test': proto => tcp, action => accept, #{type} => 'MULTICAST', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp65, catch_failures: true) apply_manifest(pp65, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype\s.*\sMULTICAST -m comment --comment "603 - test" -j ACCEPT}) end end end context 'when ! MULTICAST' do pp66 = <<-PUPPETCODE class { '::firewall': } firewall { '603 - test inversion': proto => tcp, action => accept, #{type} => '! MULTICAST', provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp66, catch_failures: true) apply_manifest(pp66, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype( !\s.*\sMULTICAST|\s.*\s! MULTICAST) -m comment --comment "603 - test inversion" -j ACCEPT}) end end end context 'when BROKEN' do pp67 = <<-PUPPETCODE class { '::firewall': } firewall { '603 - test': proto => tcp, action => accept, #{type} => 'BROKEN', provider => 'ip6tables', } PUPPETCODE it 'fails' do apply_manifest(pp67, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "BROKEN".}) end end it 'does not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype\s.*\sBROKEN -m comment --comment "603 - test" -j ACCEPT}) end end end end end end end describe 'limit' do context 'when 500/sec' do pp68 = <<-PUPPETCODE class { '::firewall': } firewall { '572 - test': ensure => present, proto => tcp, port => '572', action => accept, limit => '500/sec', } PUPPETCODE it 'applies' do apply_manifest(pp68, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 572 -m limit --limit 500\/sec -m comment --comment "572 - test" -j ACCEPT}) end end end end describe 'burst' do context 'when 500' do pp69 = <<-PUPPETCODE class { '::firewall': } firewall { '573 - test': ensure => present, proto => tcp, port => '573', action => accept, limit => '500/sec', burst => '1500', } PUPPETCODE it 'applies' do apply_manifest(pp69, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 573 -m limit --limit 500\/sec --limit-burst 1500 -m comment --comment "573 - test" -j ACCEPT}) end end end context 'when invalid' do pp70 = <<-PUPPETCODE class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, limit => '500/sec', burst => '1500/sec', } PUPPETCODE it 'applies' do apply_manifest(pp70, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "1500\/sec".}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --ports 573 -m comment --comment "573 - test" -m limit --limit 500\/sec --limit-burst 1500\/sec -j ACCEPT}) end end end end describe 'uid' do context 'when nobody' do pp71 = <<-PUPPETCODE class { '::firewall': } firewall { '574 - test': ensure => present, proto => tcp, chain => 'OUTPUT', port => '574', action => accept, uid => 'nobody', } PUPPETCODE it 'applies' do apply_manifest(pp71, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m owner --uid-owner (nobody|\d+) -m multiport --ports 574 -m comment --comment "574 - test" -j ACCEPT}) end end end end describe 'gid' do context 'when root' do pp72 = <<-PUPPETCODE class { '::firewall': } firewall { '575 - test': ensure => present, proto => tcp, chain => 'OUTPUT', port => '575', action => accept, gid => 'root', } PUPPETCODE it 'applies' do apply_manifest(pp72, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m owner --gid-owner (root|\d+) -m multiport --ports 575 -m comment --comment "575 - test" -j ACCEPT}) end end end end # iptables version 1.3.5 does not support masks on MARK rules if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'set_mark' do context 'when 0x3e8/0xffffffff' do pp73 = <<-PUPPETCODE class { '::firewall': } firewall { '580 - test': ensure => present, chain => 'OUTPUT', proto => tcp, port => '580', jump => 'MARK', table => 'mangle', set_mark => '0x3e8/0xffffffff', } PUPPETCODE it 'applies' do apply_manifest(pp73, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --ports 580 -m comment --comment "580 - test" -j MARK --set-xmark 0x3e8\/0xffffffff}) end end end end end describe 'pkttype' do context 'when multicast' do pp74 = <<-PUPPETCODE class { '::firewall': } firewall { '581 - test': ensure => present, proto => tcp, port => '581', action => accept, pkttype => 'multicast', } PUPPETCODE it 'applies' do apply_manifest(pp74, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 581 -m pkttype --pkt-type multicast -m comment --comment "581 - test" -j ACCEPT}) end end end context 'when test' do pp75 = <<-PUPPETCODE class { '::firewall': } firewall { '582 - test': ensure => present, proto => tcp, port => '582', action => accept, pkttype => 'test', } PUPPETCODE it 'applies' do apply_manifest(pp75, expect_failures: true) do |r| expect(r.stderr).to match(%r{Invalid value "test".}) end end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m multiport --ports 582 -m pkttype --pkt-type multicast -m comment --comment "582 - test" -j ACCEPT}) end end end end describe 'isfragment' do context 'when true' do pp76 = <<-PUPPETCODE class { '::firewall': } firewall { '583 - test': ensure => present, proto => tcp, port => '583', action => accept, isfragment => true, } PUPPETCODE it 'applies' do apply_manifest(pp76, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -f -m multiport --ports 583 -m comment --comment "583 - test" -j ACCEPT}) end end end context 'when false' do pp77 = <<-PUPPETCODE class { '::firewall': } firewall { '584 - test': ensure => present, proto => tcp, port => '584', action => accept, isfragment => false, } PUPPETCODE it 'applies' do apply_manifest(pp77, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m multiport --ports 584 -m comment --comment "584 - test" -j ACCEPT}) end end end end # RHEL5/SLES does not support -m socket describe 'socket', unless: (default['platform'] =~ %r{el-5} || fact('operatingsystem') == 'SLES') do context 'when true' do pp78 = <<-PUPPETCODE class { '::firewall': } firewall { '585 - test': ensure => present, proto => tcp, port => '585', action => accept, chain => 'PREROUTING', table => 'nat', socket => true, } PUPPETCODE it 'applies' do apply_manifest(pp78, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A PREROUTING -p tcp -m multiport --ports 585 -m socket -m comment --comment "585 - test" -j ACCEPT}) end end end context 'when false' do pp79 = <<-PUPPETCODE class { '::firewall': } firewall { '586 - test': ensure => present, proto => tcp, port => '586', action => accept, chain => 'PREROUTING', table => 'nat', socket => false, } PUPPETCODE it 'applies' do apply_manifest(pp79, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A PREROUTING -p tcp -m multiport --ports 586 -m comment --comment "586 - test" -j ACCEPT}) end end end end describe 'ipsec_policy' do context 'when ipsec' do pp80 = <<-PUPPETCODE class { '::firewall': } firewall { '593 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '20.0.0.0/8', ipsec_dir => 'out', ipsec_policy => 'ipsec', proto => 'all', reject => 'icmp-net-unreachable', table => 'filter', } PUPPETCODE it 'applies' do apply_manifest(pp80, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol ipsec -m comment --comment "593 - test" -j REJECT --reject-with icmp-net-unreachable}) end end end context 'when none' do pp81 = <<-PUPPETCODE class { '::firewall': } firewall { '594 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '20.0.0.0/8', ipsec_dir => 'out', ipsec_policy => 'none', proto => 'all', reject => 'icmp-net-unreachable', table => 'filter', } PUPPETCODE it 'applies' do apply_manifest(pp81, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol none -m comment --comment "594 - test" -j REJECT --reject-with icmp-net-unreachable}) end end end end describe 'ipsec_dir' do context 'when out' do pp82 = <<-PUPPETCODE class { '::firewall': } firewall { '595 - test': ensure => 'present', action => 'reject', chain => 'OUTPUT', destination => '20.0.0.0/8', ipsec_dir => 'out', ipsec_policy => 'ipsec', proto => 'all', reject => 'icmp-net-unreachable', table => 'filter', } PUPPETCODE it 'applies' do apply_manifest(pp82, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir out --pol ipsec -m comment --comment "595 - test" -j REJECT --reject-with icmp-net-unreachable}) end end end context 'when in' do pp83 = <<-PUPPETCODE class { '::firewall': } firewall { '596 - test': ensure => 'present', action => 'reject', chain => 'INPUT', destination => '20.0.0.0/8', ipsec_dir => 'in', ipsec_policy => 'none', proto => 'all', reject => 'icmp-net-unreachable', table => 'filter', } PUPPETCODE it 'applies' do apply_manifest(pp83, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m policy --dir in --pol none -m comment --comment "596 - test" -j REJECT --reject-with icmp-net-unreachable}) end end end end describe 'recent' do context 'when set' do pp84 = <<-PUPPETCODE class { '::firewall': } firewall { '597 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'set', rdest => true, rname => 'list1', } PUPPETCODE it 'applies' do apply_manifest(pp84, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| # Mask added as of Ubuntu 14.04. expect(r.stdout).to match(%r{-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --set --name list1 (--mask 255.255.255.255 )?--rdest -m comment --comment "597 - test"}) end end end context 'when rcheck' do pp85 = <<-PUPPETCODE class { '::firewall': } firewall { '598 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'rcheck', rsource => true, rname => 'list1', rseconds => 60, rhitcount => 5, rttl => true, } PUPPETCODE it 'applies' do apply_manifest(pp85, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --rcheck --seconds 60 --hitcount 5 --rttl --name list1 (--mask 255.255.255.255 )?--rsource -m comment --comment "598 - test"}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end context 'when update' do pp86 = <<-PUPPETCODE class { '::firewall': } firewall { '599 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'update', } PUPPETCODE it 'applies' do apply_manifest(pp86, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --update --name DEFAULT (--mask 255.255.255.255 )?--rsource -m comment --comment "599 - test"}) end end end context 'when remove' do pp87 = <<-PUPPETCODE class { '::firewall': } firewall { '600 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'remove', } PUPPETCODE it 'applies' do apply_manifest(pp87, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m recent --remove --name DEFAULT (--mask 255.255.255.255 )?--rsource -m comment --comment "600 - test"}) end end end end describe 'mac_source' do context 'when 0A:1B:3C:4D:5E:6F' do pp88 = <<-PUPPETCODE class { '::firewall': } firewall { '610 - test': ensure => present, source => '10.1.5.28/32', mac_source => '0A:1B:3C:4D:5E:6F', chain => 'INPUT', } PUPPETCODE it 'applies' do apply_manifest(pp88, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| if (fact('osfamily') == 'RedHat' && fact('operatingsystemmajrelease') == '5') || (default['platform'] =~ %r{sles-10}) expect(r.stdout).to match(%r{-A INPUT -s 10.1.5.28 -p tcp -m mac --mac-source 0A:1B:3C:4D:5E:6F -m comment --comment "610 - test"}) else expect(r.stdout).to match(%r{-A INPUT -s 10.1.5.28\/(32|255\.255\.255\.255) -p tcp -m mac --mac-source 0A:1B:3C:4D:5E:6F -m comment --comment "610 - test"}) end end end # rubocop:enable RSpec/ExampleLength : Cannot reduce lines to required size end end describe 'reset' do it 'deletes all rules' do shell('ip6tables --flush') shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end end describe 'to' do context 'when Destination netmap 192.168.1.1' do pp89 = <<-PUPPETCODE class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'PREROUTING', jump => 'NETMAP', source => '200.200.200.200', to => '192.168.1.1', } PUPPETCODE it 'applies' do apply_manifest(pp89, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A PREROUTING -s 200.200.200.200(\/32)? -p tcp -m comment --comment "569 - test" -j NETMAP --to 192.168.1.1}) end end end describe 'reset' do it 'deletes all rules' do shell('ip6tables --flush') shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end end context 'when Source netmap 192.168.1.1' do pp90 = <<-PUPPETCODE class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'POSTROUTING', jump => 'NETMAP', destination => '200.200.200.200', to => '192.168.1.1', } PUPPETCODE it 'applies' do apply_manifest(pp90, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(%r{-A POSTROUTING -d 200.200.200.200(\/32)? -p tcp -m comment --comment "569 - test" -j NETMAP --to 192.168.1.1}) end end end end context 'when log_prefix containing -A' do pp91 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - test': jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } PUPPETCODE it 'adds the rule' do apply_manifest(pp91, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m comment --comment "700 - test" -j LOG --log-prefix "FW-A-INPUT: "}) end end pp92 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - test': ensure => absent, jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } PUPPETCODE it 'removes the rule' do apply_manifest(pp92, catch_failures: true) end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m comment --comment "700 - test" -j LOG --log-prefix "FW-A-INPUT: "}) end end end context 'when log_uid is true' do pp93 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - test log_uid': chain => 'OUTPUT', jump => 'LOG', log_uid => true, } PUPPETCODE it 'adds the rule' do apply_manifest(pp93, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m comment --comment "700 - test log_uid" -j LOG --log-uid}) end end pp94 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - test log_uid': chain => 'OUTPUT', jump => 'LOG', log_uid => false, ensure => absent, } PUPPETCODE it 'removes the rule' do apply_manifest(pp94, catch_failures: true) end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A OUTPUT -p tcp -m comment --comment "700 - test log_uid" -j --log-uid}) end end end context 'when comment containing "-A "' do pp95 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - blah-A Test Rule': jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } PUPPETCODE it 'adds the rule' do apply_manifest(pp95, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m comment --comment "700 - blah-A Test Rule" -j LOG --log-prefix "FW-A-INPUT: "}) end end pp96 = <<-PUPPETCODE class { '::firewall': } firewall { '700 - blah-A Test Rule': ensure => absent, jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } PUPPETCODE it 'removes the rule' do apply_manifest(pp96, catch_failures: true) end it 'does not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m comment --comment "700 - blah-A Test Rule" -j LOG --log-prefix "FW-A-INPUT: "}) end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_tee_spec.rb0100644005276200011600000000355213232340436021570 0ustar00require 'spec_helper_acceptance' describe 'firewall tee' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end if default['platform'] =~ %r{ubuntu-1404} || default['platform'] =~ %r{ubuntu-1204} || default['platform'] =~ %r{debian-7} || default['platform'] =~ %r{debian-8} || default['platform'] =~ %r{el-7} describe 'tee_gateway' do context 'when 10.0.0.2' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '810 - tee_gateway': chain => 'PREROUTING', table => 'mangle', jump => 'TEE', gateway => '10.0.0.2', proto => all, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) end it 'contains the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A PREROUTING -m comment --comment "810 - tee_gateway" -j TEE --gateway 10.0.0.2}) end end end end describe 'tee_gateway6' do context 'when 2001:db8::1' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '811 - tee_gateway6': chain => 'PREROUTING', table => 'mangle', jump => 'TEE', gateway => '2001:db8::1', proto => all, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(%r{-A PREROUTING -m comment --comment "811 - tee_gateway6" -j TEE --gateway 2001:db8::1}) end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_time_spec.rb0100644005276200011600000000603613232340436021751 0ustar00require 'spec_helper_acceptance' describe 'firewall time' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end if default['platform'] =~ %r{ubuntu-1404} || default['platform'] =~ %r{debian-7} || default['platform'] =~ %r{debian-8} || default['platform'] =~ %r{el-7} describe 'time tests ipv4' do context 'when set all time parameters' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '805 - test': proto => tcp, dport => '8080', action => accept, chain => 'OUTPUT', date_start => '2016-01-19T04:17:07', date_stop => '2038-01-19T04:17:07', time_start => '6:00', time_stop => '17:00:00', month_days => '7', week_days => 'Tue', kernel_timezone => true, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --dports 8080 -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -m comment --comment "805 - test" -j ACCEPT}) # rubocop:disable Metrics/LineLength : Cannot reduce line length to the required size end end end end describe 'time tests ipv6' do context 'when when set all time parameters' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '805 - test': proto => tcp, dport => '8080', action => accept, chain => 'OUTPUT', date_start => '2016-01-19T04:17:07', date_stop => '2038-01-19T04:17:07', time_start => '6:00', time_stop => '17:00:00', month_days => '7', week_days => 'Tue', kernel_timezone => true, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -p tcp -m multiport --dports 8080 -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -m comment --comment "805 - test" -j ACCEPT}) # rubocop:disable Metrics/LineLength : Cannot reduce line length to the required size end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewall_uid_spec.rb0100644005276200011600000000532113232340436021570 0ustar00require 'spec_helper_acceptance' describe 'firewall uid' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'uid tests' do context 'when uid set to root' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - test': chain => 'OUTPUT', action => accept, uid => 'root', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner --uid-owner (0|root) -m comment --comment "801 - test" -j ACCEPT}) end end end context 'when uid set to !root' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - test': chain => 'OUTPUT', action => accept, uid => '!root', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner ! --uid-owner (0|root) -m comment --comment "802 - test" -j ACCEPT}) end end end context 'when uid set to 0' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '803 - test': chain => 'OUTPUT', action => accept, uid => '0', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) apply_manifest(pp3, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner --uid-owner (0|root) -m comment --comment "803 - test" -j ACCEPT}) end end end context 'when uid set to !0' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '804 - test': chain => 'OUTPUT', action => accept, uid => '!0', proto => 'all', } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) apply_manifest(pp4, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A OUTPUT -m owner ! --uid-owner (0|root) -m comment --comment "804 - test" -j ACCEPT}) end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/firewallchain_spec.rb0100644005276200011600000000666213232340436021743 0ustar00require 'spec_helper_acceptance' describe 'puppet resource firewallchain command' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'ensure' do context 'when present' do pp1 = <<-PUPPETCODE firewallchain { 'MY_CHAIN:filter:IPv4': ensure => present, } PUPPETCODE it 'applies cleanly' do # Run it twice and test for idempotency apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end it 'finds the chain' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{MY_CHAIN}) end end end context 'when absent' do pp2 = <<-PUPPETCODE firewallchain { 'MY_CHAIN:filter:IPv4': ensure => absent, } PUPPETCODE it 'applies cleanly' do # Run it twice and test for idempotency apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end it 'fails to find the chain' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{MY_CHAIN}) end end end end # XXX purge => false is not yet implemented # context 'when adding a firewall rule to a chain:' do # pp3 = <<-PUPPETCODE # firewallchain { 'MY_CHAIN:filter:IPv4': # ensure => present, # } # firewall { '100 my rule': # chain => 'MY_CHAIN', # action => 'accept', # proto => 'tcp', # dport => 5000, # } # PUPPETCODE # it 'applies cleanly' do # # Run it twice and test for idempotency # apply_manifest(pp3, :catch_failures => true) # apply_manifest(pp3, :catch_changes => do_catch_changes) # end # end # context 'when not purge firewallchain chains:' do # pp4 = <<-PUPPETCODE # firewallchain { 'MY_CHAIN:filter:IPv4': # ensure => present, # purge => false, # before => Resources['firewall'], # } # resources { 'firewall': # purge => true, # } # PUPPETCODE # it 'does not purge the rule' do # # Run it twice and test for idempotency # apply_manifest(pp4, :catch_failures => true) do |r| # expect(r.stdout).to_not match(/removed/) # expect(r.stderr).to eq('') # end # apply_manifest(pp4, :catch_changes => do_catch_changes) # end # pp5 = <<-PUPPETCODE # firewall { '100 my rule': # chain => 'MY_CHAIN', # action => 'accept', # proto => 'tcp', # dport => 5000, # } # PUPPETCODE # it 'still has the rule' do # # Run it twice and test for idempotency # apply_manifest(pp5, :catch_changes => do_catch_changes) # end # end describe 'policy' do after :all do shell('iptables -t filter -P FORWARD ACCEPT') end context 'when DROP' do pp6 = <<-PUPPETCODE firewallchain { 'FORWARD:filter:IPv4': policy => 'drop', } PUPPETCODE it 'applies cleanly' do # Run it twice and test for idempotency apply_manifest(pp6, catch_failures: true) apply_manifest(pp6, catch_changes: do_catch_changes) end it 'finds the chain' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{FORWARD DROP}) end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/hashlimit_spec.rb0100644005276200011600000001165113232340436021107 0ustar00 require 'spec_helper_acceptance' describe 'hashlimit property', if: fact('operatingsystemmajrelease') != '5' && (fact('operatingsystem') != 'Scientific' || fact('operatingsystem') != 'RedHat') do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end describe 'hashlimit_tests' do context 'when hashlimit_above' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '800 - hashlimit_above test': chain => 'INPUT', proto => 'tcp', hashlimit_name => 'above', hashlimit_above => '526/sec', hashlimit_htable_gcinterval => '10', hashlimit_mode => 'srcip,dstip', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end regex_array = [%r{-A INPUT}, %r{-p tcp}, %r{--hashlimit-above 526\/sec}, %r{--hashlimit-mode srcip,dstip}, %r{--hashlimit-name above}, %r{--hashlimit-htable-gcinterval 10}, %r{-j ACCEPT}] it 'contains the rule' do shell('iptables-save') do |r| regex_array.each do |regex| expect(r.stdout).to match(regex) end end end end context 'when hashlimit_above_ip6' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '801 - hashlimit_above test ipv6': chain => 'INPUT', provider => 'ip6tables', proto => 'tcp', hashlimit_name => 'above-ip6', hashlimit_above => '526/sec', hashlimit_htable_gcinterval => '10', hashlimit_mode => 'srcip,dstip', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end regex_array = [%r{-A INPUT}, %r{-p tcp}, %r{--hashlimit-above 526\/sec}, %r{--hashlimit-mode srcip,dstip}, %r{--hashlimit-name above-ip6}, %r{--hashlimit-htable-gcinterval 10}, %r{-j ACCEPT}] it 'contains the rule' do shell('ip6tables-save') do |r| regex_array.each do |regex| expect(r.stdout).to match(regex) end end end end context 'when hashlimit_upto' do pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '802 - hashlimit_upto test': chain => 'INPUT', hashlimit_name => 'upto', hashlimit_upto => '16/sec', hashlimit_burst => '640', hashlimit_htable_size => '1310000', hashlimit_htable_max => '320000', hashlimit_htable_expire => '36000000', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp3, catch_failures: true) apply_manifest(pp3, catch_changes: do_catch_changes) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m hashlimit --hashlimit-upto 16\/sec --hashlimit-burst 640 --hashlimit-name upto --hashlimit-htable-size 1310000 --hashlimit-htable-max 320000 --hashlimit-htable-expire 36000000 -m comment --comment "802 - hashlimit_upto test" -j ACCEPT}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end context 'when hashlimit_upto_ip6' do pp4 = <<-PUPPETCODE class { '::firewall': } firewall { '803 - hashlimit_upto test ip6': chain => 'INPUT', provider => 'ip6tables', hashlimit_name => 'upto-ip6', hashlimit_upto => '16/sec', hashlimit_burst => '640', hashlimit_htable_size => '1310000', hashlimit_htable_max => '320000', hashlimit_htable_expire => '36000000', action => accept, } PUPPETCODE it 'applies' do apply_manifest(pp4, catch_failures: true) apply_manifest(pp4, catch_changes: do_catch_changes) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -p tcp -m hashlimit --hashlimit-upto 16\/sec --hashlimit-burst 640 --hashlimit-name upto-ip6 --hashlimit-htable-size 1310000 --hashlimit-htable-max 320000 --hashlimit-htable-expire 36000000 -m comment --comment "803 - hashlimit_upto test ip6" -j ACCEPT}) # rubocop:disable Metrics/LineLength : Cannot reduce line to required length end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/invert_spec.rb0100644005276200011600000000352713232340436020437 0ustar00require 'spec_helper_acceptance' describe 'firewall inverting' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end context 'when inverting rules' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '601 disallow esp protocol': action => 'accept', proto => '! esp', } firewall { '602 drop NEW external website packets with FIN/RST/ACK set and SYN unset': chain => 'INPUT', state => 'NEW', action => 'drop', proto => 'tcp', sport => ['! http', '! 443'], source => '! 10.0.0.0/8', tcp_flags => '! FIN,SYN,RST,ACK SYN', } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) end regex_array = [%r{-A INPUT (-s !|! -s) (10\.0\.0\.0\/8|10\.0\.0\.0\/255\.0\.0\.0).*}, %r{-A INPUT.*(--sports !|! --sports) 80,443.*}, %r{-A INPUT.*-m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN.*}, %r{-A INPUT.*-j DROP}, %r{-A INPUT (! -p|-p !) esp -m comment --comment "601 disallow esp protocol" -j ACCEPT}] it 'contains the rules' do shell('iptables-save') do |r| regex_array.each do |regex| expect(r.stdout).to match(regex) end end end end context 'when inverting partial array rules' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '603 drop 80,443 traffic': chain => 'INPUT', action => 'drop', proto => 'tcp', sport => ['! http', '443'], } PUPPETCODE it 'raises a failure' do apply_manifest(pp2, expect_failures: true) do |r| expect(r.stderr).to match(%r{is not prefixed}) end end end end puppetlabs-firewall-1.12.0/spec/acceptance/ip6_fragment_spec.rb0100644005276200011600000001077313232340436021512 0ustar00require 'spec_helper_acceptance' if default['platform'] =~ %r{el-5} || default['platform'] =~ %r{sles-10} describe "firewall ip6tables doesn't work on 1.3.5 because --comment is missing" do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', } PUPPETCODE it "can't use ip6tables" do expect(apply_manifest(pp1, expect_failures: true).stderr).to match(%r{ip6tables provider is not supported}) end end else describe 'firewall ishasmorefrags/islastfrag/isfirstfrag properties' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end shared_examples 'is idempotent' do |values, line_match| pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', #{values} } PUPPETCODE it "changes the values to #{values}" do apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end shared_examples "doesn't change" do |values, line_match| pp3 = <<-PUPPETCODE class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', #{values} } PUPPETCODE it "doesn't change the values to #{values}" do apply_manifest(pp3, catch_changes: do_catch_changes) shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end describe 'adding a rule' do context 'when unset' do before :all do ip6tables_flush_all_tables end it_behaves_like 'is idempotent', '', %r{-A INPUT -p tcp -m comment --comment "599 - test"} end context 'when set to true' do before :all do ip6tables_flush_all_tables end it_behaves_like 'is idempotent', 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', %r{-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"} end context 'when set to false' do before :all do ip6tables_flush_all_tables end it_behaves_like 'is idempotent', 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', %r{-A INPUT -p tcp -m comment --comment "599 - test"} end end describe 'editing a rule' do context 'when unset or false' do before :each do ip6tables_flush_all_tables shell('ip6tables -A INPUT -p tcp -m comment --comment "599 - test"') end context 'when current value is false' do it_behaves_like "doesn't change", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', %r{-A INPUT -p tcp -m comment --comment "599 - test"} end context 'when current value is true' do it_behaves_like 'is idempotent', 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', %r{-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"} end end context 'when set to true' do before :each do ip6tables_flush_all_tables shell('ip6tables -A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"') end context 'when current value is false' do it_behaves_like 'is idempotent', 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', %r{-A INPUT -p tcp -m comment --comment "599 - test"} end context 'when current value is true' do it_behaves_like "doesn't change", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', %r{-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"} end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/isfragment_spec.rb0100644005276200011600000000622513232340436021265 0ustar00require 'spec_helper_acceptance' describe 'firewall isfragment property' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end shared_examples 'is idempotent' do |value, line_match| pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '597 - test': ensure => present, proto => 'tcp', #{value} } PUPPETCODE it "changes the value to #{value}" do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: do_catch_changes) shell('iptables-save') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end shared_examples "doesn't change" do |value, line_match| pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '597 - test': ensure => present, proto => 'tcp', #{value} } PUPPETCODE it "doesn't change the value to #{value}" do apply_manifest(pp2, catch_changes: do_catch_changes) shell('iptables-save') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end describe 'adding a rule' do context 'when unset' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', '', %r{-A INPUT -p tcp -m comment --comment "597 - test"} end context 'when set to true' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', 'isfragment => true,', %r{-A INPUT -p tcp -f -m comment --comment "597 - test"} end context 'when set to false' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', 'isfragment => false,', %r{-A INPUT -p tcp -m comment --comment "597 - test"} end end describe 'editing a rule and current value is false' do context 'when unset or false' do before :each do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -m comment --comment "597 - test"') end it_behaves_like "doesn't change", 'isfragment => false,', %r{-A INPUT -p tcp -m comment --comment "597 - test"} end context 'when unset or false and current value is true' do before :each do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -m comment --comment "597 - test"') end it_behaves_like 'is idempotent', 'isfragment => true,', %r{-A INPUT -p tcp -f -m comment --comment "597 - test"} end context 'when set to true and current value is false' do before :each do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -f -m comment --comment "597 - test"') end it_behaves_like 'is idempotent', 'isfragment => false,', %r{-A INPUT -p tcp -m comment --comment "597 - test"} end context 'when set to trueand current value is true' do before :each do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -f -m comment --comment "597 - test"') end it_behaves_like "doesn't change", 'isfragment => true,', %r{-A INPUT -p tcp -f -m comment --comment "597 - test"} end end end puppetlabs-firewall-1.12.0/spec/acceptance/match_mark_spec.rb0100644005276200011600000000317313232340436021233 0ustar00require 'spec_helper_acceptance' describe 'firewall match marks' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} describe 'match_mark' do context 'when 0x1' do pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '503 match_mark - test': proto => 'all', match_mark => '0x1', action => reject, } PUPPETCODE it 'applies' do apply_manifest(pp1, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -m mark --mark 0x1 -m comment --comment "503 match_mark - test" -j REJECT --reject-with icmp-port-unreachable}) end end end end describe 'match_mark_ip6' do context 'when 0x1' do pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '503 match_mark ip6tables - test': proto => 'all', match_mark => '0x1', action => reject, provider => 'ip6tables', } PUPPETCODE it 'applies' do apply_manifest(pp2, catch_failures: true) end it 'contains the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{-A INPUT -m mark --mark 0x1 -m comment --comment "503 match_mark ip6tables - test" -j REJECT --reject-with icmp6-port-unreachable}) end end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/nflog_spec.rb0100644005276200011600000000555213232340436020235 0ustar00require 'spec_helper_acceptance' describe 'nflog on older OSes', if: fact('iptables_version') < '1.3.7' do # rubocop:disable RSpec/MultipleDescribes : Describes are clearly seperate pp1 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_group => 3, } PUPPETCODE it 'throws an error' do apply_manifest(pp1, acceptable_error_codes: [0]) end end describe 'nflog', unless: fact('iptables_version') < '1.3.7' do describe 'nflog_group' do let(:group) { 3 } it 'applies' do pp2 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_group => #{group}} PUPPETCODE apply_manifest(pp2, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{NFLOG --nflog-group #{group}}) end end end describe 'nflog_prefix' do let(:prefix) { 'TEST PREFIX' } it 'applies' do pp3 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_prefix => '#{prefix}'} PUPPETCODE apply_manifest(pp3, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{NFLOG --nflog-prefix +"#{prefix}"}) end end end describe 'nflog_range' do let(:range) { 16 } it 'applies' do pp4 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_range => #{range}} PUPPETCODE apply_manifest(pp4, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{NFLOG --nflog-range #{range}}) end end end describe 'nflog_threshold' do let(:threshold) { 2 } it 'applies' do pp5 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_threshold => #{threshold}} PUPPETCODE apply_manifest(pp5, catch_failures: true) end it 'contains the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{NFLOG --nflog-threshold #{threshold}}) end end end describe 'multiple rules' do let(:threshold) { 2 } let(:group) { 3 } it 'applies' do pp6 = <<-PUPPETCODE class {'::firewall': } firewall { '503 - test': jump => 'NFLOG', proto => 'all', nflog_threshold => #{threshold}, nflog_group => #{group}} PUPPETCODE apply_manifest(pp6, catch_failures: true) end it 'contains the rules' do shell('iptables-save') do |r| expect(r.stdout).to match(%r{NFLOG --nflog-group #{group} --nflog-threshold #{threshold}}) end end end end puppetlabs-firewall-1.12.0/spec/acceptance/nodesets0040755005276200011600000000000013232340576017337 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/centos-7-x64.yml0100644005276200011600000000025613102663532022213 0ustar00HOSTS: centos-7-x64: roles: - agent - default platform: el-7-x86_64 hypervisor: vagrant box: puppetlabs/centos-7.2-64-nocm CONFIG: type: foss puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/debian-8-x64.yml0100644005276200011600000000026113102663532022137 0ustar00HOSTS: debian-8-x64: roles: - agent - default platform: debian-8-amd64 hypervisor: vagrant box: puppetlabs/debian-8.2-64-nocm CONFIG: type: foss puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/default.yml0100644005276200011600000000027213102663532021557 0ustar00HOSTS: ubuntu-1404-x64: roles: - agent - default platform: ubuntu-14.04-amd64 hypervisor: vagrant box: puppetlabs/ubuntu-14.04-64-nocm CONFIG: type: foss puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/docker0040755005276200011600000000000013232340576020606 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/docker/centos-7.yml0100644005276200011600000000057513102663532023047 0ustar00HOSTS: centos-7-x64: platform: el-7-x86_64 hypervisor: docker image: centos:7 docker_preserve_image: true docker_cmd: '["/usr/sbin/init"]' # install various tools required to get the image up to usable levels docker_image_commands: - 'yum install -y crontabs tar wget openssl sysvinit-tools iproute which initscripts' CONFIG: trace_limit: 200 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/docker/debian-8.yml0100644005276200011600000000054413102663532022773 0ustar00HOSTS: debian-8-x64: platform: debian-8-amd64 hypervisor: docker image: debian:8 docker_preserve_image: true docker_cmd: '["/sbin/init"]' docker_image_commands: - 'apt-get update && apt-get install -y net-tools wget locales strace lsof && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen' CONFIG: trace_limit: 200 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/docker/ubuntu-14.04.yml0100644005276200011600000000073213102663532023371 0ustar00HOSTS: ubuntu-1404-x64: platform: ubuntu-14.04-amd64 hypervisor: docker image: ubuntu:14.04 docker_preserve_image: true docker_cmd: '["/sbin/init"]' docker_image_commands: # ensure that upstart is booting correctly in the container - 'rm /usr/sbin/policy-rc.d && rm /sbin/initctl && dpkg-divert --rename --remove /sbin/initctl && apt-get update && apt-get install -y net-tools wget && locale-gen en_US.UTF-8' CONFIG: trace_limit: 200 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new0040755005276200011600000000000013232340576020130 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio0040755005276200011600000000000013232340576020700 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio/debian-8-64mda.yml0100644005276200011600000000113413102663532023772 0ustar00--- HOSTS: debian-8-amd64-agent: roles: - agent - default platform: debian-8-amd64 template: debian-8-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio/redhat-6-64mda.yml0100644005276200011600000000113013102663532024011 0ustar00--- HOSTS: redhat-6-x86_64-agent: roles: - agent - default platform: el-6-x86_64 template: redhat-6-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio/redhat-7-64mda.yml0100644005276200011600000000113013102663532024012 0ustar00--- HOSTS: redhat-7-x86_64-agent: roles: - agent - default platform: el-7-x86_64 template: redhat-7-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio/ubuntu-1404-64mda.yml0100644005276200011600000000121213102663532024310 0ustar00--- HOSTS: ubuntu-1404-agent: roles: - agent - default platform: ubuntu-14.04-amd64 template: Delivery/Quality Assurance/Templates/vCloud/ubuntu-1404-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/aio/ubuntu-1604-64mda.yml0100644005276200011600000000121313102663532024313 0ustar00--- 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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe0040755005276200011600000000000013232340576020534 5ustar00puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/centos-5-64mda.yml0100644005276200011600000000117113102663532023675 0ustar00--- HOSTS: centos-5-x86_64-agent: roles: - agent - default platform: el-5-x86_64 template: Delivery/Quality Assurance/Templates/vCloud/centos-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/centos-6-64mda.yml0100644005276200011600000000117113102663532023676 0ustar00--- HOSTS: centos-6-x86_64-agent: roles: - agent - default platform: el-6-x86_64 template: Delivery/Quality Assurance/Templates/vCloud/centos-6-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/centos-7-64mda.yml0100644005276200011600000000111513102663532023675 0ustar00--- HOSTS: centos-7-x86_64-agent: roles: - agent - default platform: el-7-x86_64 template: centos-7-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/debian-6-64mda.yml0100644005276200011600000000111713102663532023625 0ustar00--- HOSTS: debian-6-amd64-agent: roles: - agent - default platform: debian-6-amd64 template: debian-6-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/debian-7-64mda.yml0100644005276200011600000000111613102663532023625 0ustar00--- HOSTS: debian-7-amd64-agent: roles: - agent - default platform: debian-7-amd64 template: debian-7-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/debian-8-64mda.yml0100644005276200011600000000112013102663532023621 0ustar00--- HOSTS: debian-8-amd64-agent: roles: - agent - default platform: debian-8-amd64 template: debian-8-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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/oracle-5-64mda.yml0100644005276200011600000000111513102663532023645 0ustar00--- 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 puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/oracle-6-64mda.yml0100644005276200011600000000111413102663532023645 0ustar00--- HOSTS: oracle-6-x86_64-agent: roles: - agent - default platform: el-6-x86_64 template: oracle-6-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/oracle-7-64mda.yml0100644005276200011600000000111413102663532023646 0ustar00--- HOSTS: oracle-7-x86_64-agent: roles: - agent - default platform: el-7-x86_64 template: oracle-7-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/redhat-5-64mda.yml0100644005276200011600000000111413102663532023646 0ustar00--- HOSTS: redhat-5-x86_64-agent: roles: - agent - default platform: el-5-x86_64 template: redhat-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/redhat-6-64mda.yml0100644005276200011600000000111413102663532023647 0ustar00--- HOSTS: redhat-6-x86_64-agent: roles: - agent - default platform: el-6-x86_64 template: redhat-6-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/redhat-7-64mda.yml0100644005276200011600000000111413102663532023650 0ustar00--- HOSTS: redhat-7-x86_64-agent: roles: - agent - default platform: el-7-x86_64 template: redhat-7-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/scientific-5-64mda.yml0100644005276200011600000000112413102663532024520 0ustar00--- HOSTS: scientific-5-x86_64-agent: roles: - agent - default platform: el-5-x86_64 template: scientific-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/scientific-6-64mda.yml0100644005276200011600000000112413102663532024521 0ustar00--- HOSTS: scientific-6-x86_64-agent: roles: - agent - default platform: el-6-x86_64 template: scientific-6-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/scientific-7-64mda.yml0100644005276200011600000000112413102663532024522 0ustar00--- HOSTS: scientific-7-x86_64-agent: roles: - agent - default platform: el-7-x86_64 template: scientific-7-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/sles-10-64mda.yml0100644005276200011600000000111513102663532023422 0ustar00--- HOSTS: sles-10-x86_64-agent: roles: - agent - default platform: sles-10-x86_64 template: sles-10-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/sles-11-64mda.yml0100644005276200011600000000111513102663532023423 0ustar00--- HOSTS: sles-11-x86_64-agent: roles: - agent - default platform: sles-11-x86_64 template: sles-11-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/sles-12-64mda.yml0100644005276200011600000000111513102663532023424 0ustar00--- HOSTS: sles-12-x86_64-agent: roles: - agent - default platform: sles-12-x86_64 template: sles-12-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/ubuntu-1004-64mda.yml0100644005276200011600000000112213102663532024140 0ustar00--- HOSTS: ubuntu-1004-agent: roles: - agent - default platform: ubuntu-10.04-amd64 template: ubuntu-1004-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/ubuntu-1204-64mda.yml0100644005276200011600000000117613102663532024153 0ustar00--- HOSTS: ubuntu-1204-agent: roles: - agent - default platform: ubuntu-12.04-amd64 template: Delivery/Quality Assurance/Templates/vCloud/ubuntu-1204-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/ubuntu-1404-64mda.yml0100644005276200011600000000117613102663532024155 0ustar00--- HOSTS: ubuntu-1404-agent: roles: - agent - default platform: ubuntu-14.04-amd64 template: Delivery/Quality Assurance/Templates/vCloud/ubuntu-1404-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: 600puppetlabs-firewall-1.12.0/spec/acceptance/nodesets/new/pe/ubuntu-1604-64mda.yml0100644005276200011600000000117713102663532024160 0ustar00--- 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 puppetlabs-firewall-1.12.0/spec/acceptance/params_spec.rb0100644005276200011600000000726413232340436020415 0ustar00require 'spec_helper_acceptance' describe 'param based tests' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end ppm1 = <<-PUPPETCODE firewall { '100 test': table => 'raw', socket => 'true', chain => 'PREROUTING', jump => 'LOG', log_level => 'debug', } PUPPETCODE values = [2, 0] it 'test various params', unless: (default['platform'].match(%r{el-5}) || fact('operatingsystem') == 'SLES') do iptables_flush_all_tables values.each do |value| expect(apply_manifest(ppm1, catch_failures: true).exit_code).to eq(value) end end ppm2 = <<-PUPPETCODE firewall { '998 log all': proto => 'all', jump => 'LOG', log_level => 'debug', } PUPPETCODE values = [2, 0] it 'test log rule' do iptables_flush_all_tables values.each do |value| expect(apply_manifest(ppm2, catch_failures: true).exit_code).to eq(value) end end ppm3 = <<-PUPPETCODE firewall { '004 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } PUPPETCODE ppm4 = <<-PUPPETCODE firewall { '003 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } PUPPETCODE ppm5 = <<-PUPPETCODE + "\n" + ppm4 resources { 'firewall': purge => true, } PUPPETCODE it 'test log rule - changing names' do iptables_flush_all_tables expect(apply_manifest(ppm3, catch_failures: true).exit_code).to eq(2) expect(apply_manifest(ppm5, catch_failures: true).exit_code).to eq(2) end ppm6 = <<-PUPPETCODE firewall { '004 with a chain': chain => 'INPUT', proto => 'all', } PUPPETCODE ppm7 = <<-PUPPETCODE firewall { '004 with a chain': chain => 'OUTPUT', proto => 'all', } PUPPETCODE _ppm8 = <<-PUPPETCODE + "\n" + ppm7 resources { 'firewall': purge => true, } PUPPETCODE it 'test chain - changing names' do iptables_flush_all_tables apply_manifest(ppm6, expect_changes: true) expect(apply_manifest(ppm7, expect_failures: true).stderr).to match(%r{is not supported}) end ppm9 = <<-PUPPETCODE firewall { '004 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } PUPPETCODE values = [2, 0] it 'test log rule - idempotent' do iptables_flush_all_tables values.each do |value| expect(apply_manifest(ppm9, catch_failures: true).exit_code).to eq(value) end end ppm10 = <<-PUPPETCODE firewall { '997 block src ip range': chain => 'INPUT', proto => 'all', action => 'drop', src_range => '10.0.0.1-10.0.0.10', } PUPPETCODE values = [2, 0] it 'test src_range rule' do iptables_flush_all_tables values.each do |value| expect(apply_manifest(ppm10, catch_failures: true).exit_code).to eq(value) end end ppm11 = <<-PUPPETCODE firewall { '998 block dst ip range': chain => 'INPUT', proto => 'all', action => 'drop', dst_range => '10.0.0.2-10.0.0.20', } PUPPETCODE values = [2, 0] it 'test dst_range rule' do iptables_flush_all_tables values.each do |value| expect(apply_manifest(ppm11, catch_failures: true).exit_code).to eq(value) end end end puppetlabs-firewall-1.12.0/spec/acceptance/purge_spec.rb0100644005276200011600000001423413232340436020247 0ustar00require 'spec_helper_acceptance' describe 'purge tests' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end context('when resources purge') do before(:all) do iptables_flush_all_tables shell('iptables -A INPUT -s 1.2.1.2') shell('iptables -A INPUT -s 1.2.1.2') end pp1 = <<-PUPPETCODE class { 'firewall': } resources { 'firewall': purge => true, } PUPPETCODE it 'make sure duplicate existing rules get purged' do apply_manifest(pp1, expect_changes: true) end it 'saves' do shell('iptables-save') do |r| expect(r.stdout).not_to match(%r{1\.2\.1\.2}) expect(r.stderr).to eq('') end end end context('when ipv4 chain purge') do after(:all) do iptables_flush_all_tables end before(:each) do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -s 1.2.1.1') shell('iptables -A INPUT -p udp -s 1.2.1.1') shell('iptables -A OUTPUT -s 1.2.1.2 -m comment --comment "010 output-1.2.1.2"') end pp2 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv4': purge => true, } PUPPETCODE it 'purges only the specified chain' do apply_manifest(pp2, expect_changes: true) shell('iptables-save') do |r| expect(r.stdout).to match(%r{010 output-1\.2\.1\.2}) expect(r.stdout).not_to match(%r{1\.2\.1\.1}) expect(r.stderr).to eq('') end end # rubocop:enable RSpec/ExampleLength pp3 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'OUTPUT:filter:IPv4': purge => true, } firewall { '010 output-1.2.1.2': chain => 'OUTPUT', proto => 'all', source => '1.2.1.2', } PUPPETCODE it 'ignores managed rules' do apply_manifest(pp3, catch_changes: do_catch_changes) end pp4 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv4': purge => true, ignore => [ '-s 1\.2\.1\.1', ], } PUPPETCODE it 'ignores specified rules' do apply_manifest(pp4, catch_changes: do_catch_changes) end pp5 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv4': purge => true, ignore => [ '-s 1\.2\.1\.1', ], } firewall { '014 input-1.2.1.6': chain => 'INPUT', proto => 'all', source => '1.2.1.6', } -> firewall { '013 input-1.2.1.5': chain => 'INPUT', proto => 'all', source => '1.2.1.5', } -> firewall { '012 input-1.2.1.4': chain => 'INPUT', proto => 'all', source => '1.2.1.4', } -> firewall { '011 input-1.2.1.3': chain => 'INPUT', proto => 'all', source => '1.2.1.3', } PUPPETCODE it 'adds managed rules with ignored rules' do apply_manifest(pp5, catch_failures: true) expect(shell('iptables-save').stdout).to match(%r{-A INPUT -s 1\.2\.1\.1(\/32)? -p tcp\s?\n-A INPUT -s 1\.2\.1\.1(\/32)? -p udp}) end end if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} context 'when ipv6 chain purge' do after(:all) do ip6tables_flush_all_tables end before(:each) do ip6tables_flush_all_tables shell('ip6tables -A INPUT -p tcp -s 1::42') shell('ip6tables -A INPUT -p udp -s 1::42') shell('ip6tables -A OUTPUT -s 1::50 -m comment --comment "010 output-1::50"') end pp6 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv6': purge => true, } PUPPETCODE it 'purges only the specified chain' do apply_manifest(pp6, expect_changes: true) shell('ip6tables-save') do |r| expect(r.stdout).to match(%r{010 output-1::50}) expect(r.stdout).not_to match(%r{1::42}) expect(r.stderr).to eq('') end end # rubocop:enable RSpec/ExampleLength pp7 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'OUTPUT:filter:IPv6': purge => true, } firewall { '010 output-1::50': chain => 'OUTPUT', proto => 'all', source => '1::50', provider => 'ip6tables', } PUPPETCODE it 'ignores managed rules' do apply_manifest(pp7, catch_changes: do_catch_changes) end pp8 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv6': purge => true, ignore => [ '-s 1::42', ], } PUPPETCODE it 'ignores specified rules' do apply_manifest(pp8, catch_changes: do_catch_changes) end pp9 = <<-PUPPETCODE class { 'firewall': } firewallchain { 'INPUT:filter:IPv6': purge => true, ignore => [ '-s 1::42', ], } firewall { '014 input-1::46': chain => 'INPUT', proto => 'all', source => '1::46', provider => 'ip6tables', } -> firewall { '013 input-1::45': chain => 'INPUT', proto => 'all', source => '1::45', provider => 'ip6tables', } -> firewall { '012 input-1::44': chain => 'INPUT', proto => 'all', source => '1::44', provider => 'ip6tables', } -> firewall { '011 input-1::43': chain => 'INPUT', proto => 'all', source => '1::43', provider => 'ip6tables', } PUPPETCODE it 'adds managed rules with ignored rules' do apply_manifest(pp9, catch_failures: true) expect(shell('ip6tables-save').stdout).to match(%r{-A INPUT -s 1::42(\/128)? -p tcp\s?\n-A INPUT -s 1::42(\/128)? -p udp}) end end end end puppetlabs-firewall-1.12.0/spec/acceptance/resource_cmd_spec.rb0100644005276200011600000001605313232340436021600 0ustar00require 'spec_helper_acceptance' # Here we want to test the the resource commands ability to work with different # existing ruleset scenarios. This will give the parsing capabilities of the # code a good work out. describe 'puppet resource firewall command' do before(:all) do # In order to properly check stderr for anomalies we need to fix the deprecation warnings from puppet.conf. config = shell('puppet config print config').stdout shell("sed -i -e \'s/^templatedir.*$//\' #{config}") end context 'when make sure it returns no errors when executed on a clean machine' do it do shell('puppet resource firewall') do |r| r.exit_code.should be_zero # don't check stdout, some boxes come with rules, that is normal r.stderr.should be_empty end end end context 'when flush iptables and make sure it returns nothing afterwards' do before(:all) do iptables_flush_all_tables end # No rules, means no output thanks. And no errors as well. it do shell('puppet resource firewall') do |r| r.exit_code.should be_zero r.stdout.should == "\n" end end end context 'when accepts rules without comments' do before(:all) do iptables_flush_all_tables shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80') 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 context 'when accepts rules with invalid comments' do before(:all) do iptables_flush_all_tables shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80 -m comment --comment "http"') 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 context 'when accepts rules with negation' do before :all do iptables_flush_all_tables shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535') shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535') shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE') 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 context 'when accepts rules with match extension tcp flag' do before :all do iptables_flush_all_tables shell('iptables -t mangle -A PREROUTING -d 1.2.3.4 -p tcp -m tcp -m multiport --dports 80,443,8140 -j MARK --set-mark 42') 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 if default['platform'] !~ %r{sles-10} context 'when accepts rules utilizing the statistic module' do before :all do iptables_flush_all_tables # This command doesn't work with all versions/oses, so let it fail shell('iptables -t nat -A POSTROUTING -d 1.2.3.4/32 -o eth0 -m statistic --mode nth --every 2 -j SNAT --to-source 2.3.4.5', acceptable_exit_codes: [0, 1, 2]) shell('iptables -t nat -A POSTROUTING -d 1.2.3.4/32 -o eth0 -m statistic --mode nth --every 1 --packet 0 -j SNAT --to-source 2.3.4.6') shell('iptables -t nat -A POSTROUTING -d 1.2.3.4/32 -o eth0 -m statistic --mode random --probability 0.99 -j SNAT --to-source 2.3.4.7') 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 end context 'when accepts rules with negation' do before :all do iptables_flush_all_tables shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -m policy --dir out --pol ipsec -j ACCEPT') shell('iptables -t filter -A FORWARD -s 192.168.1.0/24 -d 192.168.122.0/24 -i eth0 -m policy --dir in --pol ipsec --reqid 108 --proto esp -j ACCEPT') shell('iptables -t filter -A FORWARD -s 192.168.122.0/24 -d 192.168.1.0/24 -o eth0 -m policy --dir out --pol ipsec --reqid 108 --proto esp -j ACCEPT') shell('iptables -t filter -A FORWARD -s 192.168.201.1/32 -d 192.168.122.0/24 -i eth0 -m policy --dir in --pol ipsec --reqid 107 --proto esp -j ACCEPT') shell('iptables -t filter -A FORWARD -s 192.168.122.0/24 -d 192.168.201.1/32 -o eth0 -m policy --dir out --pol ipsec --reqid 107 --proto esp -j ACCEPT') 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 context 'when accepts rules with -m (tcp|udp) without dport/sport' do before :all do iptables_flush_all_tables shell('iptables -A INPUT -s 10.0.0.0/8 -p udp -m udp -j ACCEPT') 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 context 'when 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 # TODO: Test below fails if this file is run seperately. i.e. bundle exec rspec spec/acceptance/resource_cmd_spec.rb if default['platform'] !~ %r{el-5} && default['platform'] !~ %r{sles-10} context 'when dport/sport with ip6tables' do before :all do if fact('osfamily') == 'Debian' shell('echo "iptables-persistent iptables-persistent/autosave_v4 boolean false" | debconf-set-selections') shell('echo "iptables-persistent iptables-persistent/autosave_v6 boolean false" | debconf-set-selections') shell('apt-get install iptables-persistent -y') end ip6tables_flush_all_tables shell('ip6tables -A INPUT -d fe80::/64 -p tcp -m tcp --dport 546 --sport 547 -j ACCEPT -m comment --comment 000-foobar') end it do shell('puppet resource firewall \'000-foobar\' provider=ip6tables') 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 end end puppetlabs-firewall-1.12.0/spec/acceptance/rules_spec.rb0100644005276200011600000002371613232340436020264 0ustar00require 'spec_helper_acceptance' describe 'rules spec' do describe 'complex ruleset 1' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end after :all do shell('iptables -t filter -P INPUT ACCEPT') shell('iptables -t filter -P FORWARD ACCEPT') shell('iptables -t filter -P OUTPUT ACCEPT') shell('iptables -t filter --flush') end pp1 = <<-PUPPETCODE firewall { '090 forward allow local': chain => 'FORWARD', proto => 'all', source => '10.0.0.0/8', destination => '10.0.0.0/8', action => 'accept', } firewall { '100 forward standard allow tcp': chain => 'FORWARD', source => '10.0.0.0/8', destination => '!10.0.0.0/8', proto => 'tcp', state => 'NEW', port => [80,443,21,20,22,53,123,43,873,25,465], action => 'accept', } firewall { '100 forward standard allow udp': chain => 'FORWARD', source => '10.0.0.0/8', destination => '!10.0.0.0/8', proto => 'udp', port => [53,123], action => 'accept', } firewall { '100 forward standard allow icmp': chain => 'FORWARD', source => '10.0.0.0/8', destination => '!10.0.0.0/8', proto => 'icmp', action => 'accept', } firewall { '090 ignore ipsec': table => 'nat', chain => 'POSTROUTING', outiface => 'eth0', ipsec_policy => 'ipsec', ipsec_dir => 'out', action => 'accept', } firewall { '093 ignore 10.0.0.0/8': table => 'nat', chain => 'POSTROUTING', outiface => 'eth0', destination => '10.0.0.0/8', action => 'accept', } firewall { '093 ignore 172.16.0.0/12': table => 'nat', chain => 'POSTROUTING', outiface => 'eth0', destination => '172.16.0.0/12', action => 'accept', } firewall { '093 ignore 192.168.0.0/16': table => 'nat', chain => 'POSTROUTING', outiface => 'eth0', destination => '192.168.0.0/16', action => 'accept', } firewall { '100 masq outbound': table => 'nat', chain => 'POSTROUTING', outiface => 'eth0', jump => 'MASQUERADE', } firewall { '101 redirect port 1': table => 'nat', chain => 'PREROUTING', iniface => 'eth0', proto => 'tcp', dport => '1', toports => '22', jump => 'REDIRECT', } PUPPETCODE it 'applies cleanly' do # Run it twice and test for idempotency apply_manifest(pp1, catch_failures: true) expect(apply_manifest(pp1, catch_failures: true).exit_code).to be_zero end regex_values = [ %r{INPUT ACCEPT}, %r{FORWARD ACCEPT}, %r{OUTPUT ACCEPT}, %r{-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) -d 10.0.0.0\/(8|255\.0\.0\.0) -m comment --comment \"090 forward allow local\" -j ACCEPT}, %r{-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"100 forward standard allow icmp\" -j ACCEPT}, %r{-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p tcp -m multiport --ports 80,443,21,20,22,53,123,43,873,25,465 -m state --state NEW -m comment --comment \"100 forward standard allow tcp\" -j ACCEPT}, # rubocop:disable Metrics/LineLength %r{-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p udp -m multiport --ports 53,123 -m comment --comment \"100 forward standard allow udp\" -j ACCEPT} ] it 'contains appropriate rules' do shell('iptables-save') do |r| regex_values.each do |line| expect(r.stdout).to match(line) end end end end describe 'complex ruleset 2' do after :all do shell('iptables -t filter -P INPUT ACCEPT') shell('iptables -t filter -P FORWARD ACCEPT') shell('iptables -t filter -P OUTPUT ACCEPT') shell('iptables -t filter --flush') end pp2 = <<-PUPPETCODE class { '::firewall': } Firewall { proto => 'all', } Firewallchain { purge => 'true', ignore => [ '--comment "[^"]*(?i:ignore)[^"]*"', ], } firewall { '001 ssh needed for beaker testing': proto => 'tcp', dport => '22', action => 'accept', before => Firewallchain['INPUT:filter:IPv4'], } firewall { '010 INPUT allow established and related': proto => 'all', state => ['ESTABLISHED', 'RELATED'], action => 'accept', before => Firewallchain['INPUT:filter:IPv4'], } firewall { "011 reject local traffic not on loopback interface": iniface => '! lo', proto => 'all', destination => '127.0.0.1/8', action => 'reject', } firewall { '012 accept loopback': iniface => 'lo', action => 'accept', before => Firewallchain['INPUT:filter:IPv4'], } firewall { '020 ssh': proto => 'tcp', dport => '22', state => 'NEW', action => 'accept', before => Firewallchain['INPUT:filter:IPv4'], } firewall { '025 smtp': outiface => '! eth0:2', chain => 'OUTPUT', proto => 'tcp', dport => '25', state => 'NEW', action => 'accept', } firewall { '013 icmp echo-request': proto => 'icmp', icmp => 'echo-request', action => 'accept', source => '10.0.0.0/8', } firewall { '013 icmp destination-unreachable': proto => 'icmp', icmp => 'destination-unreachable', action => 'accept', } firewall { '013 icmp time-exceeded': proto => 'icmp', icmp => 'time-exceeded', action => 'accept', } firewall { '443 ssl on aliased interface': proto => 'tcp', dport => '443', state => 'NEW', action => 'accept', iniface => 'eth0:3', } firewallchain { 'LOCAL_INPUT_PRE:filter:IPv4': } firewall { '001 LOCAL_INPUT_PRE': jump => 'LOCAL_INPUT_PRE', require => Firewallchain['LOCAL_INPUT_PRE:filter:IPv4'], } firewallchain { 'LOCAL_INPUT:filter:IPv4': } firewall { '900 LOCAL_INPUT': jump => 'LOCAL_INPUT', require => Firewallchain['LOCAL_INPUT:filter:IPv4'], } firewallchain { 'INPUT:filter:IPv4': policy => 'drop', ignore => [ '-j fail2ban-ssh', '--comment "[^"]*(?i:ignore)[^"]*"', ], } firewall { '010 allow established and related': chain => 'FORWARD', proto => 'all', state => ['ESTABLISHED','RELATED'], action => 'accept', before => Firewallchain['FORWARD:filter:IPv4'], } firewallchain { 'FORWARD:filter:IPv4': policy => 'drop', } firewallchain { 'OUTPUT:filter:IPv4': } # purge unknown rules from mangle table firewallchain { ['PREROUTING:mangle:IPv4', 'INPUT:mangle:IPv4', 'FORWARD:mangle:IPv4', 'OUTPUT:mangle:IPv4', 'POSTROUTING:mangle:IPv4']: } # and the nat table firewallchain { ['PREROUTING:nat:IPv4', 'INPUT:nat:IPv4', 'OUTPUT:nat:IPv4', 'POSTROUTING:nat:IPv4']: } PUPPETCODE it 'applies cleanly' do # Run it twice and test for idempotency apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: do_catch_changes) end regex_values = [ %r{INPUT DROP}, %r{FORWARD DROP}, %r{OUTPUT ACCEPT}, %r{LOCAL_INPUT}, %r{LOCAL_INPUT_PRE}, %r{-A INPUT -m comment --comment \"001 LOCAL_INPUT_PRE\" -j LOCAL_INPUT_PRE}, %r{-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"001 ssh needed for beaker testing\" -j ACCEPT}, %r{-A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment \"010 INPUT allow established and related\" -j ACCEPT}, %r{-A INPUT -d 127.0.0.0\/(8|255\.0\.0\.0) (! -i|-i !) lo -m comment --comment \"011 reject local traffic not on loopback interface\" -j REJECT --reject-with icmp-port-unreachable}, %r{-A INPUT -i lo -m comment --comment \"012 accept loopback\" -j ACCEPT}, %r{-A INPUT -p icmp -m icmp --icmp-type 3 -m comment --comment \"013 icmp destination-unreachable\" -j ACCEPT}, %r{-A INPUT -s 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m icmp --icmp-type 8 -m comment --comment \"013 icmp echo-request\" -j ACCEPT}, %r{-A INPUT -p icmp -m icmp --icmp-type 11 -m comment --comment \"013 icmp time-exceeded\" -j ACCEPT}, %r{-A INPUT -p tcp -m multiport --dports 22 -m state --state NEW -m comment --comment \"020 ssh\" -j ACCEPT}, %r{-A INPUT -i eth0:3 -p tcp -m multiport --dports 443 -m state --state NEW -m comment --comment \"443 ssl on aliased interface\" -j ACCEPT}, %r{-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT}, %r{-A FORWARD -m state --state RELATED,ESTABLISHED -m comment --comment \"010 allow established and related\" -j ACCEPT}, %r{-A OUTPUT (! -o|-o !) eth0:2 -p tcp -m multiport --dports 25 -m state --state NEW -m comment --comment \"025 smtp\" -j ACCEPT}, ] it 'contains appropriate rules' do shell('iptables-save') do |r| regex_values.each do |line| expect(r.stdout).to match(line) end end end end end puppetlabs-firewall-1.12.0/spec/acceptance/socket_spec.rb0100644005276200011600000000673013232340436020417 0ustar00require 'spec_helper_acceptance' # RHEL5 does not support -m socket describe 'firewall socket property', unless: default['platform'] =~ %r{el-5} || fact('operatingsystem') == 'SLES' do before :all do iptables_flush_all_tables ip6tables_flush_all_tables end shared_examples 'is idempotent' do |value, line_match| pp1 = <<-PUPPETCODE class { '::firewall': } firewall { '598 - test': ensure => present, proto => 'tcp', chain => 'PREROUTING', table => 'raw', #{value} } PUPPETCODE it "changes the value to #{value}" do apply_manifest(pp1, catch_failures: true) apply_manifest(pp1, catch_changes: true) shell('iptables-save -t raw') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end shared_examples "doesn't change" do |value, line_match| pp2 = <<-PUPPETCODE class { '::firewall': } firewall { '598 - test': ensure => present, proto => 'tcp', chain => 'PREROUTING', table => 'raw', #{value} } PUPPETCODE it "doesn't change the value to #{value}" do apply_manifest(pp2, catch_changes: true) shell('iptables-save -t raw') do |r| expect(r.stdout).to match(%r{#{line_match}}) end end end describe 'adding a rule' do context 'when unset' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', '', %r{-A PREROUTING -p tcp -m comment --comment "598 - test"} end context 'when set to true' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', 'socket => true,', %r{-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"} end context 'when set to false' do before :all do iptables_flush_all_tables end it_behaves_like 'is idempotent', 'socket => false,', %r{-A PREROUTING -p tcp -m comment --comment "598 - test"} end end describe 'editing a rule' do context 'when unset or false and current value is false' do before :each do iptables_flush_all_tables shell('iptables -t raw -A PREROUTING -p tcp -m comment --comment "598 - test"') end it_behaves_like "doesn't change", 'socket => false,', %r{-A PREROUTING -p tcp -m comment --comment "598 - test"} end context 'when unset or false and current value is true' do before :each do iptables_flush_all_tables shell('iptables -t raw -A PREROUTING -p tcp -m comment --comment "598 - test"') end it_behaves_like 'is idempotent', 'socket => true,', %r{-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"} end context 'when set to true and current value is false' do before :each do iptables_flush_all_tables shell('iptables -t raw -A PREROUTING -p tcp -m socket -m comment --comment "598 - test"') end it_behaves_like 'is idempotent', 'socket => false,', %r{-A PREROUTING -p tcp -m comment --comment "598 - test"} end context 'when set to true and current value is true' do before :each do iptables_flush_all_tables shell('iptables -t raw -A PREROUTING -p tcp -m socket -m comment --comment "598 - test"') end it_behaves_like "doesn't change", 'socket => true,', %r{-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"} end end end puppetlabs-firewall-1.12.0/spec/acceptance/standard_usage_spec.rb0100644005276200011600000000312013232340436022101 0ustar00require 'spec_helper_acceptance' # Some tests for the standard recommended usage describe 'standard usage tests' do pp = <<-PUPPETCODE class my_fw::pre { Firewall { require => undef, } # Default firewall rules firewall { '000 accept all icmp': proto => 'icmp', action => 'accept', }-> firewall { '001 accept all to lo interface': proto => 'all', iniface => 'lo', action => 'accept', }-> firewall { "0002 reject local traffic not on loopback interface": iniface => '! lo', destination => '127.0.0.1/8', action => 'reject', }-> firewall { '003 accept related established rules': proto => 'all', ctstate => ['RELATED', 'ESTABLISHED'], action => 'accept', } } class my_fw::post { firewall { '999 drop all': proto => 'all', action => 'drop', before => undef, } } resources { "firewall": purge => true } Firewall { before => Class['my_fw::post'], require => Class['my_fw::pre'], } class { ['my_fw::pre', 'my_fw::post']: } class { 'firewall': } firewall { '500 open up port 22': action => 'accept', proto => 'tcp', dport => 22, } PUPPETCODE it 'applies twice' do # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: do_catch_changes) end end puppetlabs-firewall-1.12.0/spec/default_facts.yml0100644005276200011600000000036013232340436017022 0ustar00# Use default_module_facts.yml for module specific facts. # # Facts specified here will override the values provided by rspec-puppet-facts. --- concat_basedir: "/tmp" ipaddress: "172.16.254.254" is_pe: false macaddress: "AA:AA:AA:AA:AA:AA" puppetlabs-firewall-1.12.0/spec/fixtures0040755005276200011600000000000013232340576015276 5ustar00puppetlabs-firewall-1.12.0/spec/fixtures/ip6tables0040755005276200011600000000000013232340576017167 5ustar00puppetlabs-firewall-1.12.0/spec/fixtures/ip6tables/conversion_hash.rb0100644005276200011600000001021413232340436022751 0ustar00# These hashes allow us to iterate across a series of test data # creating rspec examples for each parameter to ensure the input :line # extrapolates to the desired value for the parameter in question. And # vice-versa # This hash is for testing a line conversion to a hash of parameters # which will be used to create a resource. ARGS_TO_HASH6 = { 'source_destination_ipv6_no_cidr' => { line: '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"', table: 'filter', provider: 'ip6tables', params: { source: '2001:db8:85a3::8a2e:370:7334/128', destination: '2001:db8:85a3::8a2e:370:7334/128', }, }, 'source_destination_ipv6_netmask' => { line: '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"', table: 'filter', provider: 'ip6tables', params: { source: '2001:db8:1234::/48', destination: '2001:db8:4321::/48', }, }, 'udp_source_port_and_destination_port' => { line: '-A ufw6-before-input -s fe80::/10 -d fe80::/10 -p udp -m udp --sport 547 --dport 546 -j ACCEPT', table: 'filter', provider: 'ip6tables', params: { proto: 'udp', sport: ['547'], dport: ['546'], }, }, }.freeze # This hash is for testing converting a hash to an argument line. HASH_TO_ARGS6 = { 'zero_prefixlen_ipv6' => { params: { name: '100 zero prefix length ipv6', table: 'filter', provider: 'ip6tables', source: '::/0', destination: '::/0', }, args: ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'], }, 'source_destination_ipv4_no_cidr' => { params: { name: '000 source destination ipv4 no cidr', table: 'filter', provider: 'ip6tables', source: '1.1.1.1', destination: '2.2.2.2', }, args: ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'], }, 'source_destination_ipv6_no_cidr' => { params: { name: '000 source destination ipv6 no cidr', table: 'filter', provider: 'ip6tables', source: '2001:db8:1234::', destination: '2001:db8:4321::', }, args: ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'], }, 'source_destination_ipv6_netmask' => { params: { name: '000 source destination ipv6 netmask', table: 'filter', provider: 'ip6tables', source: '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000', destination: '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000', }, args: ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'], }, 'frag_ishasmorefrags' => { params: { name: '100 has more fragments', ishasmorefrags: true, provider: 'ip6tables', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'frag', '--fragid', '0', '--fragmore', '-m', 'comment', '--comment', '100 has more fragments'], }, 'frag_islastfrag' => { params: { name: '100 last fragment', islastfrag: true, provider: 'ip6tables', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'frag', '--fragid', '0', '--fraglast', '-m', 'comment', '--comment', '100 last fragment'], }, 'frag_isfirstfrags' => { params: { name: '100 first fragment', isfirstfrag: true, provider: 'ip6tables', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'frag', '--fragid', '0', '--fragfirst', '-m', 'comment', '--comment', '100 first fragment'], }, 'hop_limit' => { params: { name: '100 hop limit', hop_limit: 255, provider: 'ip6tables', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'hl', '--hl-eq', 255, '-m', 'comment', '--comment', '100 hop limit'], }, }.freeze puppetlabs-firewall-1.12.0/spec/fixtures/iptables0040755005276200011600000000000013232340576017101 5ustar00puppetlabs-firewall-1.12.0/spec/fixtures/iptables/conversion_hash.rb0100644005276200011600000012156013232340436022672 0ustar00# These hashes allow us to iterate across a series of test data # creating rspec examples for each parameter to ensure the input :line # extrapolates to the desired value for the parameter in question. And # vice-versa # This hash is for testing a line conversion to a hash of parameters # which will be used to create a resource. ARGS_TO_HASH = { 'mac_source_1' => { line: '-A neutron-openvswi-FORWARD -s 1.2.3.4/32 -m mac --mac-source FA:16:00:00:00:00 -j ACCEPT', table: 'filter', params: { chain: 'neutron-openvswi-FORWARD', source: '1.2.3.4/32', mac_source: 'FA:16:00:00:00:00', }, }, 'dport_and_sport' => { line: '-A nova-compute-FORWARD -s 0.0.0.0/32 -d 255.255.255.255/32 -p udp -m udp --sport 68 --dport 67 -j ACCEPT', table: 'filter', params: { action: 'accept', chain: 'nova-compute-FORWARD', source: '0.0.0.0/32', destination: '255.255.255.255/32', sport: ['68'], dport: ['67'], proto: 'udp', }, }, 'long_rule_1' => { line: '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT -m comment --comment "000 allow foo"', table: 'filter', compare_all: true, params: { action: 'accept', chain: 'INPUT', destination: '1.1.1.1/32', dport: %w[7061 7062], ensure: :present, line: '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT -m comment --comment "000 allow foo"', name: '000 allow foo', proto: 'tcp', provider: 'iptables', source: '1.1.1.1/32', sport: %w[7061 7062], table: 'filter', }, }, 'action_drop_1' => { line: '-A INPUT -j DROP -m comment --comment "000 allow foo"', table: 'filter', params: { jump: nil, action: 'drop', }, }, 'action_reject_1' => { line: '-A INPUT -j REJECT -m comment --comment "000 allow foo"', table: 'filter', params: { jump: nil, action: 'reject', }, }, 'action_nil_1' => { line: '-A INPUT -m comment --comment "000 allow foo"', table: 'filter', params: { jump: nil, action: nil, }, }, 'jump_custom_chain_1' => { line: '-A INPUT -j custom_chain -m comment --comment "000 allow foo"', table: 'filter', params: { jump: 'custom_chain', 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', params: { source: '1.1.1.1/32', destination: '2.2.2.2/32', }, }, 'source_destination_ipv6_no_cidr' => { line: '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"', table: 'filter', params: { source: '2001:db8:85a3::8a2e:370:7334/128', destination: '2001:db8:85a3::8a2e:370:7334/128', }, }, 'source_destination_ipv4_netmask' => { line: '-A INPUT -s 1.1.1.0/255.255.255.0 -d 2.2.0.0/255.255.0.0 -m comment --comment "000 source destination ipv4 netmask"', table: 'filter', params: { source: '1.1.1.0/24', destination: '2.2.0.0/16', }, }, 'source_destination_ipv6_netmask' => { line: '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"', table: 'filter', params: { source: '2001:db8:1234::/48', destination: '2001:db8:4321::/48', }, }, 'source_destination_negate_source' => { line: '-A INPUT ! -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 negated source address"', table: 'filter', params: { source: '! 1.1.1.1/32', destination: '2.2.2.2/32', }, }, 'source_destination_negate_destination' => { line: '-A INPUT -s 1.1.1.1 ! -d 2.2.2.2 -m comment --comment "000 negated destination address"', table: 'filter', params: { source: '1.1.1.1/32', destination: '! 2.2.2.2/32', }, }, 'source_destination_negate_destination_alternative' => { line: '-A INPUT -s 1.1.1.1 -d ! 2.2.2.2 -m comment --comment "000 negated destination address alternative"', table: 'filter', params: { source: '1.1.1.1/32', destination: '! 2.2.2.2/32', }, }, 'dport_range_1' => { line: '-A INPUT -m multiport --dports 1:1024 -m comment --comment "000 allow foo"', table: 'filter', params: { dport: ['1-1024'], }, }, 'dport_range_2' => { line: '-A INPUT -m multiport --dports 15,512:1024 -m comment --comment "000 allow foo"', table: 'filter', params: { dport: ['15', '512-1024'], }, }, 'sport_range_1' => { line: '-A INPUT -m multiport --sports 1:1024 -m comment --comment "000 allow foo"', table: 'filter', params: { sport: ['1-1024'], }, }, 'sport_range_2' => { line: '-A INPUT -m multiport --sports 15,512:1024 -m comment --comment "000 allow foo"', table: 'filter', params: { sport: ['15', '512-1024'], }, }, 'dst_type_1' => { line: '-A INPUT -m addrtype --dst-type LOCAL', table: 'filter', params: { dst_type: 'LOCAL', }, }, 'src_type_1' => { line: '-A INPUT -m addrtype --src-type LOCAL', table: 'filter', params: { src_type: 'LOCAL', }, }, 'dst_range_1' => { line: '-A INPUT -m iprange --dst-range 10.0.0.2-10.0.0.20', table: 'filter', params: { dst_range: '10.0.0.2-10.0.0.20', }, }, 'src_range_1' => { line: '-A INPUT -m iprange --src-range 10.0.0.2-10.0.0.20', table: 'filter', params: { src_range: '10.0.0.2-10.0.0.20', }, }, 'tcp_flags_1' => { line: '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"', table: 'filter', compare_all: true, chain: 'INPUT', proto: 'tcp', params: { chain: 'INPUT', ensure: :present, line: '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"', name: '000 initiation', proto: 'tcp', provider: 'iptables', table: 'filter', tcp_flags: 'SYN,RST,ACK,FIN SYN', }, }, 'state_returns_sorted_values' => { line: '-A INPUT -m state --state INVALID,RELATED,ESTABLISHED', table: 'filter', params: { state: %w[ESTABLISHED INVALID RELATED], action: nil, }, }, 'ctstate_returns_sorted_values' => { line: '-A INPUT -m conntrack --ctstate INVALID,RELATED,ESTABLISHED', table: 'filter', params: { ctstate: %w[ESTABLISHED INVALID RELATED], action: nil, }, }, 'comment_string_character_validation' => { line: '-A INPUT -s 192.168.0.1/32 -m comment --comment "000 allow from 192.168.0.1, please"', table: 'filter', params: { source: '192.168.0.1/32', }, }, 'string_escape_sequences' => { line: '-A INPUT -m comment --comment "000 parse escaped \\"s, \\\'s, and \\\\s"', table: 'filter', params: { name: '000 parse escaped "s, \'s, and \\s', }, }, 'log_level_debug' => { line: '-A INPUT -m state --state NEW -j LOG --log-level 7 -m comment --comment "956 INPUT log-level"', table: 'filter', params: { state: ['NEW'], log_level: '7', jump: 'LOG', }, }, 'log_level_warn' => { line: '-A INPUT -m state --state NEW -j LOG -m comment --comment "956 INPUT log-level"', table: 'filter', params: { state: ['NEW'], log_level: '4', jump: 'LOG', }, }, 'load_limit_module_and_implicit_burst' => { line: '-A INPUT -m multiport --dports 123 -m limit --limit 15/hour -m comment --comment "057 INPUT limit NTP"', table: 'filter', params: { dport: ['123'], limit: '15/hour', burst: '5', }, }, 'limit_with_explicit_burst' => { line: '-A INPUT -m multiport --dports 123 -m limit --limit 30/hour --limit-burst 10 -m comment --comment "057 INPUT limit NTP"', table: 'filter', params: { dport: ['123'], limit: '30/hour', burst: '10', }, }, 'proto_ipencap' => { line: '-A INPUT -p ipencap -m comment --comment "0100 INPUT accept ipencap"', table: 'filter', params: { proto: 'ipencap', }, }, 'load_uid_owner_filter_module' => { line: '-A OUTPUT -m owner --uid-owner root -j ACCEPT -m comment --comment "057 OUTPUT uid root only"', table: 'filter', params: { action: 'accept', uid: 'root', chain: 'OUTPUT', }, }, 'load_uid_owner_postrouting_module' => { line: '-t mangle -A POSTROUTING -m owner --uid-owner root -j ACCEPT -m comment --comment "057 POSTROUTING uid root only"', table: 'mangle', params: { action: 'accept', chain: 'POSTROUTING', uid: 'root', }, }, 'load_gid_owner_filter_module' => { line: '-A OUTPUT -m owner --gid-owner root -j ACCEPT -m comment --comment "057 OUTPUT gid root only"', table: 'filter', params: { action: 'accept', chain: 'OUTPUT', gid: 'root', }, }, 'load_gid_owner_postrouting_module' => { line: '-t mangle -A POSTROUTING -m owner --gid-owner root -j ACCEPT -m comment --comment "057 POSTROUTING gid root only"', table: 'mangle', params: { action: 'accept', chain: 'POSTROUTING', gid: 'root', }, }, 'mark_set-mark' => { line: '-t mangle -A PREROUTING -j MARK --set-xmark 0x3e8/0xffffffff', table: 'mangle', params: { jump: 'MARK', chain: 'PREROUTING', set_mark: '0x3e8/0xffffffff', }, }, 'iniface_1' => { line: '-A INPUT -i eth0 -j DROP -m comment --comment "060 iniface"', table: 'filter', params: { action: 'drop', chain: 'INPUT', iniface: 'eth0', }, }, 'ipset_negated' => { line: '-A PREROUTING -p tcp -m multiport --dports 1094 -m comment --comment "060 ipset" -m state --state NEW -m set ! --match-set setname1 src -j DROP', table: 'filter', params: { chain: 'PREROUTING', proto: 'tcp', dport: ['1094'], state: ['NEW'], ipset: ['! setname1 src'], action: 'drop', }, }, 'iniface_1_negated' => { line: '-A INPUT ! -i eth0 -j DROP -m comment --comment "060 iniface"', table: 'filter', params: { action: 'drop', chain: 'INPUT', iniface: '! eth0', }, }, 'iniface_2_negated' => { line: '-A CHAIN-WITH-DASH ! -i eth0 -p tcp -m comment --comment "005 iniface 2" -j DROP', table: 'filter', params: { action: 'drop', chain: 'CHAIN-WITH-DASH', iniface: '! eth0', }, }, 'iniface_1_aliased' => { line: '-A INPUT -i eth0:1 -j DROP -m comment --comment "060 iniface"', table: 'filter', params: { action: 'drop', chain: 'INPUT', iniface: 'eth0:1', }, }, 'iniface_with_vlans_1' => { line: '-A INPUT -i eth0.234 -j DROP -m comment --comment "060 iniface"', table: 'filter', params: { action: 'drop', chain: 'INPUT', iniface: 'eth0.234', }, }, 'iniface_with_plus_1' => { line: '-A INPUT -i eth+ -j DROP -m comment --comment "060 iniface"', table: 'filter', params: { action: 'drop', chain: 'INPUT', iniface: 'eth+', }, }, 'outiface_1' => { line: '-A OUTPUT -o eth0 -j DROP -m comment --comment "060 outiface"', table: 'filter', params: { action: 'drop', chain: 'OUTPUT', outiface: 'eth0', }, }, 'outiface_1_negated' => { line: '-A OUTPUT ! -o eth0 -j DROP -m comment --comment "060 outiface"', table: 'filter', params: { action: 'drop', chain: 'OUTPUT', outiface: '! eth0', }, }, 'outiface_1_aliased' => { line: '-A OUTPUT -o eth0:2 -j DROP -m comment --comment "060 outiface"', table: 'filter', params: { action: 'drop', chain: 'OUTPUT', outiface: 'eth0:2', }, }, 'outiface_with_vlans_1' => { line: '-A OUTPUT -o eth0.234 -j DROP -m comment --comment "060 outiface"', table: 'filter', params: { action: 'drop', chain: 'OUTPUT', outiface: 'eth0.234', }, }, 'outiface_with_plus_1' => { line: '-A OUTPUT -o eth+ -j DROP -m comment --comment "060 outiface"', table: 'filter', params: { action: 'drop', chain: 'OUTPUT', outiface: 'eth+', }, }, 'pkttype multicast' => { line: '-A INPUT -m pkttype --pkt-type multicast -j ACCEPT', table: 'filter', params: { action: 'accept', pkttype: 'multicast', }, }, 'socket_option' => { line: '-A PREROUTING -m socket -j ACCEPT', table: 'mangle', params: { action: 'accept', chain: 'PREROUTING', socket: true, }, }, 'isfragment_option' => { line: '-A INPUT -f -j ACCEPT -m comment --comment "010 a-f comment with dashf"', table: 'filter', params: { name: '010 a-f comment with dashf', action: 'accept', isfragment: true, }, }, 'single_tcp_sport' => { line: '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --sport 20443 -j ACCEPT', table: 'mangle', params: { action: 'accept', chain: 'OUTPUT', source: '10.94.100.46/32', proto: 'tcp', sport: ['20443'], }, }, 'single_udp_sport' => { line: '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --sport 20443 -j ACCEPT', table: 'mangle', params: { action: 'accept', chain: 'OUTPUT', source: '10.94.100.46/32', proto: 'udp', sport: ['20443'], }, }, 'single_tcp_dport' => { line: '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --dport 20443 -j ACCEPT', table: 'mangle', params: { action: 'accept', chain: 'OUTPUT', source: '10.94.100.46/32', proto: 'tcp', dport: ['20443'], }, }, 'single_udp_dport' => { line: '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --dport 20443 -j ACCEPT', table: 'mangle', params: { action: 'accept', chain: 'OUTPUT', source: '10.94.100.46/32', proto: 'udp', dport: ['20443'], }, }, 'connlimit_above' => { line: '-A INPUT -p tcp -m multiport --dports 22 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with icmp-port-unreachable -m comment --comment "061 REJECT connlimit_above 10"', # rubocop:disable Metrics/LineLength table: 'filter', params: { proto: 'tcp', dport: ['22'], connlimit_above: '10', action: 'reject', }, }, 'connlimit_above_with_connlimit_mask' => { line: '-A INPUT -p tcp -m multiport --dports 22 -m connlimit --connlimit-above 10 --connlimit-mask 24 -j REJECT --reject-with icmp-port-unreachable -m comment --comment "061 REJECT connlimit_above 10 with mask 24"', # rubocop:disable Metrics/LineLength, table: 'filter', params: { proto: 'tcp', dport: ['22'], connlimit_above: '10', connlimit_mask: '24', action: 'reject', }, }, 'connmark' => { line: '-A INPUT -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable -m comment --comment "062 REJECT connmark"', table: 'filter', params: { proto: 'all', connmark: '0x1', action: 'reject', }, }, 'disallow_esp_protocol' => { line: '-t filter ! -p esp -j ACCEPT -m comment --comment "063 disallow esp protocol"', table: 'filter', params: { name: '063 disallow esp protocol', action: 'accept', proto: '! esp', }, }, 'drop_new_packets_without_syn' => { line: '-t filter ! -s 10.0.0.0/8 ! -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP -m comment --comment "064 drop NEW non-tcp external packets with FIN/RST/ACK set and SYN unset"', # rubocop:disable Metrics/LineLength table: 'filter', params: { name: '064 drop NEW non-tcp external packets with FIN/RST/ACK set and SYN unset', state: ['NEW'], action: 'drop', proto: '! tcp', source: '! 10.0.0.0/8', tcp_flags: '! FIN,SYN,RST,ACK SYN', }, }, 'negate_dport_and_sport' => { line: '-A nova-compute-FORWARD -s 0.0.0.0/32 -d 255.255.255.255/32 -p udp -m udp ! --sport 68,69 ! --dport 67,66 -j ACCEPT', table: 'filter', params: { action: 'accept', chain: 'nova-compute-FORWARD', source: '0.0.0.0/32', destination: '255.255.255.255/32', sport: ['! 68', '! 69'], dport: ['! 67', '! 66'], proto: 'udp', }, }, 'match_mark' => { line: '-A INPUT -p tcp -m mark --mark 0x1 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with icmp-port-unreachable -m comment --comment "066 REJECT connlimit_above 10 with mask 32 and mark matches"', # rubocop:disable Metrics/LineLength table: 'filter', params: { proto: 'tcp', connlimit_above: '10', connlimit_mask: '32', match_mark: '0x1', action: 'reject', }, }, 'clamp_mss_to_pmtu' => { line: '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -m comment --comment "067 change max segment size"', table: 'filter', params: { name: '067 change max segment size', table: 'filter', proto: 'tcp', tcp_flags: 'SYN,RST SYN', jump: 'TCPMSS', clamp_mss_to_pmtu: true, }, }, 'mangled_chain_name_with_-f' => { line: '-A foo-filter -p tcp -j ACCEPT -m comment --comment "068 chain name containing -f"', params: { name: '068 chain name containing -f', action: 'accept', 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 -j NFQUEUE --queue-num 50 -m comment --comment "000 nfqueue specify queue_num"', 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 -j NFQUEUE --queue-num 50 --queue-bypass -m comment --comment "002 nfqueue specify queue_num and 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 -j NFQUEUE -m comment --comment "003 nfqueue dont specify queue_num or queue_bypass"', 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', }, }, 'parser_sanity_check' => { line: '-A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "004 parser sanity check" -j ACCEPT', table: 'filter', produce_warning: true, params: {}, }, }.freeze # This hash is for testing converting a hash to an argument line. HASH_TO_ARGS = { 'long_rule_1' => { params: { action: 'accept', chain: 'INPUT', destination: '1.1.1.1', dport: %w[7061 7062], ensure: :present, name: '000 allow foo', proto: 'tcp', source: '1.1.1.1', sport: %w[7061 7062], table: 'filter', }, args: ['-t', :filter, '-s', '1.1.1.1/32', '-d', '1.1.1.1/32', '-p', :tcp, '-m', 'multiport', '--sports', '7061,7062', '-m', 'multiport', '--dports', '7061,7062', '-j', 'ACCEPT', '-m', 'comment', '--comment', '000 allow foo'], # rubocop:disable Metrics/LineLength }, 'long_rule_2' => { params: { chain: 'INPUT', destination: '2.10.13.3/24', dport: ['7061'], ensure: :present, jump: 'my_custom_chain', name: '700 allow bar', proto: 'udp', source: '1.1.1.1', sport: %w[7061 7062], table: 'filter', }, args: ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.10.13.0/24', '-p', :udp, '-m', 'multiport', '--sports', '7061,7062', '-m', 'multiport', '--dports', '7061', '-j', 'my_custom_chain', '-m', 'comment', '--comment', '700 allow bar'], # rubocop:disable Metrics/LineLength }, 'no_action' => { params: { name: '100 no action', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 no action'], }, 'zero_prefixlen_ipv4' => { params: { name: '100 zero prefix length ipv4', table: 'filter', source: '0.0.0.0/0', destination: '0.0.0.0/0', }, args: ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv4'], }, 'zero_prefixlen_ipv6' => { params: { name: '100 zero prefix length ipv6', table: 'filter', source: '::/0', destination: '::/0', }, args: ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'], }, 'source_destination_ipv4_no_cidr' => { params: { name: '000 source destination ipv4 no cidr', table: 'filter', source: '1.1.1.1', destination: '2.2.2.2', }, args: ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'], }, 'source_destination_ipv6_no_cidr' => { params: { name: '000 source destination ipv6 no cidr', table: 'filter', source: '2001:db8:1234::', destination: '2001:db8:4321::', }, args: ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'], }, 'source_destination_ipv4_netmask' => { params: { name: '000 source destination ipv4 netmask', table: 'filter', source: '1.1.1.0/255.255.255.0', destination: '2.2.0.0/255.255.0.0', }, args: ['-t', :filter, '-s', '1.1.1.0/24', '-d', '2.2.0.0/16', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 netmask'], }, 'source_destination_ipv6_netmask' => { params: { name: '000 source destination ipv6 netmask', table: 'filter', source: '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000', destination: '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000', }, args: ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'], }, 'sport_range_1' => { params: { name: '100 sport range', sport: ['1-1024'], table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--sports', '1:1024', '-m', 'comment', '--comment', '100 sport range'], }, 'sport_range_2' => { params: { name: '100 sport range', sport: ['15', '512-1024'], table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--sports', '15,512:1024', '-m', 'comment', '--comment', '100 sport range'], }, 'dport_range_1' => { params: { name: '100 sport range', dport: ['1-1024'], table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '1:1024', '-m', 'comment', '--comment', '100 sport range'], }, 'dport_range_2' => { params: { name: '100 sport range', dport: ['15', '512-1024'], table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '15,512:1024', '-m', 'comment', '--comment', '100 sport range'], }, 'dst_type_1' => { params: { name: '000 dst_type', table: 'filter', dst_type: 'LOCAL', }, args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', :LOCAL, '-m', 'comment', '--comment', '000 dst_type'], }, 'src_type_1' => { params: { name: '000 src_type', table: 'filter', src_type: 'LOCAL', }, args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', :LOCAL, '-m', 'comment', '--comment', '000 src_type'], }, 'dst_range_1' => { params: { name: '000 dst_range', table: 'filter', dst_range: '10.0.0.1-10.0.0.10', }, args: ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 dst_range'], }, 'src_range_1' => { params: { name: '000 src_range', table: 'filter', dst_range: '10.0.0.1-10.0.0.10', }, args: ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 src_range'], }, 'tcp_flags_1' => { params: { name: '000 initiation', tcp_flags: 'SYN,RST,ACK,FIN SYN', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'tcp', '--tcp-flags', 'SYN,RST,ACK,FIN', 'SYN', '-m', 'comment', '--comment', '000 initiation'], }, 'states_set_from_array' => { params: { name: '100 states_set_from_array', table: 'filter', state: %w[ESTABLISHED INVALID], }, args: ['-t', :filter, '-p', :tcp, '-m', 'state', '--state', 'ESTABLISHED,INVALID', '-m', 'comment', '--comment', '100 states_set_from_array'], }, 'ctstates_set_from_array' => { params: { name: '100 ctstates_set_from_array', table: 'filter', ctstate: %w[ESTABLISHED INVALID], }, args: ['-t', :filter, '-p', :tcp, '-m', 'conntrack', '--ctstate', 'ESTABLISHED,INVALID', '-m', 'comment', '--comment', '100 ctstates_set_from_array'], }, 'comment_string_character_validation' => { params: { name: '000 allow from 192.168.0.1, please', table: 'filter', source: '192.168.0.1', }, args: ['-t', :filter, '-s', '192.168.0.1/32', '-p', :tcp, '-m', 'comment', '--comment', '000 allow from 192.168.0.1, please'], }, 'comment_string_character_validation_2' => { params: { name: '000 allow symbols ( $+<=>^`|~ ) in ruby >= 1.9', table: 'filter', }, args: ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '000 allow symbols ( $+<=>^`|~ ) in ruby >= 1.9'], }, 'log_level_debug' => { params: { name: '956 INPUT log-level', table: 'filter', state: 'NEW', jump: 'LOG', log_level: 'debug', }, args: ['-t', :filter, '-p', :tcp, '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '7', '-m', 'comment', '--comment', '956 INPUT log-level'], }, 'log_level_warn' => { params: { name: '956 INPUT log-level', table: 'filter', state: 'NEW', jump: 'LOG', log_level: 'warn', }, args: ['-t', :filter, '-p', :tcp, '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '4', '-m', 'comment', '--comment', '956 INPUT log-level'], }, 'load_limit_module_and_implicit_burst' => { params: { name: '057 INPUT limit NTP', table: 'filter', dport: '123', limit: '15/hour', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'limit', '--limit', '15/hour', '-m', 'comment', '--comment', '057 INPUT limit NTP'], }, 'limit_with_explicit_burst' => { params: { name: '057 INPUT limit NTP', table: 'filter', dport: '123', limit: '30/hour', burst: '10', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'limit', '--limit', '30/hour', '--limit-burst', '10', '-m', 'comment', '--comment', '057 INPUT limit NTP'], }, 'proto_ipencap' => { params: { name: '0100 INPUT accept ipencap', table: 'filter', proto: 'ipencap', }, args: ['-t', :filter, '-p', :ipencap, '-m', 'comment', '--comment', '0100 INPUT accept ipencap'], }, 'load_uid_owner_filter_module' => { params: { name: '057 OUTPUT uid root only', table: 'filter', uid: 'root', action: 'accept', chain: 'OUTPUT', proto: 'all', }, args: ['-t', :filter, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-j', 'ACCEPT', '-m', 'comment', '--comment', '057 OUTPUT uid root only'], }, 'load_uid_owner_postrouting_module' => { params: { name: '057 POSTROUTING uid root only', table: 'mangle', uid: 'root', action: 'accept', chain: 'POSTROUTING', proto: 'all', }, args: ['-t', :mangle, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-j', 'ACCEPT', '-m', 'comment', '--comment', '057 POSTROUTING uid root only'], }, 'load_gid_owner_filter_module' => { params: { name: '057 OUTPUT gid root only', table: 'filter', chain: 'OUTPUT', gid: 'root', action: 'accept', proto: 'all', }, args: ['-t', :filter, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-j', 'ACCEPT', '-m', 'comment', '--comment', '057 OUTPUT gid root only'], }, 'load_gid_owner_postrouting_module' => { params: { name: '057 POSTROUTING gid root only', table: 'mangle', gid: 'root', action: 'accept', chain: 'POSTROUTING', proto: 'all', }, args: ['-t', :mangle, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-j', 'ACCEPT', '-m', 'comment', '--comment', '057 POSTROUTING gid root only'], }, 'mark_set-mark_int' => { params: { name: '058 set-mark 1000', table: 'mangle', jump: 'MARK', chain: 'PREROUTING', set_mark: '1000', }, args: ['-t', :mangle, '-p', :tcp, '-j', 'MARK', '--set-xmark', '0x3e8/0xffffffff', '-m', 'comment', '--comment', '058 set-mark 1000'], }, 'mark_set-mark_hex' => { params: { name: '058 set-mark 0x32', table: 'mangle', jump: 'MARK', chain: 'PREROUTING', set_mark: '0x32', }, args: ['-t', :mangle, '-p', :tcp, '-j', 'MARK', '--set-xmark', '0x32/0xffffffff', '-m', 'comment', '--comment', '058 set-mark 0x32'], }, 'mark_set-mark_hex_with_hex_mask' => { params: { name: '058 set-mark 0x32/0xffffffff', table: 'mangle', jump: 'MARK', chain: 'PREROUTING', set_mark: '0x32/0xffffffff', }, args: ['-t', :mangle, '-p', :tcp, '-j', 'MARK', '--set-xmark', '0x32/0xffffffff', '-m', 'comment', '--comment', '058 set-mark 0x32/0xffffffff'], }, 'mark_set-mark_hex_with_mask' => { params: { name: '058 set-mark 0x32/4', table: 'mangle', jump: 'MARK', chain: 'PREROUTING', set_mark: '0x32/4', }, args: ['-t', :mangle, '-p', :tcp, '-j', 'MARK', '--set-xmark', '0x32/0x4', '-m', 'comment', '--comment', '058 set-mark 0x32/4'], }, 'iniface_1' => { params: { name: '060 iniface', table: 'filter', action: 'drop', chain: 'INPUT', iniface: 'eth0', }, args: ['-t', :filter, '-i', 'eth0', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 iniface'], }, 'iniface_with_vlans_1' => { params: { name: '060 iniface', table: 'filter', action: 'drop', chain: 'INPUT', iniface: 'eth0.234', }, args: ['-t', :filter, '-i', 'eth0.234', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 iniface'], }, 'iniface_with_plus_1' => { params: { name: '060 iniface', table: 'filter', action: 'drop', chain: 'INPUT', iniface: 'eth+', }, args: ['-t', :filter, '-i', 'eth+', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 iniface'], }, 'outiface_1' => { params: { name: '060 outiface', table: 'filter', action: 'drop', chain: 'OUTPUT', outiface: 'eth0', }, args: ['-t', :filter, '-o', 'eth0', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 outiface'], }, 'outiface_with_vlans_1' => { params: { name: '060 outiface', table: 'filter', action: 'drop', chain: 'OUTPUT', outiface: 'eth0.234', }, args: ['-t', :filter, '-o', 'eth0.234', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 outiface'], }, 'outiface_with_plus_1' => { params: { name: '060 outiface', table: 'filter', action: 'drop', chain: 'OUTPUT', outiface: 'eth+', }, args: ['-t', :filter, '-o', 'eth+', '-p', :tcp, '-j', 'DROP', '-m', 'comment', '--comment', '060 outiface'], }, 'pkttype multicast' => { params: { name: '062 pkttype multicast', table: 'filter', action: 'accept', chain: 'INPUT', iniface: 'eth0', pkttype: 'multicast', }, args: ['-t', :filter, '-i', 'eth0', '-p', :tcp, '-m', 'pkttype', '--pkt-type', :multicast, '-j', 'ACCEPT', '-m', 'comment', '--comment', '062 pkttype multicast'], }, 'socket_option' => { params: { name: '050 socket option', table: 'mangle', action: 'accept', chain: 'PREROUTING', socket: true, }, args: ['-t', :mangle, '-p', :tcp, '-m', 'socket', '-j', 'ACCEPT', '-m', 'comment', '--comment', '050 socket option'], }, 'isfragment_option' => { params: { name: '050 isfragment option', table: 'filter', proto: :all, action: 'accept', isfragment: true, }, args: ['-t', :filter, '-p', :all, '-f', '-j', 'ACCEPT', '-m', 'comment', '--comment', '050 isfragment option'], }, 'isfragment_option not changing -f in comment' => { params: { name: '050 testcomment-with-fdashf', table: 'filter', proto: :all, action: 'accept', }, args: ['-t', :filter, '-p', :all, '-j', 'ACCEPT', '-m', 'comment', '--comment', '050 testcomment-with-fdashf'], }, 'connlimit_above' => { params: { name: '061 REJECT connlimit_above 10', table: 'filter', proto: 'tcp', dport: ['22'], connlimit_above: '10', action: 'reject', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '22', '-j', 'REJECT', '-m', 'connlimit', '--connlimit-above', '10', '-m', 'comment', '--comment', '061 REJECT connlimit_above 10'], }, 'connlimit_above_with_connlimit_mask' => { params: { name: '061 REJECT connlimit_above 10 with mask 24', table: 'filter', proto: 'tcp', dport: ['22'], connlimit_above: '10', connlimit_mask: '24', action: 'reject', }, args: ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '22', '-j', 'REJECT', '-m', 'connlimit', '--connlimit-above', '10', '--connlimit-mask', '24', '-m', 'comment', '--comment', '061 REJECT connlimit_above 10 with mask 24'], # rubocop:disable Metrics/LineLength }, 'connmark' => { params: { name: '062 REJECT connmark', table: 'filter', proto: 'all', connmark: '0x1', action: 'reject', }, args: ['-t', :filter, '-p', :all, '-j', 'REJECT', '-m', 'connmark', '--mark', '0x1', '-m', 'comment', '--comment', '062 REJECT connmark'], }, 'disallow_esp_protocol' => { params: { name: '063 disallow esp protocol', table: 'filter', action: 'accept', proto: '! esp', }, args: ['-t', :filter, '!', '-p', :esp, '-j', 'ACCEPT', '-m', 'comment', '--comment', '063 disallow esp protocol'], }, 'drop_new_packets_without_syn' => { params: { name: '064 drop NEW non-tcp external packets with FIN/RST/ACK set and SYN unset', table: 'filter', chain: 'INPUT', state: ['NEW'], action: 'drop', proto: '! tcp', source: '! 10.0.0.0/8', tcp_flags: '! FIN,SYN,RST,ACK SYN', }, args: ['-t', :filter, '!', '-s', '10.0.0.0/8', '!', '-p', :tcp, '-m', 'tcp', '!', '--tcp-flags', 'FIN,SYN,RST,ACK', 'SYN', '-m', 'state', '--state', 'NEW', '-j', 'DROP', '-m', 'comment', '--comment', '064 drop NEW non-tcp external packets with FIN/RST/ACK set and SYN unset'], # rubocop:disable Metrics/LineLength }, 'negate_dport_and_sport' => { params: { name: '065 negate dport and sport', table: 'filter', action: 'accept', chain: 'nova-compute-FORWARD', source: '0.0.0.0/32', destination: '255.255.255.255/32', sport: ['! 68', '! 69'], dport: ['! 67', '! 66'], proto: 'udp', }, args: ['-t', :filter, '-s', '0.0.0.0/32', '-d', '255.255.255.255/32', '-p', :udp, '-m', 'multiport', '!', '--sports', '68,69', '-m', 'multiport', '!', '--dports', '67,66', '-j', 'ACCEPT', '-m', 'comment', '--comment', '065 negate dport and sport'], # rubocop:disable Metrics/LineLength }, 'match_mark' => { params: { name: '066 REJECT connlimit_above 10 with mask 32 and mark matches', table: 'filter', proto: 'tcp', connlimit_above: '10', connlimit_mask: '32', match_mark: '0x1', action: 'reject', }, args: ['-t', :filter, '-p', :tcp, '-j', 'REJECT', '-m', 'mark', '--mark', '0x1', '-m', 'connlimit', '--connlimit-above', '10', '--connlimit-mask', '32', '-m', 'comment', '--comment', '066 REJECT connlimit_above 10 with mask 32 and mark matches'], # rubocop:disable Metrics/LineLength }, 'clamp_mss_to_pmtu' => { params: { name: '067 change max segment size', table: 'filter', proto: 'tcp', tcp_flags: 'SYN,RST SYN', jump: 'TCPMSS', clamp_mss_to_pmtu: true, }, args: ['-t', :filter, '-p', :tcp, '-m', 'tcp', '--tcp-flags', 'SYN,RST', 'SYN', '-j', 'TCPMSS', '--clamp-mss-to-pmtu', '-m', 'comment', '--comment', '067 change max segment size'], }, 'set_dscp_class' => { params: { name: '068 set dscp class to EF', table: 'mangle', proto: 'tcp', port: '997', jump: 'DSCP', set_dscp_class: 'ef', }, args: ['-t', :mangle, '-p', :tcp, '-m', 'multiport', '--ports', '997', '-j', 'DSCP', '--set-dscp-class', 'ef', '-m', 'comment', '--comment', '068 set dscp class to EF'], }, 'length_1' => { params: { name: '000 length', table: 'filter', length: '42000', }, args: ['-t', :filter, '-p', :tcp, '-m', 'length', '--length', '42000', '-m', 'comment', '--comment', '000 length'], }, 'length_2' => { params: { name: '000 length', table: 'filter', length: '1492-65535', }, args: ['-t', :filter, '-p', :tcp, '-m', 'length', '--length', '1492:65535', '-m', 'comment', '--comment', '000 length'], }, 'string_matching_1' => { params: { name: '000 string_matching', table: 'filter', string: 'GET /index.html', }, args: ['-t', :filter, '-p', :tcp, '-m', 'string', '--string', "'GET /index.html'", '-m', 'comment', '--comment', '000 string_matching'], }, 'string_matching_2' => { params: { name: '000 string_matching', table: 'filter', string: 'GET /index.html', string_algo: 'bm', }, args: ['-t', :filter, '-p', :tcp, '-m', 'string', '--string', "'GET /index.html'", '--algo', :bm, '-m', 'comment', '--comment', '000 string_matching'], }, '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', 'string', '--string', "'GET /index.html'", '--from', '1', '--to', '65535', '-m', 'comment', '--comment', '000 string_matching'], }, '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, '-j', 'NFQUEUE', '--queue-num', '50', '-m', 'comment', '--comment', '000 nfqueue specify queue_num'], }, '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, '-j', 'NFQUEUE', '--queue-num', '50', '--queue-bypass', '-m', 'comment', '--comment', '002 nfqueue specify queue_num and queue_bypass'], # rubocop:disable Metrics/LineLength }, '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, '-j', 'NFQUEUE', '-m', 'comment', '--comment', '003 nfqueue dont specify queue_num or queue_bypass'], }, }.freeze puppetlabs-firewall-1.12.0/spec/spec_helper.rb0100644005276200011600000000144313232340436016314 0ustar00require 'puppetlabs_spec_helper/module_spec_helper' require 'rspec-puppet-facts' include RspecPuppetFacts default_facts = { puppetversion: Puppet.version, facterversion: Facter.version, } default_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')) default_module_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')) if File.exist?(default_facts_path) && File.readable?(default_facts_path) default_facts.merge!(YAML.safe_load(File.read(default_facts_path))) end if File.exist?(default_module_facts_path) && File.readable?(default_module_facts_path) default_facts.merge!(YAML.safe_load(File.read(default_module_facts_path))) end RSpec.configure do |c| c.default_facts = default_facts end require 'spec_helper_local' puppetlabs-firewall-1.12.0/spec/spec_helper_acceptance.rb0100644005276200011600000000174013207747121020466 0ustar00require 'beaker-rspec' require 'beaker/puppet_install_helper' require 'beaker/module_install_helper' def iptables_flush_all_tables %w[filter nat mangle raw].each do |t| expect(shell("iptables -t #{t} -F").stderr).to eq('') end end def ip6tables_flush_all_tables %w[filter mangle].each do |t| expect(shell("ip6tables -t #{t} -F").stderr).to eq('') end end def do_catch_changes if default['platform'] =~ %r{el-5} false else true end end run_puppet_install_helper install_module_on(hosts) install_module_dependencies_on(hosts) RSpec.configure do |c| # Configure all nodes in nodeset c.before :suite do # Install module and dependencies hosts.each do |host| on host, puppet('module', 'install', 'puppetlabs-stdlib'), acceptable_exit_codes: [0] # the ubuntu-14.04 docker image doesn't carry the iptables command apply_manifest_on host, 'package { "iptables": ensure => installed }' if fact('osfamily') == 'Debian' end end end puppetlabs-firewall-1.12.0/spec/spec_helper_local.rb0100644005276200011600000000035613207747121017474 0ustar00RSpec.configure do |config| config.mock_with :rspec end def with_debian_facts let :facts do { kernel: 'Linux', operatingsystem: 'Debian', operatingsystemrelease: '8.0', osfamily: 'Debian', } end end puppetlabs-firewall-1.12.0/spec/unit0040755005276200011600000000000013232340576014404 5ustar00puppetlabs-firewall-1.12.0/spec/unit/classes0040755005276200011600000000000013232340576016041 5ustar00puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_linux_archlinux_spec.rb0100644005276200011600000000176213232340436024556 0ustar00require 'spec_helper' describe 'firewall::linux::archlinux', type: :class do let(:facts) do { osfamily: 'Archlinux', operatingsystem: 'Archlinux', } end it { is_expected.to contain_service('iptables').with( ensure: 'running', enable: 'true', ) } it { is_expected.to contain_service('ip6tables').with( ensure: 'running', enable: 'true', ) } context 'with ensure => stopped' do let(:params) { { ensure: 'stopped' } } it { is_expected.to contain_service('iptables').with( ensure: 'stopped', ) } it { is_expected.to contain_service('ip6tables').with( ensure: 'stopped', ) } end context 'with enable => false' do let(:params) { { enable: 'false' } } it { is_expected.to contain_service('iptables').with( enable: 'false', ) } it { is_expected.to contain_service('ip6tables').with( enable: 'false', ) } end end puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_linux_debian_spec.rb0100644005276200011600000000510513232340436023776 0ustar00require 'spec_helper' describe 'firewall::linux::debian', type: :class do context 'with Debian 7' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '7.0', } end it { is_expected.to contain_package('iptables-persistent').with( ensure: 'present', ) } it { is_expected.to contain_service('iptables-persistent').with( ensure: nil, enable: 'true', require: 'Package[iptables-persistent]', ) } end context 'with deb7 enable => false' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '7.0', } end let(:params) { { enable: 'false' } } it { is_expected.to contain_service('iptables-persistent').with( enable: 'false', ) } end context 'with Debian 8' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: 'jessie/sid', } end it { is_expected.to contain_package('iptables-persistent').with( ensure: 'present', ) } it { is_expected.to contain_service('netfilter-persistent').with( ensure: nil, enable: 'true', require: 'Package[iptables-persistent]', ) } end context 'with deb8 enable => false' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: 'jessie/sid', } end let(:params) { { enable: 'false' } } it { is_expected.to contain_service('netfilter-persistent').with( enable: 'false', ) } end context 'with Debian 8, alt operatingsystem' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '8.0', } end it { is_expected.to contain_package('iptables-persistent').with( ensure: 'present', ) } it { is_expected.to contain_service('netfilter-persistent').with( ensure: nil, enable: 'true', require: 'Package[iptables-persistent]', ) } end context 'with deb8, alt operatingsystem, enable => false' do let(:facts) do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '8.0', } end let(:params) { { enable: 'false' } } it { is_expected.to contain_service('netfilter-persistent').with( enable: 'false', ) } end end puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_linux_gentoo_spec.rb0100644005276200011600000000212513232340436024046 0ustar00require 'spec_helper' describe 'firewall::linux::gentoo', type: :class do let(:facts) do { osfamily: 'Gentoo', operatingsystem: 'Gentoo', } end it { is_expected.to contain_service('iptables').with( ensure: 'running', enable: 'true', ) } it { is_expected.to contain_service('ip6tables').with( ensure: 'running', enable: 'true', ) } it { is_expected.to contain_package('net-firewall/iptables').with( ensure: 'present', ) } context 'with ensure => stopped' do let(:params) { { ensure: 'stopped' } } it { is_expected.to contain_service('iptables').with( ensure: 'stopped', ) } it { is_expected.to contain_service('ip6tables').with( ensure: 'stopped', ) } end context 'with enable => false' do let(:params) { { enable: 'false' } } it { is_expected.to contain_service('iptables').with( enable: 'false', ) } it { is_expected.to contain_service('ip6tables').with( enable: 'false', ) } end end puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_linux_redhat_spec.rb0100644005276200011600000000656413232340436024035 0ustar00require 'spec_helper' RSpec.shared_examples 'ensures iptables service' do context 'with default' do it { is_expected.to contain_service('iptables').with( ensure: 'running', enable: 'true', ) } end context 'with ensure => stopped' do let(:params) { { ensure: 'stopped' } } it { is_expected.to contain_service('iptables').with( ensure: 'stopped', ) } end context 'with enable => false' do let(:params) { { enable: 'false' } } it { is_expected.to contain_service('iptables').with( enable: 'false', ) } end end describe 'firewall::linux::redhat', type: :class do %w[RedHat CentOS Fedora].each do |os| oldreleases = ((os == 'Fedora') ? ['14'] : ['6.5']) newreleases = ((os == 'Fedora') ? %w[15 Rawhide] : ['7.0.1406']) oldreleases.each do |osrel| context "os #{os} and osrel #{osrel}" do let(:facts) do { operatingsystem: os, operatingsystemrelease: osrel, osfamily: 'RedHat', selinux: false, puppetversion: Puppet.version, } end it { is_expected.not_to contain_service('firewalld') } it { is_expected.not_to contain_package('iptables-services') } it_behaves_like 'ensures iptables service' end end newreleases.each do |osrel| context "os #{os} and osrel #{osrel}" do let(:facts) do { operatingsystem: os, operatingsystemrelease: osrel, osfamily: 'RedHat', selinux: false, puppetversion: Puppet.version, } end it { is_expected.to contain_service('iptables').with( ensure: 'running', enable: 'true', ) } it { is_expected.to contain_service('ip6tables').with( ensure: 'running', enable: 'true', ) } context 'with ensure => stopped' do let(:params) { { ensure: 'stopped' } } it { is_expected.to contain_service('iptables').with( ensure: 'stopped', ) } end context 'with ensure_v6 => stopped' do let(:params) { { ensure_v6: 'stopped' } } it { is_expected.to contain_service('ip6tables').with( ensure: 'stopped', ) } end context 'with enable => false' do let(:params) { { enable: 'false' } } it { is_expected.to contain_service('iptables').with( enable: 'false', ) } end context 'with enable_v6 => false' do let(:params) { { enable_v6: 'false' } } it { is_expected.to contain_service('ip6tables').with( enable: 'false', ) } end it { is_expected.to contain_service('firewalld').with( ensure: 'stopped', enable: false, before: ['Package[iptables-services]', 'Service[iptables]'], ) } it { is_expected.to contain_package('iptables-services').with( ensure: 'present', before: 'Service[iptables]', ) } it_behaves_like 'ensures iptables service' end end end end puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_linux_spec.rb0100644005276200011600000000274513207747121022507 0ustar00require 'spec_helper' describe 'firewall::linux', type: :class do %w[RedHat CentOS Fedora].each do |os| context "Redhat Like: operatingsystem => #{os}" do releases = ((os == 'Fedora') ? %w[14 15 Rawhide] : %w[6 7]) releases.each do |osrel| context "operatingsystemrelease => #{osrel}" do let(:facts) do { kernel: 'Linux', operatingsystem: os, operatingsystemrelease: osrel, osfamily: 'RedHat', selinux: false, puppetversion: Puppet.version, } end it { is_expected.to contain_class('firewall::linux::redhat').with_require('Package[iptables]') } it { is_expected.to contain_package('iptables').with_ensure('present') } end end end end %w[Debian Ubuntu].each do |os| context "Debian Like: operatingsystem => #{os}" do releases = ((os == 'Debian') ? %w[6 7 8] : ['10.04', '12.04', '14.04']) releases.each do |osrel| let(:facts) do { kernel: 'Linux', operatingsystem: os, operatingsystemrelease: osrel, osfamily: 'Debian', selinux: false, puppetversion: Puppet.version, } end it { is_expected.to contain_class('firewall::linux::debian').with_require('Package[iptables]') } it { is_expected.to contain_package('iptables').with_ensure('present') } end end end end puppetlabs-firewall-1.12.0/spec/unit/classes/firewall_spec.rb0100644005276200011600000000266713232340436021267 0ustar00require 'spec_helper' describe 'firewall', type: :class do context 'with kernel => Linux' do with_debian_facts it { is_expected.to contain_class('firewall::linux').with_ensure('running') } end context 'with kernel => Windows' do let(:facts) { { kernel: 'Windows' } } it { expect { is_expected.to contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'with kernel => SunOS' do let(:facts) { { kernel: 'SunOS' } } it { expect { is_expected.to contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'with kernel => Darwin' do let(:facts) { { kernel: 'Darwin' } } it { expect { is_expected.to contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'with ensure => stopped' do with_debian_facts let(:params) { { ensure: 'stopped' } } it { is_expected.to contain_class('firewall::linux').with_ensure('stopped') } end context 'with ensure => test' do let(:facts) { { kernel: 'Linux' } } let(:params) { { ensure: 'test' } } it { expect { is_expected.to contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'with ebtables_manage => true' do let(:facts) { { kernel: 'Linux' } } let(:params) { { ebtables_manage: true } } it { expect { is_expected.to contain_package('ebtables') }.to raise_error(Puppet::Error) } end # rubocop:enable RSpec/MultipleExpectations end puppetlabs-firewall-1.12.0/spec/unit/documentation0040755005276200011600000000000013232340576017255 5ustar00puppetlabs-firewall-1.12.0/spec/unit/documentation/readme_spec.rb0100644005276200011600000000031213207747121022120 0ustar00describe 'formatting in README.markdown' do it 'does not contain badly formatted heading markers' do content = File.read('README.markdown') expect(content).not_to match %r{^#+[^# ]} end end puppetlabs-firewall-1.12.0/spec/unit/facter0040755005276200011600000000000013232340576015650 5ustar00puppetlabs-firewall-1.12.0/spec/unit/facter/iptables_persistent_version_spec.rb0100644005276200011600000000654113232340436025114 0ustar00require 'spec_helper' describe 'Facter::Util::Fact iptables_persistent_version' do context 'when iptables-persistent applicable' do before(:each) { Facter.clear } let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" } { 'Debian' => '0.0.20090701', 'Ubuntu' => '0.5.3ubuntu2', }.each do |os, ver| if os == 'Debian' os_release = '7.0' elsif os == 'Ubuntu' os_release = '14.04' end describe "#{os} package installed" do before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value).and_return(os) allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return(os_release) allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd) .and_return(ver) end it { expect(Facter.fact(:iptables_persistent_version).value).to eql ver } end end describe 'Ubuntu package not installed' do before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('14.04') allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd) .and_return(nil) end it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil } end describe 'CentOS not supported' do before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value) .and_return('CentOS') end it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil } end end context 'when netfilter-persistent applicable' do before(:each) { Facter.clear } let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' netfilter-persistent 2>/dev/null" } { 'Debian' => '0.0.20090701', 'Ubuntu' => '0.5.3ubuntu2', }.each do |os, ver| if os == 'Debian' os_release = '8.0' elsif os == 'Ubuntu' os_release = '14.10' end describe "#{os} package installed" do before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value).and_return(os) allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return(os_release) allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd) .and_return(ver) end it { expect(Facter.fact(:iptables_persistent_version).value).to eql ver } end end describe 'Ubuntu package not installed' do os_release = '14.10' before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return(os_release) allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd) .and_return(nil) end it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil } end describe 'CentOS not supported' do before(:each) do allow(Facter.fact(:operatingsystem)).to receive(:value) .and_return('CentOS') end it { expect(Facter.fact(:iptables_persistent_version).value).to be_nil } end end end puppetlabs-firewall-1.12.0/spec/unit/facter/iptables_spec.rb0100644005276200011600000000144513207747121021071 0ustar00require 'spec_helper' describe 'Facter::Util::Fact' do before(:each) do Facter.clear allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:kernelrelease)).to receive(:value).and_return('2.6') end describe 'iptables_version' do it { allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version') .and_return('iptables v1.4.7') expect(Facter.fact(:iptables_version).value).to eql '1.4.7' } end describe 'ip6tables_version' do before(:each) do allow(Facter::Util::Resolution).to receive(:exec) .with('ip6tables --version').and_return('ip6tables v1.4.7') end it { expect(Facter.fact(:ip6tables_version).value).to eql '1.4.7' } end end puppetlabs-firewall-1.12.0/spec/unit/puppet0040755005276200011600000000000013232340576015721 5ustar00puppetlabs-firewall-1.12.0/spec/unit/puppet/provider0040755005276200011600000000000013232340576017553 5ustar00puppetlabs-firewall-1.12.0/spec/unit/puppet/provider/ip6tables_spec.rb0100644005276200011600000000405213232340436023053 0ustar00#!/usr/bin/env rspec # rubocop:disable Lint/ScriptPermission : Puppet error? require 'spec_helper' if Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') < 0 require 'puppet/provider/confine/exists' else require 'puppet/confine/exists' end provider_class = Puppet::Type.type(:firewall).provider(:ip6tables) describe 'ip6tables' do let(:params) { { name: '000 test foo', action: 'accept' } } let(:provider) { provider_class } let(:resource) { Puppet::Type.type(:firewall) } let(:ip6tables_version) { '1.4.0' } before :each do end def stub_iptables allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider # Stub confine facts allow(provider).to receive(:command).with(:iptables_save).and_return '/sbin/iptables-save' allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian') allow(Facter.fact('ip6tables_version')).to receive(:value).and_return(ip6tables_version) allow(Puppet::Util::Execution).to receive(:execute).and_return '' allow(Puppet::Util).to receive(:which).with('iptables-save') .and_return '/sbin/iptables-save' end shared_examples 'raise error' do it { stub_iptables expect { provider.new(resource.new(params)) }.to raise_error(Puppet::DevError, error_message) } end shared_examples 'run' do it { stub_iptables provider.new(resource.new(params)) } end context 'when iptables 1.3' do let(:params) { { name: '000 test foo', action: 'accept' } } let(:error_message) { %r{The ip6tables provider is not supported on version 1\.3 of iptables} } let(:ip6tables_version) { '1.3.10' } it_behaves_like 'raise error' end context 'when ip6tables nil' do let(:params) { { name: '000 test foo', action: 'accept' } } let(:error_message) { %r{The ip6tables provider is not supported on version 1\.3 of iptables} } let(:ip6tables_version) { nil } it_behaves_like 'run' end end puppetlabs-firewall-1.12.0/spec/unit/puppet/provider/iptables_chain_spec.rb0100755005276200011600000001702113232340436024132 0ustar00#!/usr/bin/env rspec require 'spec_helper' if Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') < 0 require 'puppet/provider/confine/exists' else require 'puppet/confine/exists' end describe 'iptables chain' do describe 'iptables chain provider detection' do if Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') < 0 let(:exists) do Puppet::Provider::Confine::Exists end else let(:exists) do Puppet::Confine::Exists end end before :each do # Reset the default provider Puppet::Type.type(:firewallchain).defaultprovider = nil # Stub confine facts allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian') # Stub lookup for /sbin/iptables & /sbin/iptables-save allow(exists).to receive(:which).with('ebtables') .and_return '/sbin/ebtables' allow(exists).to receive(:which).with('ebtables-save') .and_return '/sbin/ebtables-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' allow(exists).to receive(:which).with('ip6tables') .and_return '/sbin/ip6tables' allow(exists).to receive(:which).with('ip6tables-save') .and_return '/sbin/ip6tables-save' # Every other command should return false so we don't pick up any # other providers allow(exists).to receive(:which) { |value| value !~ %r{(eb|ip|ip6)tables(-save)?$} }.and_return false end it 'defaults to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists' do # Create a resource instance and make sure the provider is iptables resource = Puppet::Type.type(:firewallchain).new(name: 'test:filter:IPv4') expect(resource.provider.class.to_s).to eq('Puppet::Type::Firewallchain::ProviderIptables_chain') end end describe 'iptables chain provider' do let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) } let(:resource) do Puppet::Type.type(:firewallchain).new(name: ':test:') end before :each do allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider allow(provider).to receive(:command).with(:ebtables_save).and_return '/sbin/ebtables-save' allow(provider).to receive(:command).with(:iptables_save).and_return '/sbin/iptables-save' allow(provider).to receive(:command).with(:ip6tables_save).and_return '/sbin/ip6tables-save' # Pretend to return nil from iptables allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return('') allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return('') allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return('') end it 'is able to get a list of existing rules' do provider.instances.each do |chain| expect(chain).to be_instance_of(provider) expect(chain.properties[:provider].to_s).to eq(provider.name.to_s) end end end describe 'iptables chain resource parsing' do let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) } before :each do ebtables = ['BROUTE:BROUTING:ethernet', 'BROUTE:broute:ethernet', ':INPUT:ethernet', ':FORWARD:ethernet', ':OUTPUT:ethernet', ':filter:ethernet', ':filterdrop:ethernet', ':filterreturn:ethernet', 'NAT:PREROUTING:ethernet', 'NAT:OUTPUT:ethernet', 'NAT:POSTROUTING:ethernet'] allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return(' *broute :BROUTING ACCEPT :broute ACCEPT *filter :INPUT ACCEPT :FORWARD ACCEPT :OUTPUT ACCEPT :filter ACCEPT :filterdrop DROP :filterreturn RETURN *nat :PREROUTING ACCEPT :OUTPUT ACCEPT :POSTROUTING ACCEPT ') iptables = [ 'raw:PREROUTING:IPv4', 'raw:OUTPUT:IPv4', 'raw:raw:IPv4', 'mangle:PREROUTING:IPv4', 'mangle:INPUT:IPv4', 'mangle:FORWARD:IPv4', 'mangle:OUTPUT:IPv4', 'mangle:POSTROUTING:IPv4', 'mangle:mangle:IPv4', 'NAT:PREROUTING:IPv4', 'NAT:OUTPUT:IPv4', 'NAT:POSTROUTING:IPv4', 'NAT:mangle:IPv4', 'NAT:mangle:IPv4', 'NAT:mangle:IPv4', 'security:INPUT:IPv4', 'security:FORWARD:IPv4', 'security:OUTPUT:IPv4', ':$5()*&%\'"^$): :IPv4', ] allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return(' # Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012 *raw :PREROUTING ACCEPT [12:1780] :OUTPUT ACCEPT [19:1159] :raw - [0:0] COMMIT # Completed on Mon Jan 2 01:20:06 2012 # Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012 *mangle :PREROUTING ACCEPT [12:1780] :INPUT ACCEPT [12:1780] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [19:1159] :POSTROUTING ACCEPT [19:1159] :mangle - [0:0] COMMIT # Completed on Mon Jan 2 01:20:06 2012 # Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012 *nat :PREROUTING ACCEPT [2242:639750] :OUTPUT ACCEPT [5176:326206] :POSTROUTING ACCEPT [5162:325382] COMMIT # Completed on Mon Jan 2 01:20:06 2012 # Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012 *filter :INPUT ACCEPT [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [5673:420879] :$5()*&%\'"^$): - [0:0] COMMIT # Completed on Mon Jan 2 01:20:06 2012 ') ip6tables = [ 'raw:PREROUTING:IPv6', 'raw:OUTPUT:IPv6', 'raw:ff:IPv6', 'mangle:PREROUTING:IPv6', 'mangle:INPUT:IPv6', 'mangle:FORWARD:IPv6', 'mangle:OUTPUT:IPv6', 'mangle:POSTROUTING:IPv6', 'mangle:ff:IPv6', 'security:INPUT:IPv6', 'security:FORWARD:IPv6', 'security:OUTPUT:IPv6', ':INPUT:IPv6', ':FORWARD:IPv6', ':OUTPUT:IPv6', ':test:IPv6', ] allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return(' # Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012 *raw :PREROUTING ACCEPT [2173:489241] :OUTPUT ACCEPT [0:0] :ff - [0:0] COMMIT # Completed on Mon Jan 2 01:31:39 2012 # Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012 *mangle :PREROUTING ACCEPT [2301:518373] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :ff - [0:0] COMMIT # Completed on Mon Jan 2 01:31:39 2012 # Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012 *filter :INPUT ACCEPT [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [20:1292] :test - [0:0] COMMIT # Completed on Mon Jan 2 01:31:39 2012 ') @all = ebtables + iptables + ip6tables # IPv4 and IPv6 names also exist as resources {table}:{chain}:IP and {table}:{chain}: iptables.each { |name| @all += [name[0..-3], name[0..-5]] } ip6tables.each { |name| @all += [name[0..-3], name[0..-5]] } end it 'has all in parsed resources' do provider.instances.each do |resource| @all.include?(resource.name) # rubocop:disable RSpec/InstanceVariable end end end end puppetlabs-firewall-1.12.0/spec/unit/puppet/provider/iptables_spec.rb0100644005276200011600000004511613232340436022773 0ustar00#!/usr/bin/env rspec # rubocop:disable Lint/ScriptPermission : Puppet error? require 'spec_helper' if Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') < 0 require 'puppet/provider/confine/exists' else require 'puppet/confine/exists' end describe 'iptables provider detection' do # rubocop:disable RSpec/MultipleDescribes if Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') < 0 let(:exists) do Puppet::Provider::Confine::Exists end else let(:exists) do Puppet::Confine::Exists end end before :each do # Reset the default provider Puppet::Type.type(:firewall).defaultprovider = nil # Stub confine facts allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian') end 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 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) }.and_return false # Create a resource instance and make sure the provider is iptables resource = Puppet::Type.type(:firewall).new(name: '000 test foo') expect(resource.provider.class.to_s).to eq('Puppet::Type::Firewall::ProviderIptables') end end describe 'iptables provider' do let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) } let(:resource) do Puppet::Type.type(:firewall).new(name: '000 test foo', action: 'accept') end before :each do allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider allow(provider).to receive(:command).with(:iptables_save).and_return '/sbin/iptables-save' # Stub iptables version allow(Facter.fact(:iptables_version)).to receive(:value).and_return('1.4.2') allow(Puppet::Util::Execution).to receive(:execute).and_return '' allow(Puppet::Util).to receive(:which).with('iptables-save') .and_return '/sbin/iptables-save' end 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 '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') expect(provider.instances.length).to be_zero end describe '#insert_order' do let(:iptables_save_output) do [ '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -m comment --comment "200 test" -j ACCEPT', '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT', ] end let(:resources) do iptables_save_output.each_with_index.map { |l, index| provider.rule_to_hash(l, 'filter', index) } end let(:providers) do resources.map { |r| provider.new(r) } end it 'understands offsets for adding rules to the beginning' do resource = Puppet::Type.type(:firewall).new(name: '001 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(1) # 1-indexed end it 'understands offsets for editing rules at the beginning' do resource = Puppet::Type.type(:firewall).new(name: '100 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(1) end it 'understands offsets for adding rules to the middle' do resource = Puppet::Type.type(:firewall).new(name: '101 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(2) end it 'understands offsets for editing rules at the middle' do resource = Puppet::Type.type(:firewall).new(name: '200 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(2) end it 'understands offsets for adding rules to the end' do resource = Puppet::Type.type(:firewall).new(name: '301 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(4) end it 'understands offsets for editing rules at the end' do resource = Puppet::Type.type(:firewall).new(name: '300 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(3) end context 'with unname rules between' do let(:iptables_save_output) do [ '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT', '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT', '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT', '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT', ] end it 'understands offsets for adding rules before unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '001 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(1) end it 'understands offsets for editing rules before unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '100 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(1) end it 'understands offsets for adding rules between managed rules' do resource = Puppet::Type.type(:firewall).new(name: '120 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(2) end it 'understands offsets for adding rules between unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '151 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(3) end it 'understands offsets for adding rules after unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '351 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(7) end end context 'with unname rules before and after' do let(:iptables_save_output) do [ '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 050 -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 090 -j ACCEPT', '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT', '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT', '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT', '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT', '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT', '-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 400 -j ACCEPT', '-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 450 -j ACCEPT', ] end it 'understands offsets for adding rules before unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '001 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(1) end it 'understands offsets for editing rules before unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '100 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(3) end it 'understands offsets for adding rules between managed rules' do resource = Puppet::Type.type(:firewall).new(name: '120 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(4) end it 'understands offsets for adding rules between unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '151 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(5) end it 'understands offsets for adding rules after unnamed rules' do resource = Puppet::Type.type(:firewall).new(name: '351 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(9) end it 'understands offsets for adding rules at the end' do resource = Puppet::Type.type(:firewall).new(name: '950 test') allow(resource.provider.class).to receive(:instances).and_return(providers) expect(resource.provider.insert_order).to eq(11) end end end # Load in ruby hash for test fixtures. load 'spec/fixtures/iptables/conversion_hash.rb' describe 'when converting rules to resources' do ARGS_TO_HASH.each do |test_name, data| describe "for test data '#{test_name}'" do let(:resource) { provider.rule_to_hash(data[:line], data[:table], 0) } # If this option is enabled, make sure the error was raised if data[:produce_warning] it 'the input rules should produce a warning by rules_to_hash' do allow(provider).to receive(:warning).with(%r{Skipping unparsable iptables rule}) resource # force resource to get evaluated end end # If this option is enabled, make sure the parameters exactly match if data[:compare_all] it 'the parameter hash keys should be the same as returned by rules_to_hash' do expect(resource.keys).to match_array(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}' should match #{param_value.inspect}" do # booleans get cludged to string "true" if param_value == true expect(resource[param_name]).to be_truthy else expect(resource[param_name]).to eq(data[:params][param_name]) end end end end end end describe 'when working out general_args' do HASH_TO_ARGS.each do |test_name, data| describe "for test data '#{test_name}'" do let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) } let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) } let(:instance) { provider.new(resource) } it 'general_args should be valid' do expect(instance.general_args.flatten).to eq(data[:args]) end end end end describe 'when converting rules without comments to resources' do let(:sample_rule) do '-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT' end let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) } let(:instance) { provider.new(resource) } it 'rule name contains a MD5 sum of the line' do expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}") end resource_types = [:chain, :source, :destination, :proto, :dport, :sport, :action] rule_values = ['INPUT', '1.1.1.1/32', '1.1.1.1/32', 'tcp', %w[7061 7062], %w[7061 7062], 'accept'] it 'parsed the rule arguments correctly' do resource_types.each_with_index do |type, index| expect(resource[type]).to eq(rule_values[index]) end end end describe 'when converting existing rules generates by system-config-firewall-tui to resources' do let(:sample_rule) do # as generated by iptables-save from rules created with system-config-firewall-tui '-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT' end let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) } let(:instance) { provider.new(resource) } it 'rule name contains a MD5 sum of the line' do expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}") end resource_types = [:chain, :proto, :dport, :state, :action] rule_values = ['INPUT', 'tcp', ['22'], ['NEW'], 'accept'] it 'parse arguments' do resource_types.each_with_index do |type, index| expect(resource[type]).to eq(rule_values[index]) end end end describe 'when creating resources' do let(:instance) { provider.new(resource) } it 'insert_args should be an array' do expect(instance.insert_args.class).to eq(Array) end end describe 'when modifying resources' do let(:instance) { provider.new(resource) } it 'update_args should be an array' do expect(instance.update_args.class).to eq(Array) end it 'fails when modifying the chain' do expect { instance.chain = 'OUTPUT' }.to raise_error(%r{is not supported}) end end describe 'when inverting rules' do let(:resource) do Puppet::Type.type(:firewall).new(name: '040 partial invert', table: 'filter', action: 'accept', chain: 'nova-compute-FORWARD', source: '0.0.0.0/32', destination: '255.255.255.255/32', sport: ['! 78', '79', 'http'], dport: ['77', '! 76'], proto: 'udp') end let(:instance) { provider.new(resource) } it 'fails when not all array items are inverted' do expect { instance.insert }.to raise_error RuntimeError, %r{but '79', '80' are not prefixed} end end describe 'when deleting resources' do let(:sample_rule) do '-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT' end let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) } let(:instance) { provider.new(resource) } it 'resource[:line] looks like the original rule' do resource[:line] == sample_rule end it 'delete_args is an array' do expect(instance.delete_args.class).to eq(Array) end it 'delete_args is the same as the rule string when joined' do expect(instance.delete_args.join(' ')).to eq(sample_rule.gsub(%r{\-A}, '-t filter -D')) end end end describe 'ip6tables provider' do let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) } let(:resource) do Puppet::Type.type(:firewall).new(name: '000 test foo', action: 'accept', provider: 'ip6tables') end before :each do allow(Puppet::Type::Firewall).to receive(:ip6tables).and_return provider6 allow(provider6).to receive(:command).with(:ip6tables_save).and_return '/sbin/ip6tables-save' # Stub iptables version allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return '1.4.7' allow(Puppet::Util::Execution).to receive(:execute).and_return '' allow(Puppet::Util).to receive(:which).with('ip6tables-save') .and_return '/sbin/ip6tables-save' end it 'is expected to be able to get a list of existing rules' do provider6.instances.each do |rule| expect(rule).to be_instance_of(provider6) expect(rule.properties[:provider6].to_s).to eql provider6.name.to_s end end 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') expect(provider6.instances.length).to eq 0 end # Load in ruby hash for test fixtures. load 'spec/fixtures/ip6tables/conversion_hash.rb' describe 'when converting rules to resources' do ARGS_TO_HASH6.each do |test_name, data| describe "for test data '#{test_name}'" do let(:resource) { provider6.rule_to_hash(data[:line], data[:table], 0) } # If this option is enabled, make sure the parameters exactly match if data[:compare_all] it 'the parameter hash keys should be the same as returned by rules_to_hash' do 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}' should match #{param_value.inspect}" do expect(resource[param_name]).to eql data[:params][param_name] end end end end end describe 'when working out general_args' do HASH_TO_ARGS6.each do |test_name, data| describe "for test data '#{test_name}'" do let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) } let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) } let(:instance) { provider6.new(resource) } it 'general_args should be valid' do data[:args].unshift('--wait') if instance.general_args.flatten.include? '--wait' expect(instance.general_args.flatten).to eql data[:args] end end end end end puppetlabs-firewall-1.12.0/spec/unit/puppet/type0040755005276200011600000000000013232340576016702 5ustar00puppetlabs-firewall-1.12.0/spec/unit/puppet/type/firewall_spec.rb0100755005276200011600000006043713232340436022132 0ustar00#!/usr/bin/env rspec require 'spec_helper' firewall = Puppet::Type.type(:firewall) describe firewall do # rubocop:disable RSpec/MultipleDescribes let(:firewall_class) { firewall } let(:provider) { instance_double('provider') } let(:resource) { firewall_class.new(name: '000 test foo') } before :each do allow(provider).to receive(:name).and_return(:iptables) allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider # Stub iptables version allow(Facter.fact(:iptables_version)).to receive(:value).and_return('1.4.2') allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return('1.4.2') # Stub confine facts allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian') end it 'has :name be its namevar' do expect(firewall_class.key_attributes).to eql [:name] end describe ':name' do it 'accepts a name' do resource[:name] = '000-test-foo' expect(resource[:name]).to eql '000-test-foo' end it 'does not accept a name with non-ASCII chars' do expect(-> { resource[:name] = '%*#^(#$' }).to raise_error(Puppet::Error) end end describe ':action' do it 'has no default' do res = firewall_class.new(name: '000 test') expect(res.parameters[:action]).to be nil end [:accept, :drop, :reject].each do |action| it "should accept value #{action}" do resource[:action] = action expect(resource[:action]).to eql action end end it 'fails when value is not recognized' do expect(-> { resource[:action] = 'not valid' }).to raise_error(Puppet::Error) end end describe ':chain' do [:INPUT, :FORWARD, :OUTPUT, :PREROUTING, :POSTROUTING].each do |chain| it "should accept chain value #{chain}" do resource[:chain] = chain expect(resource[:chain]).to eql chain end end it 'fails when the chain value is not recognized' do expect(-> { resource[:chain] = 'not valid' }).to raise_error(Puppet::Error) end end describe ':table' do [:nat, :mangle, :filter, :raw].each do |table| it "should accept table value #{table}" do resource[:table] = table expect(resource[:table]).to eql table end end it 'fails when table value is not recognized' do expect(-> { resource[:table] = 'not valid' }).to raise_error(Puppet::Error) end end describe ':proto' do [:ip, :tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :pim, :all].each do |proto| it "should accept proto value #{proto}" do resource[:proto] = proto expect(resource[:proto]).to eql proto end end it 'fails when proto value is not recognized' do expect(-> { resource[:proto] = 'foo' }).to raise_error(Puppet::Error) end end describe ':jump' do it 'has no default' do res = firewall_class.new(name: '000 test') expect(res.parameters[:jump]).to be nil end %w[QUEUE RETURN DNAT SNAT LOG NFLOG MASQUERADE REDIRECT MARK].each do |jump| it "should accept jump value #{jump}" do resource[:jump] = jump expect(resource[:jump]).to eql jump end end %w[ACCEPT DROP REJECT].each do |jump| it "should now fail when value #{jump}" do expect(-> { resource[:jump] = jump }).to raise_error(Puppet::Error) end end it 'fails when jump value is not recognized' do expect(-> { resource[:jump] = '%^&*' }).to raise_error(Puppet::Error) end end [:source, :destination].each do |addr| describe addr do it "should accept a #{addr} as a string" do resource[addr] = '127.0.0.1' expect(resource[addr]).to eql '127.0.0.1/32' end ['0.0.0.0/0', '::/0'].each do |prefix| it "should be nil for zero prefix length address #{prefix}" do resource[addr] = prefix expect(resource[addr]).to be nil end end it "should accept a negated #{addr} as a string" do resource[addr] = '! 127.0.0.1' expect(resource[addr]).to eql '! 127.0.0.1/32' end end end [:dport, :sport].each do |port| describe port do it "should accept a #{port} as string" do resource[port] = '22' expect(resource[port]).to eql ['22'] end it "should accept a #{port} as an array" do resource[port] = %w[22 23] expect(resource[port]).to eql %w[22 23] end it "should accept a #{port} as a number" do resource[port] = 22 expect(resource[port]).to eql ['22'] end it "should accept a #{port} as a hyphen separated range" do resource[port] = ['22-1000'] expect(resource[port]).to eql ['22-1000'] end it "should accept a #{port} as a combination of arrays of single and " \ 'hyphen separated ranges' do resource[port] = ['22-1000', '33', '3000-4000'] expect(resource[port]).to eql ['22-1000', '33', '3000-4000'] end it "should convert a port name for #{port} to its number" do resource[port] = 'ssh' expect(resource[port]).to eql ['22'] end it "should not accept something invalid for #{port}" do expect { resource[port] = 'something odd' }.to raise_error(Puppet::Error, %r{^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service}) end it "should not accept something invalid in an array for #{port}" do expect { resource[port] = ['something odd', 'something even odder'] }.to raise_error(Puppet::Error, %r{^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service}) end end end describe 'port deprecated' do it 'raises a warning' do allow(Puppet).to receive(:warning).with %r{port to firewall is deprecated} resource[:port] = '22' end end [:dst_type, :src_type].each do |addrtype| describe addrtype do it 'has no default' do res = firewall_class.new(name: '000 test') expect(res.parameters[addrtype]).to be nil end end [:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type| it "should accept #{addrtype} value #{type}" do resource[addrtype] = type expect(resource[addrtype]).to eql type end end it "should fail when #{addrtype} value is not recognized" do expect(-> { resource[addrtype] = 'foo' }).to raise_error(Puppet::Error) end end [:iniface, :outiface].each do |iface| describe iface do it "should accept #{iface} value as a string" do resource[iface] = 'eth1' expect(resource[iface]).to eql 'eth1' end it "should accept a negated #{iface} value as a string" do resource[iface] = '! eth1' expect(resource[iface]).to eql '! eth1' end it "should accept an interface alias for the #{iface} value as a string" do resource[iface] = 'eth1:2' expect(resource[iface]).to eql 'eth1:2' end end end [:tosource, :todest, :to].each do |addr| describe addr do it "should accept #{addr} value as a string" do resource[addr] = '127.0.0.1' end end end describe ':log_level' do values = { 'panic' => '0', 'alert' => '1', 'crit' => '2', 'err' => '3', 'warn' => '4', 'warning' => '4', 'not' => '5', 'notice' => '5', 'info' => '6', 'debug' => '7', } values.each do |k, v| it { resource[:log_level] = k expect(resource[:log_level]).to eql v } it { resource[:log_level] = 3 expect(resource[:log_level]).to be 3 } it { expect(-> { resource[:log_level] = 'foo' }).to raise_error(Puppet::Error) } end end describe 'NFLOG' do describe ':nflog_group' do [0, 1, 5, 10].each do |v| it { resource[:nflog_group] = v expect(resource[:nflog_group]).to eq v } end [-3, 999_999].each do |v| it { expect(-> { resource[:nflog_group] = v }).to raise_error(Puppet::Error, %r{2\^16\-1}) } end end describe ':nflog_prefix' do let(:valid_prefix) { 'This is a valid prefix' } let(:invalid_prefix) { 'This is not a valid prefix. !t is longer than 64 char@cters for sure. How do I know? I c0unted.' } it { resource[:nflog_prefix] = valid_prefix expect(resource[:nflog_prefix]).to eq valid_prefix } it { expect(-> { resource[:nflog_prefix] = invalid_prefix }).to raise_error(Puppet::Error, %r{64 characters}) } end end describe ':icmp' do icmp_codes = { iptables: { '0' => 'echo-reply', '3' => 'destination-unreachable', '4' => 'source-quench', '6' => 'redirect', '8' => 'echo-request', '9' => 'router-advertisement', '10' => 'router-solicitation', '11' => 'time-exceeded', '12' => 'parameter-problem', '13' => 'timestamp-request', '14' => 'timestamp-reply', '17' => 'address-mask-request', '18' => 'address-mask-reply', }, ip6tables: { '1' => 'destination-unreachable', '2' => 'too-big', '3' => 'time-exceeded', '4' => 'parameter-problem', '128' => 'echo-request', '129' => 'echo-reply', '133' => 'router-solicitation', '134' => 'router-advertisement', '137' => 'redirect', }, } icmp_codes.each do |provider, values| describe provider do values.each do |k, v| resource_type = [:provider, :icmp] resource_value = [provider, v] resource_expected = [provider, k] it 'converts icmp string to number' do resource_type.each_with_index do |type, index| resource[type] = resource_value[index] expect(resource[type]).to eql resource_expected[index] end end end end end it 'accepts values as integers' do resource[:icmp] = 9 expect(resource[:icmp]).to be 9 end it 'fails if icmp type is "any"' do expect(-> { resource[:icmp] = 'any' }).to raise_error(Puppet::Error) end it 'fails if icmp type is an array' do expect(-> { resource[:icmp] = "['0', '8']" }).to raise_error(Puppet::Error) end it 'fails if icmp type cannot be mapped to a numeric' do expect(-> { resource[:icmp] = 'foo' }).to raise_error(Puppet::Error) end end describe ':state' do it 'accepts value as a string - INVALID' do resource[:state] = :INVALID expect(resource[:state]).to eql [:INVALID] end it 'accepts value as a string - UNTRACKED' do resource[:state] = :UNTRACKED expect(resource[:state]).to eql [:UNTRACKED] end it 'accepts value as an array - INVALID, NEW' do resource[:state] = [:INVALID, :NEW] expect(resource[:state]).to eql [:INVALID, :NEW] end it 'sorts values alphabetically - NEW, UNTRACKED, ESTABLISHED' do resource[:state] = [:NEW, :UNTRACKED, :ESTABLISHED] expect(resource[:state]).to eql [:ESTABLISHED, :NEW, :UNTRACKED] end end describe ':ctstate' do it 'accepts value as a string - INVALID' do resource[:ctstate] = :INVALID expect(resource[:ctstate]).to eql [:INVALID] end it 'accepts value as a string - UNTRACKED' do resource[:state] = :UNTRACKED expect(resource[:state]).to eql [:UNTRACKED] end it 'accepts value as an array - INVALID, NEW' do resource[:ctstate] = [:INVALID, :NEW] expect(resource[:ctstate]).to eql [:INVALID, :NEW] end it 'sorts values alphabetically - NEW, ESTABLISHED' do resource[:ctstate] = [:NEW, :ESTABLISHED] expect(resource[:ctstate]).to eql [:ESTABLISHED, :NEW] end end describe ':burst' do it 'accepts numeric values' do resource[:burst] = 12 expect(resource[:burst]).to be 12 end it 'fails if value is not numeric' do expect(-> { resource[:burst] = 'foo' }).to raise_error(Puppet::Error) end end describe ':recent' do %w[set update rcheck remove].each do |recent| it "should accept recent value #{recent}" do resource[:recent] = recent expect(resource[:recent]).to eql "--#{recent}" end end end describe ':action and :jump' do it 'allows only 1 to be set at a time' do expect { firewall_class.new(name: '001-test', action: 'accept', jump: 'custom_chain') }.to raise_error(RuntimeError, %r{Only one of the parameters 'action' and 'jump' can be set$}) end end describe ':gid and :uid' do it 'allows me to set uid' do resource[:uid] = 'root' expect(resource[:uid]).to eql 'root' end it 'allows me to set uid as an array, and silently hide my error' do resource[:uid] = %w[root bobby] expect(resource[:uid]).to eql 'root' end it 'allows me to set gid' do resource[:gid] = 'root' expect(resource[:gid]).to eql 'root' end it 'allows me to set gid as an array, and silently hide my error' do resource[:gid] = %w[root bobby] expect(resource[:gid]).to eql 'root' end end describe ':set_mark' do ['1.3.2', '1.4.2'].each do |iptables_version| describe "with iptables #{iptables_version}" do before(:each) do Facter.clear allow(Facter.fact(:iptables_version)).to receive(:value).and_return iptables_version allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return iptables_version end if iptables_version == '1.3.2' it 'allows me to set set-mark without mask' do resource[:set_mark] = '0x3e8' expect(resource[:set_mark]).to eql '0x3e8' end it 'converts int to hex without mask' do resource[:set_mark] = '1000' expect(resource[:set_mark]).to eql '0x3e8' end it 'fails if mask is present' do expect(-> { resource[:set_mark] = '0x3e8/0xffffffff' }).to raise_error( Puppet::Error, %r{iptables version #{iptables_version} does not support masks on MARK rules$} ) end end if iptables_version == '1.4.2' it 'allows me to set set-mark with mask' do resource[:set_mark] = '0x3e8/0xffffffff' expect(resource[:set_mark]).to eql '0x3e8/0xffffffff' end it 'converts int to hex and add a 32 bit mask' do resource[:set_mark] = '1000' expect(resource[:set_mark]).to eql '0x3e8/0xffffffff' end it 'adds a 32 bit mask' do resource[:set_mark] = '0x32' expect(resource[:set_mark]).to eql '0x32/0xffffffff' end it 'uses the mask provided' do resource[:set_mark] = '0x32/0x4' expect(resource[:set_mark]).to eql '0x32/0x4' end it 'uses the mask provided and convert int to hex' do resource[:set_mark] = '1000/0x4' expect(resource[:set_mark]).to eql '0x3e8/0x4' end it 'fails if mask value is more than 32 bits' do expect(-> { resource[:set_mark] = '1/4294967296' }).to raise_error( Puppet::Error, %r{MARK mask must be integer or hex between 0 and 0xffffffff$} ) end it 'fails if mask is malformed' do expect(-> { resource[:set_mark] = '1000/0xq4' }).to raise_error( Puppet::Error, %r{MARK mask must be integer or hex between 0 and 0xffffffff$} ) end end ['/', '1000/', 'pwnie'].each do |bad_mark| it "should fail with malformed mark '#{bad_mark}'" do expect(-> { resource[:set_mark] = bad_mark }).to raise_error(Puppet::Error) end end it 'fails if mark value is more than 32 bits' do expect(-> { resource[:set_mark] = '4294967296' }).to raise_error( Puppet::Error, %r{MARK value must be integer or hex between 0 and 0xffffffff$} ) end end end end [:chain, :jump].each do |param| describe param do it 'autorequires fwchain when table and provider are undefined' do resource[param] = 'FOO' expect(resource[:table]).to be :filter expect(resource[:provider]).to be :iptables chain = Puppet::Type.type(:firewallchain).new(name: 'FOO:filter:IPv4') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end it 'autorequires fwchain when table is undefined and provider is ip6tables' do resource[param] = 'FOO' expect(resource[:table]).to be :filter resource[:provider] = :ip6tables chain = Puppet::Type.type(:firewallchain).new(name: 'FOO:filter:IPv6') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end it 'autorequires fwchain when table is raw and provider is undefined' do resource[param] = 'FOO' resource[:table] = :raw expect(resource[:provider]).to be :iptables chain = Puppet::Type.type(:firewallchain).new(name: 'FOO:raw:IPv4') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end it 'autorequires fwchain when table is raw and provider is ip6tables' do resource[param] = 'FOO' resource[:table] = :raw resource[:provider] = :ip6tables chain = Puppet::Type.type(:firewallchain).new(name: 'FOO:raw:IPv6') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end # test where autorequire is still needed (table != filter) %w[INPUT OUTPUT FORWARD].each do |test_chain| it "should autorequire fwchain #{test_chain} when table is mangle and provider is undefined" do resource[param] = test_chain resource[:table] = :mangle expect(resource[:provider]).to be :iptables chain = Puppet::Type.type(:firewallchain).new(name: "#{test_chain}:mangle:IPv4") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end it "should autorequire fwchain #{test_chain} when table is mangle and provider is ip6tables" do resource[param] = test_chain resource[:table] = :mangle resource[:provider] = :ip6tables chain = Puppet::Type.type(:firewallchain).new(name: "#{test_chain}:mangle:IPv6") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel.source.ref).to eql chain.ref expect(rel.target.ref).to eql resource.ref end end # test of case where autorequire should not happen %w[INPUT OUTPUT FORWARD].each do |test_chain| it "should not autorequire fwchain #{test_chain} when table and provider are undefined" do resource[param] = test_chain expect(resource[:table]).to be :filter expect(resource[:provider]).to be :iptables chain = Puppet::Type.type(:firewallchain).new(name: "#{test_chain}:filter:IPv4") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel).to be nil end it "should not autorequire fwchain #{test_chain} when table is undefined and provider is ip6tables" do resource[param] = test_chain expect(resource[:table]).to be :filter resource[:provider] = :ip6tables chain = Puppet::Type.type(:firewallchain).new(name: "#{test_chain}:filter:IPv6") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain rel = resource.autorequire[0] expect(rel).to be nil end end end end describe ':chain and :jump' do it 'autorequires independent fwchains' do resource[:chain] = 'FOO' resource[:jump] = 'BAR' expect(resource[:table]).to be :filter expect(resource[:provider]).to be :iptables chain_foo = Puppet::Type.type(:firewallchain).new(name: 'FOO:filter:IPv4') chain_bar = Puppet::Type.type(:firewallchain).new(name: 'BAR:filter:IPv4') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource chain_foo catalog.add_resource chain_bar rel = resource.autorequire expect(rel[0].source.ref).to eql chain_foo.ref expect(rel[0].target.ref).to eql resource.ref expect(rel[1].source.ref).to eql chain_bar.ref expect(rel[1].target.ref).to eql resource.ref end end # rubocop:enable RSpec/ExampleLength # rubocop:enable RSpec/MultipleExpectations describe ':pkttype' do [:multicast, :broadcast, :unicast].each do |pkttype| it "should accept pkttype value #{pkttype}" do resource[:pkttype] = pkttype expect(resource[:pkttype]).to eql pkttype end end it 'fails when the pkttype value is not recognized' do expect(-> { resource[:pkttype] = 'not valid' }).to raise_error(Puppet::Error) end end describe 'autorequire packages' do [:iptables, :ip6tables].each do |provider| it "provider #{provider} should autorequire package iptables" do resource[:provider] = provider expect(resource[:provider]).to eql provider 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] expect(rel.source.ref).to eql package.ref expect(rel.target.ref).to eql resource.ref end it "provider #{provider} should autorequire packages iptables, iptables-persistent, and iptables-services" do resource[:provider] = provider expect(resource[:provider]).to eql provider packages = [ Puppet::Type.type(:package).new(name: 'iptables'), Puppet::Type.type(:package).new(name: 'iptables-persistent'), Puppet::Type.type(:package).new(name: 'iptables-services'), ] catalog = Puppet::Resource::Catalog.new catalog.add_resource resource packages.each do |package| catalog.add_resource package end packages.zip(resource.autorequire) do |package, rel| expect(rel.source.ref).to eql package.ref expect(rel.target.ref).to eql resource.ref end end end # rubocop:enable RSpec/ExampleLength # rubocop:enable RSpec/MultipleExpectations end it 'is suitable' do expect(resource).to be_suitable end end describe 'firewall on unsupported platforms' do it 'is not suitable' do # Stub iptables version allow(Facter.fact(:iptables_version)).to receive(:value).and_return(nil) allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return(nil) # Stub confine facts allow(Facter.fact(:kernel)).to receive(:value).and_return('Darwin') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Darwin') resource = firewall.new(name: '000 test foo', ensure: :present) # If our provider list is nil, then the Puppet::Transaction#evaluate will # say 'Error: Could not find a suitable provider for firewall' but there # isn't a unit testable way to get this. expect(resource).not_to be_suitable end end puppetlabs-firewall-1.12.0/spec/unit/puppet/type/firewallchain_spec.rb0100755005276200011600000001772113232340436023133 0ustar00#!/usr/bin/env rspec require 'spec_helper' firewallchain = Puppet::Type.type(:firewallchain) describe firewallchain do # rubocop:disable RSpec/MultipleDescribes before(:each) do # Stub confine facts allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian') end let(:klass) { firewallchain } let(:provider) do prov = instance_double('provider') allow(prov).to receive(:name).and_return(:iptables_chain) prov end let(:resource) do allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider klass.new(name: 'INPUT:filter:IPv4', policy: :accept) end it 'has :name be its namevar' do expect(klass.key_attributes).to eql [:name] end describe ':name' do { 'nat' => %w[PREROUTING POSTROUTING INPUT OUTPUT], 'mangle' => %w[PREROUTING POSTROUTING INPUT FORWARD OUTPUT], 'filter' => %w[INPUT OUTPUT FORWARD], 'raw' => %w[PREROUTING OUTPUT], 'broute' => ['BROUTING'], 'security' => %w[INPUT OUTPUT FORWARD] }.each_pair do |table, allowedinternalchains| %w[IPv4 IPv6 ethernet].each do |protocol| ['test', '$5()*&%\'"^$09):'].each do |chainname| name = "#{chainname}:#{table}:#{protocol}" if table == 'nat' && protocol == 'IPv6' it "should accept #{name} for Linux 3.7+" do allow(Facter.fact(:kernelmajversion)).to receive(:value).and_return('3.7') resource[:name] = 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') expect { resource[:name] = name }.to raise_error(Puppet::Error) end elsif protocol != 'ethernet' && table == 'broute' it "should fail #{name}" do # rubocop:disable RSpec/RepeatedExample expect { resource[:name] = name }.to raise_error(Puppet::Error) end else it "should accept name #{name}" do # rubocop:disable RSpec/RepeatedExample resource[:name] = name expect(resource[:name]).to eql name end end end end %w[PREROUTING POSTROUTING BROUTING INPUT FORWARD OUTPUT].each do |internalchain| name = internalchain + ':' + table + ':' name += if internalchain == 'BROUTING' 'ethernet' elsif table == 'nat' 'IPv4' else 'IPv4' end if allowedinternalchains.include? internalchain it "should allow #{name}" do # rubocop:disable RSpec/RepeatedExample resource[:name] = name expect(resource[:name]).to eql name end else it "should fail #{name}" do # rubocop:disable RSpec/RepeatedExample expect { resource[:name] = name }.to raise_error(Puppet::Error) end end end end it 'fails with invalid table names' do expect { resource[:name] = 'wrongtablename:test:IPv4' }.to raise_error(Puppet::Error) end it 'fails with invalid protocols names' do expect { resource[:name] = 'test:filter:IPv5' }.to raise_error(Puppet::Error) end end describe ':policy' do [:accept, :drop, :queue, :return].each do |policy| it "should accept policy #{policy}" do resource[:policy] = policy expect(resource[:policy]).to eql policy end end it 'fails when value is not recognized' do expect { resource[:policy] = 'not valid' }.to raise_error(Puppet::Error) end [:accept, :drop, :queue, :return].each do |policy| it "non-inbuilt chains should not accept policy #{policy}" do expect { klass.new(name: 'testchain:filter:IPv4', policy: policy) }.to raise_error(RuntimeError) end it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do klass.new(name: 'testchain:filter:ethernet', policy: policy) end end end describe 'autorequire packages' do it 'provider iptables_chain should autorequire package iptables' do expect(resource[:provider]).to be :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] 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 expect(resource[:provider]).to be :iptables_chain packages = [ Puppet::Type.type(:package).new(name: 'iptables'), Puppet::Type.type(:package).new(name: 'iptables-persistent'), Puppet::Type.type(:package).new(name: 'iptables-services'), ] catalog = Puppet::Resource::Catalog.new catalog.add_resource resource packages.each do |package| catalog.add_resource package end packages.zip(resource.autorequire) do |package, rel| expect(rel.source.ref).to eql package.ref expect(rel.target.ref).to eql resource.ref end end # rubocop:enable RSpec/ExampleLength # rubocop:enable RSpec/MultipleExpectations end describe 'purge iptables rules' do # rubocop:disable Layout/IndentHeredoc before(:each) do stub_return = < /etc/iptables/iptables.rules']) host.persist_iptables(proto) end 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') allow(host).to receive(:execute).with(%w[/sbin/service iptables save]).and_raise(Puppet::ExecutionFailure, 'some error') allow(host).to receive(:warning).with('Unable to persist firewall rules: some error') host.persist_iptables(proto) end end describe 'when proto is IPv6' do let(:proto) { 'IPv6' } 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') allow(host).to receive(:execute).with(%w[/usr/sbin/service iptables-persistent save]) host.persist_iptables(proto) end 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') allow(host).to receive(:execute).never host.persist_iptables(proto) end it 'is expected to not exec for Suse which is not supported' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse') allow(host).to receive(:execute).never host.persist_iptables(proto) end end # rubocop:enable RSpec/SubjectStub end end puppetlabs-firewall-1.12.0/spec/unit/puppet/util/ipcidr_spec.rb0100644005276200011600000000570713232340436021567 0ustar00require 'spec_helper' require 'puppet/util/ipcidr' describe 'Puppet::Util::IPCidr' do describe 'ipv4 address' do subject(:host) { ipaddr } let(:ipaddr) { Puppet::Util::IPCidr.new('96.126.112.51') } it { expect(host.cidr).to eql '96.126.112.51/32' } it { expect(host.prefixlen).to be 32 } it { expect(host.netmask).to eql '255.255.255.255' } end describe 'single ipv4 address with cidr' do subject(:host) { ipcidr } let(:ipcidr) { Puppet::Util::IPCidr.new('96.126.112.51/32') } it { expect(host.cidr).to eql '96.126.112.51/32' } it { expect(host.prefixlen).to be 32 } it { expect(host.netmask).to eql '255.255.255.255' } end describe 'ipv4 address range with cidr' do subject(:host) { ipcidr } let(:ipcidr) { Puppet::Util::IPCidr.new('96.126.112.0/24') } it { expect(host.cidr).to eql '96.126.112.0/24' } it { expect(host.prefixlen).to be 24 } it { expect(host.netmask).to eql '255.255.255.0' } end # https://tickets.puppetlabs.com/browse/MODULES-3215 describe 'ipv4 address range with invalid cidr' do subject(:host) { ipcidr } let(:ipcidr) { Puppet::Util::IPCidr.new('96.126.112.20/24') } specify { host.cidr.should == '96.126.112.0/24' } # .20 is expected to # be silently dropped. specify { host.prefixlen.should == 24 } specify { host.netmask.should == '255.255.255.0' } end describe 'ipv4 open range with cidr' do subject(:host) { ipcidr } let(:ipcidr) { Puppet::Util::IPCidr.new('0.0.0.0/0') } it { expect(host.cidr).to eql '0.0.0.0/0' } it { expect(host.prefixlen).to be 0 } it { expect(host.netmask).to eql '0.0.0.0' } end describe 'ipv6 address' do subject(:host) { ipaddr } let(:ipaddr) { Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334') } it { expect(host.cidr).to eql '2001:db8:85a3::8a2e:370:7334/128' } it { expect(host.prefixlen).to be 128 } it { expect(host.netmask).to eql 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' } end describe 'single ipv6 addr with cidr' do subject(:host) { ipaddr } let(:ipaddr) { Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334/128') } it { expect(host.cidr).to eql '2001:db8:85a3::8a2e:370:7334/128' } it { expect(host.prefixlen).to be 128 } it { expect(host.netmask).to eql 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' } end describe 'ipv6 addr range with cidr' do subject(:host) { ipaddr } let(:ipaddr) { Puppet::Util::IPCidr.new('2001:db8:1234::/48') } it { expect(host.cidr).to eql '2001:db8:1234::/48' } it { expect(host.prefixlen).to be 48 } it { expect(host.netmask).to eql 'ffff:ffff:ffff:0000:0000:0000:0000:0000' } end describe 'ipv6 open range with cidr' do subject(:host) { ipaddr } let(:ipaddr) { Puppet::Util::IPCidr.new('::/0') } it { expect(host.cidr).to eql '::/0' } it { expect(host.prefixlen).to be 0 } it { expect(host.netmask).to eql '0000:0000:0000:0000:0000:0000:0000:0000' } end end