puppetlabs-firewall-1.7.1/000755 000765 000024 00000000000 12567122052 015272 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/CHANGELOG.md000644 000765 000024 00000050054 12567120562 017113 0ustar00tpstaff000000 000000 ##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.7.1/checksums.json000644 000765 000024 00000014302 12567122052 020152 0ustar00tpstaff000000 000000 { "CHANGELOG.md": "6ed1eab9ec2269798b1464e5db44df7b", "CONTRIBUTING.md": "e2b8e8e433fc76b3798b7fe435f49375", "Gemfile": "e6e6eb07f0bfc9bb1e328895ca49b3f5", "LICENSE": "ade7f2bb88b5b4f034152822222ec314", "README.markdown": "f7480565105ed553848fe973128af5ce", "Rakefile": "d953eb985f82600dc3b9ac6e1f2cfe64", "lib/facter/ip6tables_version.rb": "091123ad703f1706686bca4398c5b06f", "lib/facter/iptables_persistent_version.rb": "8ea76fecb8032174823ef6fb846c83c9", "lib/facter/iptables_version.rb": "facbd760223f236538b731c1d1f6cf8f", "lib/puppet/provider/firewall/ip6tables.rb": "80c1c94f3d7abaa0736322d77990799a", "lib/puppet/provider/firewall/iptables.rb": "bfae9b44a9861e77154f8c55280e6211", "lib/puppet/provider/firewall.rb": "32d2f5e5dcc082986b82ef26a119038b", "lib/puppet/provider/firewallchain/iptables_chain.rb": "98ac7c8a44014681a243da2391b09de6", "lib/puppet/type/firewall.rb": "d91be4f47e0dfc962dfd9e6df5b90e22", "lib/puppet/type/firewallchain.rb": "cb1ee8ca7718a69284b546f617bf291d", "lib/puppet/util/firewall.rb": "7bcbadf9890c044a49cc58b535352269", "lib/puppet/util/ipcidr.rb": "e1160dfd6e73fc5ef2bb8abc291f6fd5", "manifests/init.pp": "8b7e2921859e31264086f9d5c5d99e66", "manifests/linux/archlinux.pp": "6b1809b8b9c1e9c56bb081b4ef31f198", "manifests/linux/debian.pp": "ba22fb671711015c462864c87cd6918c", "manifests/linux/gentoo.pp": "dc2120f24c259608884d90cb6a9ae27d", "manifests/linux/redhat.pp": "c73aaa2bbd217395440f133b999421f1", "manifests/linux.pp": "951f1c2b2d5bfe393a1b281baad2ec71", "manifests/params.pp": "dbe73a18bf95965108067ecbdfd71301", "metadata.json": "9c33ab9cff29dbb66469286f4d963c61", "spec/acceptance/change_source_spec.rb": "86279f2f4ad9e0532c9ffab00db8e009", "spec/acceptance/class_spec.rb": "4ed057fa674f7c249acb27865a986af4", "spec/acceptance/connlimit_spec.rb": "d63e404842710e581a7d047d30222dd2", "spec/acceptance/connmark_spec.rb": "cf4233e7327af69f0d4431d63140edf1", "spec/acceptance/firewall_bridging_spec.rb": "e11aff2b2524bb3a13784885d412f269", "spec/acceptance/firewall_clusterip_spec.rb": "d7c75cff551024464372ad3199f64f7b", "spec/acceptance/firewall_dscp_spec.rb": "5f04b745ba9a18c8677572bdc85f634b", "spec/acceptance/firewall_iptmodules_spec.rb": "6b74c24cc39271bc19522f2f4ca71e77", "spec/acceptance/firewall_mss_spec.rb": "b105ddc4320f6ae0acbce153aaa948d4", "spec/acceptance/firewall_spec.rb": "e3bb6910d9651768b5e3b0e58e1cb779", "spec/acceptance/firewall_tee_spec.rb": "7368aba479809ed89cdb20a038d3a94b", "spec/acceptance/firewall_time_spec.rb": "b192ba8d4121e9da000feffe752b4199", "spec/acceptance/firewall_uid_spec.rb": "87939363ba108654b5523d0138906f3b", "spec/acceptance/firewallchain_spec.rb": "ce38303451fcb6c82afe13592315f476", "spec/acceptance/invert_spec.rb": "76ca644085a0c1185a7e452eb055efc8", "spec/acceptance/ip6_fragment_spec.rb": "4f8f24c9acde189ff329f521514a473c", "spec/acceptance/isfragment_spec.rb": "3cae1de57a2bbcbdf36d985dec7356ab", "spec/acceptance/match_mark_spec.rb": "ad1a07a3176676d5498c2410e5239d00", "spec/acceptance/nodesets/centos-59-x64-pe.yml": "255100fb63e3b7c204e24dc9464ae904", "spec/acceptance/nodesets/centos-59-x64.yml": "57eb3e471b9042a8ea40978c467f8151", "spec/acceptance/nodesets/centos-64-x64-fusion.yml": "f5da18ffa623c6a13d9f48521b1bfa39", "spec/acceptance/nodesets/centos-64-x64-pe.yml": "ec075d95760df3d4702abea1ce0a829b", "spec/acceptance/nodesets/centos-64-x64.yml": "092dd2c588a9f87fa1fb12997c0723ef", "spec/acceptance/nodesets/centos-65-x64.yml": "3e5c36e6aa5a690229e720f4048bb8af", "spec/acceptance/nodesets/centos-7-x64.yml": "e7c84aff30c5c42c25817b150c30abb1", "spec/acceptance/nodesets/debian-607-x64.yml": "d566bf76f534e2af7c9a4605316d232c", "spec/acceptance/nodesets/debian-70rc1-x64.yml": "31ccca73af7b74e1cc2fb0035c230b2c", "spec/acceptance/nodesets/default.yml": "092dd2c588a9f87fa1fb12997c0723ef", "spec/acceptance/nodesets/fedora-18-x64.yml": "acc126fa764c39a3b1df36e9224a21d9", "spec/acceptance/nodesets/sles-11sp1-x64.yml": "fa0046bd89c1ab4ba9521ad79db234cd", "spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "75e86400b7889888dc0781c0ae1a1297", "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "d30d73e34cd50b043c7d14e305955269", "spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0", "spec/acceptance/params_spec.rb": "c291492b77c8ae305bf1ae0975334c2d", "spec/acceptance/purge_spec.rb": "8e39ae399e64893ee9528d91106f9356", "spec/acceptance/resource_cmd_spec.rb": "0ded877a2389f9eac355c69f77046cd2", "spec/acceptance/rules_spec.rb": "b63bead4f7977b8928668387e76aa1dd", "spec/acceptance/socket_spec.rb": "ee160ba60e3451f7a6a386e38f1f0de7", "spec/acceptance/standard_usage_spec.rb": "a02f0de040206c7415aea9e009aded6d", "spec/acceptance/unsupported_spec.rb": "5540063193905d4e8235d6042e8633fc", "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", "spec/spec_helper.rb": "f56042822899b1c60e92ce5505b00f06", "spec/spec_helper_acceptance.rb": "ec179452fea2ed0082e48a4bbcd07f91", "spec/unit/classes/firewall_linux_archlinux_spec.rb": "3f9ce56d2069fb971423b3df24de1e3a", "spec/unit/classes/firewall_linux_debian_spec.rb": "03f6a6eb35f8cc30b4932dddae9a8855", "spec/unit/classes/firewall_linux_gentoo_spec.rb": "c23c922f2e07ff25ba9de032cb182983", "spec/unit/classes/firewall_linux_redhat_spec.rb": "09982133c2b3ef91f808a8caea1659c4", "spec/unit/classes/firewall_linux_spec.rb": "5db920970b14505dab273fb06b4029c5", "spec/unit/classes/firewall_spec.rb": "60c42500e82bb37ef31a88ad82b9bdd1", "spec/unit/facter/iptables_persistent_version_spec.rb": "c1192cf6b7ffbec614b00e16d5cce0bd", "spec/unit/facter/iptables_spec.rb": "5265be1e6ec652184de8b314ae396d1a", "spec/unit/puppet/provider/ip6tables_spec.rb": "67b945e26f9e31c16fd410818649b072", "spec/unit/puppet/provider/iptables_chain_spec.rb": "8577944053cd2996357358151ef7a530", "spec/unit/puppet/provider/iptables_spec.rb": "c6db5ca0fb03331ceab59fdb05d614c6", "spec/unit/puppet/type/firewall_spec.rb": "c3116911aa894bd8140217b66cf16680", "spec/unit/puppet/type/firewallchain_spec.rb": "28ff0dd5fe0705b5993f5303ef6f7f06", "spec/unit/puppet/util/firewall_spec.rb": "f7d1e4b74561fda330a231fdf973a12e", "spec/unit/puppet/util/ipcidr_spec.rb": "1a6eeb2dd7c9634fcfb60d8ead6e1d79" }puppetlabs-firewall-1.7.1/CONTRIBUTING.md000644 000765 000024 00000017435 12567120562 017541 0ustar00tpstaff000000 000000 Checklist (and a short version for the impatient) ================================================= * Commits: - Make commits of logical units. - Check for unnecessary whitespace with "git diff --check" before committing. - Commit using Unix line endings (check the settings around "crlf" in git-config(1)). - Do not check in commented out code or unneeded files. - The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. - Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". - The body should provide a meaningful commit message, which: - uses the imperative, present tense: "change", not "changed" or "changes". - includes motivation for the change, and contrasts its implementation with the previous behavior. - Make sure that you have tests for the bug you are fixing, or feature you are adding. - Make sure the test suites passes after your commit: `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below - When introducing a new feature, make sure it is properly documented in the README.md * Submission: * Pre-requisites: - Make sure you have a [GitHub account](https://github.com/join) - [Create a ticket](https://tickets.puppetlabs.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppetlabs.com/browse/) you are patching for. * Preferred method: - Fork the repository on GitHub. - Push your changes to a topic branch in your fork of the repository. (the format ticket/1234-short_description_of_change is usually preferred for this project). - Submit a pull request to the repository in the puppetlabs organization. The long version ================ 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](http://help.github.com/send-pull-requests/). 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 GitHub issue. If there is a GitHub 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, then use it to install all dependencies needed for this project, by running ```shell % bundle install 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 ``` With all dependencies in place and up-to-date we can now run the tests: ```shell % rake spec ``` This will execute all the [rspec tests](http://rspec-puppet.com/) tests under [spec/defines](./spec/defines), [spec/classes](./spec/classes), and so on. rspec tests may have the same kind of dependencies as the module they are testing. While the module defines in its [Modulefile](./Modulefile), rspec tests define them in [.fixtures.yml](./fixtures.yml). Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker) tests. These tests spin up a virtual machine under [VirtualBox](https://www.virtualbox.org/)) with, controlling it with [Vagrant](http://www.vagrantup.com/) to actually simulate scripted test scenarios. In order to run these, you will need both of those tools installed on your system. You can run them by issuing the following command ```shell % rake spec_clean % 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 ------------- XXX getting started writing tests. If you have commit access to the repository =========================================== Even if you have commit access to the repository, you will 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 developer on the project (that did not write the code) to ensure that all changes go through a code review process. Having someone other than the author of the topic branch recorded as performing the merge is the record that they performed the code review. Additional Resources ==================== * [Getting additional help](http://puppetlabs.com/community/get-help) * [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests) * [Patchwork](https://patchwork.puppetlabs.com) * [General GitHub documentation](http://help.github.com/) * [GitHub pull request documentation](http://help.github.com/send-pull-requests/) puppetlabs-firewall-1.7.1/Gemfile000644 000765 000024 00000002477 12567120562 016603 0ustar00tpstaff000000 000000 source ENV['GEM_SOURCE'] || "https://rubygems.org" def location_for(place, fake_version = nil) if place =~ /^(git:[^#]*)#(.*)/ [fake_version, { :git => $1, :branch => $2, :require => false }].compact elsif place =~ /^file:\/\/(.*)/ ['>= 0', { :path => File.expand_path($1), :require => false }] else [place, { :require => false }] end end group :development, :unit_tests do gem 'rspec-core', '3.1.7', :require => false gem 'puppetlabs_spec_helper', :require => false gem 'simplecov', :require => false gem 'puppet_facts', :require => false gem 'json', :require => false end group :system_tests do if beaker_version = ENV['BEAKER_VERSION'] gem 'beaker', *location_for(beaker_version) end if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] gem 'beaker-rspec', *location_for(beaker_rspec_version) else gem 'beaker-rspec', :require => false end gem 'serverspec', :require => false gem 'beaker-puppet_install_helper', :require => false end if facterversion = ENV['FACTER_GEM_VERSION'] gem 'facter', facterversion, :require => false else gem 'facter', :require => false end if puppetversion = ENV['PUPPET_GEM_VERSION'] gem 'puppet', puppetversion, :require => false else gem 'puppet', :require => false end # vim:ft=ruby puppetlabs-firewall-1.7.1/lib/000755 000765 000024 00000000000 12567122052 016040 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/LICENSE000644 000765 000024 00000001651 12567120562 016306 0ustar00tpstaff000000 000000 Puppet Firewall Module - Puppet module for managing Firewalls Copyright (C) 2011-2013 Puppet Labs, Inc. Copyright (C) 2011 Jonathan Boyett Copyright (C) 2011 Media Temple, Inc. Some of the iptables code was taken from puppet-iptables which was: Copyright (C) 2011 Bob.sh Limited Copyright (C) 2008 Camptocamp Association Copyright (C) 2007 Dmitri Priimak Puppet Labs can be contacted at: info@puppetlabs.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. puppetlabs-firewall-1.7.1/manifests/000755 000765 000024 00000000000 12567122052 017263 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/metadata.json000644 000765 000024 00000003122 12567122052 017743 0ustar00tpstaff000000 000000 { "name": "puppetlabs-firewall", "version": "1.7.1", "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", "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": [ "10.04", "12.04", "14.04" ] }, { "operatingsystem": "Gentoo", "operatingsystemrelease": [ "1.0" ] } ], "requirements": [ { "name": "pe", "version_requirement": ">= 3.0.0 < 2015.3.0" }, { "name": "puppet", "version_requirement": ">= 3.0.0 < 5.0.0" } ], "dependencies": [ ] } puppetlabs-firewall-1.7.1/Rakefile000644 000765 000024 00000000766 12567120562 016754 0ustar00tpstaff000000 000000 require 'puppetlabs_spec_helper/rake_tasks' require 'puppet-lint/tasks/puppet-lint' PuppetLint.configuration.fail_on_warnings = true PuppetLint.configuration.send('relative') PuppetLint.configuration.send('disable_80chars') PuppetLint.configuration.send('disable_class_inherits_from_params_class') PuppetLint.configuration.send('disable_documentation') PuppetLint.configuration.send('disable_single_quote_string_with_variables') PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] puppetlabs-firewall-1.7.1/README.markdown000644 000765 000024 00000117155 12567120562 020011 0ustar00tpstaff000000 000000 #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 Uses 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. [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 will want to 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, } ~~~ ###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'. Default to 'running'. ####package Specify the platform-specific package(s) to install. Defaults defined in `firewall::params`. ####service Specify the platform-specific service(s) to start or stop. 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`, `log_level`, `log_prefix`, `mark`, `mask`, `mss`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `tcp_flags`. * `iptables`: Iptables type provider * Required binaries: `iptables-save`, `iptables`. * Default for `kernel` == `linux`. * Supported features: `address_type`, `clusterip`, `connection_limiting`, `dnat`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfragment`, `log_level`, `log_prefix`, `mark`, `mask`, `mss`, `netmap`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `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. * `log_level`: The ability to control the log level. * `log_prefix`: The ability to add prefixes to log messages. * `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. * `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. * `tcp_flags`: The ability to match on particular TCP flag settings. * `netmap`: The ability to map entire subnets via source or destination nat rules. #### 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'. Requires the `state_match` feature. * `date_start`: Start Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' * `date_stop`: End Date/Time for the rule to match, which must be in ISO 8601 "T" notation. The possible time range is '1970-01-01T00:00:00' to '2038-01-19T04:17:07' * `destination`: The destination address to match. For example: `destination => '192.168.1.0/24'`. You can also negate a mask by putting ! in front. For example: `destination => '! 192.168.2.0/24'`. The destination can also be an IPv6 address if your provider supports it. For some firewall providers you can pass a range of ports in the format: 'start number-end number'. For example, '1-1024' would cover ports 1 to 1024. * `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. * `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. * `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. * `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'. 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. * `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. * `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. * `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. Valid values are: * 'tcp' * 'udp' * 'icmp' * 'ipv4' * 'ipv6' * 'ipv6-icmp' * 'esp' * 'ah' * 'vrrp' * 'igmp' * 'ipencap' * 'ospf' * 'gre' * 'all' * `provider`: The specific backend to use for this firewall resource. You will seldom need to specify this --- Puppet will usually discover the appropriate provider for your platform. Available providers are ip6tables and iptables. See the [Providers](#providers) section above for details about these providers. * `random`: When using a `jump` value of 'MASQUERADE', 'DNAT', 'REDIRECT', or 'SNAT', this boolean will enable randomized port mapping. Valid values are true or false. Requires the `dnat` feature. * `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. * `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'. Requires the `state_match` 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. ###Other Bugs can be reported in JIRA: ##Development Puppet Labs 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. You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing) For this particular module, please also read CONTRIBUTING.md before contributing. Currently we support: * 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.7.1/spec/000755 000765 000024 00000000000 12567122052 016224 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/acceptance/000755 000765 000024 00000000000 12567122052 020312 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/spec.opts000644 000765 000024 00000000057 12567120562 020073 0ustar00tpstaff000000 000000 --format s --colour --loadby mtime --backtrace puppetlabs-firewall-1.7.1/spec/spec_helper.rb000644 000765 000024 00000001463 12567120562 021052 0ustar00tpstaff000000 000000 dir = File.expand_path(File.dirname(__FILE__)) $LOAD_PATH.unshift File.join(dir, 'lib') # Don't want puppet getting the command line arguments for rake or autotest ARGV.clear require 'rubygems' require 'bundler/setup' require 'rspec-puppet' Bundler.require :default, :test require 'pathname' require 'tmpdir' Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour| require behaviour.relative_path_from(Pathname.new(dir)) end fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures')) RSpec.configure do |config| config.tty = true config.mock_with :rspec do |c| c.syntax = :expect end config.module_path = File.join(fixture_path, 'modules') config.manifest_dir = File.join(fixture_path, 'manifests') config.environmentpath = File.expand_path(File.join(Dir.pwd, 'spec')) end puppetlabs-firewall-1.7.1/spec/spec_helper_acceptance.rb000644 000765 000024 00000002004 12567120562 023210 0ustar00tpstaff000000 000000 require 'beaker-rspec' require 'beaker/puppet_install_helper' def iptables_flush_all_tables ['filter', 'nat', 'mangle', 'raw'].each do |t| expect(shell("iptables -t #{t} -F").stderr).to eq("") end end def ip6tables_flush_all_tables ['filter'].each do |t| expect(shell("ip6tables -t #{t} -F").stderr).to eq("") end end def do_catch_changes if default['platform'] =~ /el-5/ return false else return true end end run_puppet_install_helper UNSUPPORTED_PLATFORMS = ['windows','Solaris','Darwin'] RSpec.configure do |c| # Project root proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) # Readable test descriptions c.formatter = :documentation # Configure all nodes in nodeset c.before :suite do # Install module and dependencies hosts.each do |host| copy_module_to(host, :source => proj_root, :module_name => 'firewall') on host, puppet('module install puppetlabs-stdlib --version 3.2.0'), { :acceptable_exit_codes => [0,1] } end end end puppetlabs-firewall-1.7.1/spec/unit/000755 000765 000024 00000000000 12567122052 017203 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/classes/000755 000765 000024 00000000000 12567122052 020640 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/facter/000755 000765 000024 00000000000 12567122052 020447 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/puppet/000755 000765 000024 00000000000 12567122052 020520 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/puppet/provider/000755 000765 000024 00000000000 12567122052 022352 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/puppet/type/000755 000765 000024 00000000000 12567122052 021501 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/puppet/util/000755 000765 000024 00000000000 12567122052 021475 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/unit/puppet/util/firewall_spec.rb000644 000765 000024 00000024424 12567120562 024653 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'Puppet::Util::Firewall' do let(:resource) { type = Puppet::Type.type(:firewall) provider = double 'provider' allow(provider).to receive(:name).and_return(:iptables) allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return(provider) type.new({:name => '000 test foo'}) } before(:each) { resource } describe '#host_to_ip' do subject { resource } specify { expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51') subject.host_to_ip('puppetlabs.com').should == '96.126.112.51/32' } specify { subject.host_to_ip('96.126.112.51').should == '96.126.112.51/32' } specify { subject.host_to_ip('96.126.112.51/32').should == '96.126.112.51/32' } specify { subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' } specify { subject.host_to_ip('2001:db8:1234::/48').should == '2001:db8:1234::/48' } specify { subject.host_to_ip('0.0.0.0/0').should == nil } specify { subject.host_to_ip('::/0').should == nil } end describe '#host_to_mask' do subject { resource } specify { expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51') subject.host_to_mask('puppetlabs.com').should == '96.126.112.51/32' subject.host_to_mask('!puppetlabs.com').should == '! 96.126.112.51/32' } specify { subject.host_to_mask('96.126.112.51').should == '96.126.112.51/32' } specify { subject.host_to_mask('!96.126.112.51').should == '! 96.126.112.51/32' } specify { subject.host_to_mask('96.126.112.51/32').should == '96.126.112.51/32' } specify { subject.host_to_mask('! 96.126.112.51/32').should == '! 96.126.112.51/32' } specify { subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' } specify { subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334').should == '! 2001:db8:85a3::8a2e:370:7334/128' } specify { subject.host_to_mask('2001:db8:1234::/48').should == '2001:db8:1234::/48' } specify { subject.host_to_mask('! 2001:db8:1234::/48').should == '! 2001:db8:1234::/48' } specify { subject.host_to_mask('0.0.0.0/0').should == nil } specify { subject.host_to_mask('!0.0.0.0/0').should == nil } specify { subject.host_to_mask('::/0').should == nil } specify { subject.host_to_mask('! ::/0').should == nil } end describe '#icmp_name_to_number' do describe 'proto unsupported' do subject { resource } %w{inet5 inet8 foo}.each do |proto| it "should reject invalid proto #{proto}" do expect { subject.icmp_name_to_number('echo-reply', proto) }. to raise_error(ArgumentError, "unsupported protocol family '#{proto}'") end end end describe 'proto IPv4' do proto = 'inet' subject { resource } specify { subject.icmp_name_to_number('echo-reply', proto).should == '0' } specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '3' } specify { subject.icmp_name_to_number('source-quench', proto).should == '4' } specify { subject.icmp_name_to_number('redirect', proto).should == '6' } specify { subject.icmp_name_to_number('echo-request', proto).should == '8' } specify { subject.icmp_name_to_number('router-advertisement', proto).should == '9' } specify { subject.icmp_name_to_number('router-solicitation', proto).should == '10' } specify { subject.icmp_name_to_number('time-exceeded', proto).should == '11' } specify { subject.icmp_name_to_number('parameter-problem', proto).should == '12' } specify { subject.icmp_name_to_number('timestamp-request', proto).should == '13' } specify { subject.icmp_name_to_number('timestamp-reply', proto).should == '14' } specify { subject.icmp_name_to_number('address-mask-request', proto).should == '17' } specify { subject.icmp_name_to_number('address-mask-reply', proto).should == '18' } end describe 'proto IPv6' do proto = 'inet6' subject { resource } specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '1' } specify { subject.icmp_name_to_number('time-exceeded', proto).should == '3' } specify { subject.icmp_name_to_number('parameter-problem', proto).should == '4' } specify { subject.icmp_name_to_number('echo-request', proto).should == '128' } specify { subject.icmp_name_to_number('echo-reply', proto).should == '129' } specify { subject.icmp_name_to_number('router-solicitation', proto).should == '133' } specify { subject.icmp_name_to_number('router-advertisement', proto).should == '134' } specify { subject.icmp_name_to_number('neighbour-solicitation', proto).should == '135' } specify { subject.icmp_name_to_number('neighbour-advertisement', proto).should == '136' } specify { subject.icmp_name_to_number('redirect', proto).should == '137' } end end describe '#string_to_port' do subject { resource } specify { subject.string_to_port('80','tcp').should == '80' } specify { subject.string_to_port(80,'tcp').should == '80' } specify { subject.string_to_port('http','tcp').should == '80' } specify { subject.string_to_port('domain','udp').should == '53' } end describe '#to_hex32' do subject { resource } specify { subject.to_hex32('0').should == '0x0' } specify { subject.to_hex32('0x32').should == '0x32' } specify { subject.to_hex32('42').should == '0x2a' } specify { subject.to_hex32('4294967295').should == '0xffffffff' } specify { subject.to_hex32('4294967296').should == nil } specify { subject.to_hex32('-1').should == nil } specify { subject.to_hex32('bananas').should == nil } end describe '#persist_iptables' do before { Facter.clear } subject { resource } describe 'when proto is IPv4' do let(:proto) { 'IPv4' } it 'should exec /sbin/service if running RHEL 6 or earlier' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6') expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}) subject.persist_iptables(proto) end it 'should exec for systemd if running RHEL 7 or greater' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7') expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save}) subject.persist_iptables(proto) end it 'should exec for systemd if running Fedora 15 or greater' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat') allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Fedora') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('15') expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save}) subject.persist_iptables(proto) end it 'should exec for CentOS 6 identified from operatingsystem and operatingsystemrelease' do allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil) allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6.5') expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}) subject.persist_iptables(proto) end it 'should exec for CentOS 7 identified from operatingsystem and operatingsystemrelease' do allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil) allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS') allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7.0.1406') expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save}) subject.persist_iptables(proto) end it 'should exec for Archlinux identified from osfamily' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('Archlinux') expect(subject).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules']) subject.persist_iptables(proto) end it 'should raise a warning when exec fails' do 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') expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}). and_raise(Puppet::ExecutionFailure, 'some error') expect(subject).to receive(:warning).with('Unable to persist firewall rules: some error') subject.persist_iptables(proto) end end describe 'when proto is IPv6' do let(:proto) { 'IPv6' } it 'should exec for newer Ubuntu' do allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil) allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu') allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.5.3ubuntu2') expect(subject).to receive(:execute).with(%w{/usr/sbin/service iptables-persistent save}) subject.persist_iptables(proto) end it 'should not exec for older Ubuntu which does not support IPv6' do allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil) allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu') allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.0.20090701') expect(subject).to receive(:execute).never subject.persist_iptables(proto) end it 'should not exec for Suse which is not supported' do allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse') expect(subject).to receive(:execute).never subject.persist_iptables(proto) end end end end puppetlabs-firewall-1.7.1/spec/unit/puppet/util/ipcidr_spec.rb000644 000765 000024 00000005074 12567120562 024320 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'Puppet::Util::IPCidr' do describe 'ipv4 address' do before { @ipaddr = Puppet::Util::IPCidr.new('96.126.112.51') } subject { @ipaddr } specify { subject.cidr.should == '96.126.112.51/32' } specify { subject.prefixlen.should == 32 } specify { subject.netmask.should == '255.255.255.255' } end describe 'single ipv4 address with cidr' do before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.51/32') } subject { @ipcidr } specify { subject.cidr.should == '96.126.112.51/32' } specify { subject.prefixlen.should == 32 } specify { subject.netmask.should == '255.255.255.255' } end describe 'ipv4 address range with cidr' do before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.0/24') } subject { @ipcidr } specify { subject.cidr.should == '96.126.112.0/24' } specify { subject.prefixlen.should == 24 } specify { subject.netmask.should == '255.255.255.0' } end describe 'ipv4 open range with cidr' do before { @ipcidr = Puppet::Util::IPCidr.new('0.0.0.0/0') } subject { @ipcidr } specify { subject.cidr.should == '0.0.0.0/0' } specify { subject.prefixlen.should == 0 } specify { subject.netmask.should == '0.0.0.0' } end describe 'ipv6 address' do before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334') } subject { @ipaddr } specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' } specify { subject.prefixlen.should == 128 } specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' } end describe 'single ipv6 addr with cidr' do before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334/128') } subject { @ipaddr } specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' } specify { subject.prefixlen.should == 128 } specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' } end describe 'ipv6 addr range with cidr' do before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:1234::/48') } subject { @ipaddr } specify { subject.cidr.should == '2001:db8:1234::/48' } specify { subject.prefixlen.should == 48 } specify { subject.netmask.should == 'ffff:ffff:ffff:0000:0000:0000:0000:0000' } end describe 'ipv6 open range with cidr' do before { @ipaddr = Puppet::Util::IPCidr.new('::/0') } subject { @ipaddr } specify { subject.cidr.should == '::/0' } specify { subject.prefixlen.should == 0 } specify { subject.netmask.should == '0000:0000:0000:0000:0000:0000:0000:0000' } end end puppetlabs-firewall-1.7.1/spec/unit/puppet/type/firewall_spec.rb000755 000765 000024 00000055216 12567120562 024665 0ustar00tpstaff000000 000000 #!/usr/bin/env rspec require 'spec_helper' firewall = Puppet::Type.type(:firewall) describe firewall do before :each do @class = firewall @provider = double 'provider' allow(@provider).to receive(:name).and_return(:iptables) allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return @provider @resource = @class.new({:name => '000 test foo'}) # 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 'should have :name be its namevar' do @class.key_attributes.should == [:name] end describe ':name' do it 'should accept a name' do @resource[:name] = '000-test-foo' @resource[:name].should == '000-test-foo' end it 'should not accept a name with non-ASCII chars' do lambda { @resource[:name] = '%*#^(#$' }.should raise_error(Puppet::Error) end end describe ':action' do it "should have no default" do res = @class.new(:name => "000 test") res.parameters[:action].should == nil end [:accept, :drop, :reject].each do |action| it "should accept value #{action}" do @resource[:action] = action @resource[:action].should == action end end it 'should fail when value is not recognized' do lambda { @resource[:action] = 'not valid' }.should 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 @resource[:chain].should == chain end end it 'should fail when the chain value is not recognized' do lambda { @resource[:chain] = 'not valid' }.should 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 @resource[:table].should == table end end it "should fail when table value is not recognized" do lambda { @resource[:table] = 'not valid' }.should raise_error(Puppet::Error) end end describe ':proto' do [:tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :all].each do |proto| it "should accept proto value #{proto}" do @resource[:proto] = proto @resource[:proto].should == proto end end it "should fail when proto value is not recognized" do lambda { @resource[:proto] = 'foo' }.should raise_error(Puppet::Error) end end describe ':jump' do it "should have no default" do res = @class.new(:name => "000 test") res.parameters[:jump].should == nil end ['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump| it "should accept jump value #{jump}" do @resource[:jump] = jump @resource[:jump].should == jump end end ['ACCEPT', 'DROP', 'REJECT'].each do |jump| it "should now fail when value #{jump}" do lambda { @resource[:jump] = jump }.should raise_error(Puppet::Error) end end it "should fail when jump value is not recognized" do lambda { @resource[:jump] = '%^&*' }.should 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' @resource[addr].should == '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 @resource[addr].should == nil end end it "should accept a negated #{addr} as a string" do @resource[addr] = '! 127.0.0.1' @resource[addr].should == '! 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' @resource[port].should == ['22'] end it "should accept a #{port} as an array" do @resource[port] = ['22','23'] @resource[port].should == ['22','23'] end it "should accept a #{port} as a number" do @resource[port] = 22 @resource[port].should == ['22'] end it "should accept a #{port} as a hyphen separated range" do @resource[port] = ['22-1000'] @resource[port].should == ['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'] @resource[port].should == ['22-1000','33','3000-4000'] end it "should convert a port name for #{port} to its number" do @resource[port] = 'ssh' @resource[port].should == ['22'] end it "should not accept something invalid for #{port}" do expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^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, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/) end end end describe 'port deprecated' do it "raises a warning" do expect(Puppet).to receive(:warning).with /port is deprecated/ @resource[:port] = "22" end end [:dst_type, :src_type].each do |addrtype| describe addrtype do it "should have no default" do res = @class.new(:name => "000 test") res.parameters[addrtype].should == 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 @resource[addrtype].should == type end end it "should fail when #{addrtype} value is not recognized" do lambda { @resource[addrtype] = 'foo' }.should 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' @resource[iface].should == 'eth1' end it "should accept a negated #{iface} value as a string" do @resource[iface] = '! eth1' @resource[iface].should == '! eth1' end it "should accept an interface alias for the #{iface} value as a string" do @resource[iface] = 'eth1:2' @resource[iface].should == '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 @resource[:log_level].should == v } it { @resource[:log_level] = 3 @resource[:log_level].should == 3 } it { lambda { @resource[:log_level] = 'foo' }.should raise_error(Puppet::Error) } 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| it 'should convert icmp string to number' do @resource[:provider] = provider @resource[:provider].should == provider @resource[:icmp] = v @resource[:icmp].should == k end end end end it 'should accept values as integers' do @resource[:icmp] = 9 @resource[:icmp].should == 9 end it 'should fail if icmp type is "any"' do lambda { @resource[:icmp] = 'any' }.should raise_error(Puppet::Error) end it 'should fail if icmp type cannot be mapped to a numeric' do lambda { @resource[:icmp] = 'foo' }.should raise_error(Puppet::Error) end end describe ':state' do it 'should accept value as a string' do @resource[:state] = :INVALID @resource[:state].should == [:INVALID] end it 'should accept value as an array' do @resource[:state] = [:INVALID, :NEW] @resource[:state].should == [:INVALID, :NEW] end it 'should sort values alphabetically' do @resource[:state] = [:NEW, :ESTABLISHED] @resource[:state].should == [:ESTABLISHED, :NEW] end end describe ':ctstate' do it 'should accept value as a string' do @resource[:ctstate] = :INVALID @resource[:ctstate].should == [:INVALID] end it 'should accept value as an array' do @resource[:ctstate] = [:INVALID, :NEW] @resource[:ctstate].should == [:INVALID, :NEW] end it 'should sort values alphabetically' do @resource[:ctstate] = [:NEW, :ESTABLISHED] @resource[:ctstate].should == [:ESTABLISHED, :NEW] end end describe ':burst' do it 'should accept numeric values' do @resource[:burst] = 12 @resource[:burst].should == 12 end it 'should fail if value is not numeric' do lambda { @resource[:burst] = 'foo' }.should raise_error(Puppet::Error) end end describe ':recent' do ['set', 'update', 'rcheck', 'remove'].each do |recent| it "should accept recent value #{recent}" do @resource[:recent] = recent @resource[:recent].should == "--#{recent}" end end end describe ':action and :jump' do it 'should allow only 1 to be set at a time' do expect { @class.new( :name => "001-test", :action => "accept", :jump => "custom_chain" ) }.to raise_error(Puppet::Error, /Only one of the parameters 'action' and 'jump' can be set$/) end end describe ':gid and :uid' do it 'should allow me to set uid' do @resource[:uid] = 'root' @resource[:uid].should == 'root' end it 'should allow me to set uid as an array, and silently hide my error' do @resource[:uid] = ['root', 'bobby'] @resource[:uid].should == 'root' end it 'should allow me to set gid' do @resource[:gid] = 'root' @resource[:gid].should == 'root' end it 'should allow me to set gid as an array, and silently hide my error' do @resource[:gid] = ['root', 'bobby'] @resource[:gid].should == 'root' end end describe ':set_mark' do ['1.3.2', '1.4.2'].each do |iptables_version| describe "with iptables #{iptables_version}" do before { 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 } if iptables_version == '1.3.2' it 'should allow me to set set-mark without mask' do @resource[:set_mark] = '0x3e8' @resource[:set_mark].should == '0x3e8' end it 'should convert int to hex without mask' do @resource[:set_mark] = '1000' @resource[:set_mark].should == '0x3e8' end it 'should fail if mask is present' do lambda { @resource[:set_mark] = '0x3e8/0xffffffff'}.should raise_error( Puppet::Error, /iptables version #{iptables_version} does not support masks on MARK rules$/ ) end end if iptables_version == '1.4.2' it 'should allow me to set set-mark with mask' do @resource[:set_mark] = '0x3e8/0xffffffff' @resource[:set_mark].should == '0x3e8/0xffffffff' end it 'should convert int to hex and add a 32 bit mask' do @resource[:set_mark] = '1000' @resource[:set_mark].should == '0x3e8/0xffffffff' end it 'should add a 32 bit mask' do @resource[:set_mark] = '0x32' @resource[:set_mark].should == '0x32/0xffffffff' end it 'should use the mask provided' do @resource[:set_mark] = '0x32/0x4' @resource[:set_mark].should == '0x32/0x4' end it 'should use the mask provided and convert int to hex' do @resource[:set_mark] = '1000/0x4' @resource[:set_mark].should == '0x3e8/0x4' end it 'should fail if mask value is more than 32 bits' do lambda { @resource[:set_mark] = '1/4294967296'}.should raise_error( Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/ ) end it 'should fail if mask is malformed' do lambda { @resource[:set_mark] = '1000/0xq4'}.should raise_error( Puppet::Error, /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 lambda { @resource[:set_mark] = bad_mark}.should raise_error(Puppet::Error) end end it 'should fail if mark value is more than 32 bits' do lambda { @resource[:set_mark] = '4294967296'}.should raise_error( Puppet::Error, /MARK value must be integer or hex between 0 and 0xffffffff$/ ) end end end end [:chain, :jump].each do |param| describe param do it 'should autorequire fwchain when table and provider are undefined' do @resource[param] = 'FOO' @resource[:table].should == :filter @resource[:provider].should == :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] rel.source.ref.should == chain.ref rel.target.ref.should == @resource.ref end it 'should autorequire fwchain when table is undefined and provider is ip6tables' do @resource[param] = 'FOO' @resource[:table].should == :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] rel.source.ref.should == chain.ref rel.target.ref.should == @resource.ref end it 'should autorequire fwchain when table is raw and provider is undefined' do @resource[param] = 'FOO' @resource[:table] = :raw @resource[:provider].should == :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] rel.source.ref.should == chain.ref rel.target.ref.should == @resource.ref end it 'should autorequire 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] rel.source.ref.should == chain.ref rel.target.ref.should == @resource.ref end # test where autorequire is still needed (table != filter) ['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 @resource[:provider].should == :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] rel.source.ref.should == chain.ref rel.target.ref.should == @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] rel.source.ref.should == chain.ref rel.target.ref.should == @resource.ref end end # test of case where autorequire should not happen ['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 @resource[:table].should == :filter @resource[:provider].should == :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] rel.should == nil end it "should not autorequire fwchain #{test_chain} when table is undefined and provider is ip6tables" do @resource[param] = test_chain @resource[:table].should == :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] rel.should == nil end end end end describe ":chain and :jump" do it 'should autorequire independent fwchains' do @resource[:chain] = 'FOO' @resource[:jump] = 'BAR' @resource[:table].should == :filter @resource[:provider].should == :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 rel[0].source.ref.should == chain_foo.ref rel[0].target.ref.should == @resource.ref rel[1].source.ref.should == chain_bar.ref rel[1].target.ref.should == @resource.ref end end describe ':pkttype' do [:multicast, :broadcast, :unicast].each do |pkttype| it "should accept pkttype value #{pkttype}" do @resource[:pkttype] = pkttype @resource[:pkttype].should == pkttype end end it 'should fail when the pkttype value is not recognized' do lambda { @resource[:pkttype] = 'not valid' }.should 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 @resource[:provider].should == 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] rel.source.ref.should == package.ref rel.target.ref.should == @resource.ref end it "provider #{provider} should autorequire packages iptables, iptables-persistent, and iptables-services" do @resource[:provider] = provider @resource[:provider].should == 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| rel.source.ref.should == package.ref rel.target.ref.should == @resource.ref end end end end it 'is suitable' do expect(@resource.suitable?).to be_truthy 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.suitable?).to be_falsey end end puppetlabs-firewall-1.7.1/spec/unit/puppet/type/firewallchain_spec.rb000755 000765 000024 00000016521 12567120562 025664 0ustar00tpstaff000000 000000 #!/usr/bin/env rspec require 'spec_helper' firewallchain = Puppet::Type.type(:firewallchain) describe firewallchain do 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) { prov = double 'provider' allow(prov).to receive(:name).and_return(:iptables_chain) prov } let(:resource) { allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider klass.new({:name => 'INPUT:filter:IPv4', :policy => :accept }) } it 'should have :name be its namevar' do klass.key_attributes.should == [:name] end describe ':name' do {'nat' => ['PREROUTING', 'POSTROUTING', 'INPUT', 'OUTPUT'], 'mangle' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ], 'filter' => ['INPUT','OUTPUT','FORWARD'], 'raw' => [ 'PREROUTING', 'OUTPUT'], 'broute' => ['BROUTING'] }.each_pair do |table, allowedinternalchains| ['IPv4', 'IPv6', 'ethernet'].each do |protocol| [ 'test', '$5()*&%\'"^$09):' ].each do |chainname| name = "#{chainname}:#{table}:#{protocol}" if table == 'nat' && protocol == 'IPv6' it "should fail #{name}" do expect { resource[:name] = name }.to raise_error(Puppet::Error) end elsif protocol != 'ethernet' && table == 'broute' it "should fail #{name}" do expect { resource[:name] = name }.to raise_error(Puppet::Error) end else it "should accept name #{name}" do resource[:name] = name resource[:name].should == name end end end # chainname end # protocol [ 'PREROUTING', 'POSTROUTING', 'BROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ].each do |internalchain| name = internalchain + ':' + table + ':' if internalchain == 'BROUTING' name += 'ethernet' elsif table == 'nat' name += 'IPv4' else name += 'IPv4' end if allowedinternalchains.include? internalchain it "should allow #{name}" do resource[:name] = name resource[:name].should == name end else it "should fail #{name}" do expect { resource[:name] = name }.to raise_error(Puppet::Error) end end end # internalchain end # table, allowedinternalchainnames it 'should fail with invalid table names' do expect { resource[:name] = 'wrongtablename:test:IPv4' }.to raise_error(Puppet::Error) end it 'should fail 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 resource[:policy].should == policy end end it 'should fail 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(Puppet::Error) 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 resource[:provider].should == :iptables_chain package = Puppet::Type.type(:package).new(:name => 'iptables') catalog = Puppet::Resource::Catalog.new catalog.add_resource resource catalog.add_resource package rel = resource.autorequire[0] rel.source.ref.should == package.ref rel.target.ref.should == resource.ref end it "provider iptables_chain should autorequire packages iptables, iptables-persistent, and iptables-services" do resource[:provider].should == :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| rel.source.ref.should == package.ref rel.target.ref.should == resource.ref end end end describe 'purge iptables rules' do before(:each) do stub_return = < 'INPUT:filter:IPv4', :purge => true) expect(resource.generate.size).to eq(3) end it 'should not generate ignored iptables rules' do allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return("1.4.21") resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true, :ignore => ['-j fail2ban-ssh']) expect(resource.generate.size).to eq(2) end it 'should not generate iptables resources when not enabled' do resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4') expect(resource.generate.size).to eq(0) end end it 'is suitable' do expect(resource.suitable?).to be_truthy 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 = firewallchain.new(:name => "INPUT:filter:IPv4", :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.suitable?).to be_falsey end end puppetlabs-firewall-1.7.1/spec/unit/puppet/provider/ip6tables_spec.rb000644 000765 000024 00000003715 12567120562 025614 0ustar00tpstaff000000 000000 #!/usr/bin/env rspec require 'spec_helper' if Puppet.version < '3.4.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 'iptables 1.3' do let(:params) { {:name => '000 test foo', :action => 'accept'} } let(:error_message) { /The ip6tables provider is not supported on version 1\.3 of iptables/ } let(:ip6tables_version) { '1.3.10' } it_should_behave_like 'raise error' end context 'ip6tables nil' do let(:params) { {:name => '000 test foo', :action => 'accept'} } let(:error_message) { /The ip6tables provider is not supported on version 1\.3 of iptables/ } let(:ip6tables_version) { nil } it_should_behave_like 'run' end end puppetlabs-firewall-1.7.1/spec/unit/puppet/provider/iptables_chain_spec.rb000755 000765 000024 00000015263 12567120562 026674 0ustar00tpstaff000000 000000 #!/usr/bin/env rspec require 'spec_helper' if Puppet.version < '3.4.0' require 'puppet/provider/confine/exists' else require 'puppet/confine/exists' end describe 'iptables chain provider detection' do if Puppet.version < '3.4.0' let(:exists) { Puppet::Provider::Confine::Exists } else let(:exists) { Puppet::Confine::Exists } 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') end it "should default to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists" do # 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 !~ /(eb|ip|ip6)tables(-save)?$/ }.and_return false # 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) { Puppet::Type.type(:firewallchain).new({ :name => ':test:', }) } 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" end it 'should be able to get a list of existing rules' do # 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("") 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', ':$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', ':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 'should have all in parsed resources' do provider.instances.each do |resource| @all.include?(resource.name) end end end puppetlabs-firewall-1.7.1/spec/unit/puppet/provider/iptables_spec.rb000644 000765 000024 00000043122 12567120562 025522 0ustar00tpstaff000000 000000 #!/usr/bin/env rspec require 'spec_helper' if Puppet.version < '3.4.0' require 'puppet/provider/confine/exists' else require 'puppet/confine/exists' end describe 'iptables provider detection' do if Puppet.version < '3.4.0' let(:exists) { Puppet::Provider::Confine::Exists } else let(:exists) { Puppet::Confine::Exists } 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 "should default to iptables provider if /sbin/iptables[-save] exists" do # Stub lookup for /sbin/iptables & /sbin/iptables-save allow(exists).to receive(:which).with("iptables"). and_return "/sbin/iptables" allow(exists).to receive(:which).with("iptables-save"). and_return "/sbin/iptables-save" # Every other command should return false so we don't pick up any # 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) { Puppet::Type.type(:firewall).new({ :name => '000 test foo', :action => 'accept', }) } 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 'should be able to get a list of existing rules' do provider.instances.each do |rule| expect(rule).to be_instance_of(provider) expect(rule.properties[:provider].to_s).to eq(provider.name.to_s) end end it 'should ignore lines with fatal errors' do 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) { [ '-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' ] } let(:resources) do iptables_save_output.each_with_index.collect { |l,index| provider.rule_to_hash(l, 'filter', index) } end let(:providers) do resources.collect { |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) { [ '-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', ] } 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) { [ '-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', ] } 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 parameters exactly match if data[:compare_all] then 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.to_s}' should match #{param_value.inspect}" do # booleans get cludged to string "true" if param_value == true then 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) { '-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' } 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 it 'parsed the rule arguments correctly' do expect(resource[:chain]).to eq('INPUT') expect(resource[:source]).to eq('1.1.1.1/32') expect(resource[:destination]).to eq('1.1.1.1/32') expect(resource[:proto]).to eq('tcp') expect(resource[:dport]).to eq(['7061', '7062']) expect(resource[:sport]).to eq(['7061', '7062']) expect(resource[:action]).to eq('accept') end end describe 'when converting existing rules generates by system-config-firewall-tui to resources' do let(:sample_rule) { # 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' } 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 it 'parse arguments' do expect(resource[:chain]).to eq('INPUT') expect(resource[:proto]).to eq('tcp') expect(resource[:dport]).to eq(['22']) expect(resource[:state]).to eq(['NEW']) expect(resource[:action]).to eq('accept') 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(/is not supported/) end end describe 'when inverting rules' do let(:resource) { 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', }) } let(:instance) { provider.new(resource) } it 'fails when not all array items are inverted' do expect { instance.insert }.to raise_error Puppet::Error, /but '79', '80' are not prefixed/ end end describe 'when deleting resources' do let(:sample_rule) { '-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' } 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(/\-A/, '-t filter -D')) end end end describe 'ip6tables provider' do let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) } let(:resource) { Puppet::Type.type(:firewall).new({ :name => '000 test foo', :action => 'accept', :provider => "ip6tables", }) } 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 'should be able to get a list of existing rules' do provider6.instances.each do |rule| rule.should be_instance_of(provider6) rule.properties[:provider6].to_s.should == provider6.name.to_s end end it 'should ignore lines with fatal errors' do allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/ip6tables-save']). and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory") provider6.instances.length.should == 0 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] then it "the parameter hash keys should be the same as returned by rules_to_hash" do resource.keys.should =~ data[:params].keys end end # Iterate across each parameter, creating an example for comparison data[:params].each do |param_name, param_value| it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do resource[param_name].should == data[:params][param_name] 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 instance.general_args.flatten.should == data[:args] end end end end end puppetlabs-firewall-1.7.1/spec/unit/facter/iptables_persistent_version_spec.rb000644 000765 000024 00000006061 12567120562 027645 0ustar00tpstaff000000 000000 require 'spec_helper' describe "Facter::Util::Fact iptables_persistent_version" do context "iptables-persistent applicable" do before { 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 { 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) } it { Facter.fact(:iptables_persistent_version).value.should == ver } end end describe 'Ubuntu package not installed' do before { 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) } it { Facter.fact(:iptables_persistent_version).value.should be_nil } end describe 'CentOS not supported' do before { allow(Facter.fact(:operatingsystem)).to receive(:value). and_return("CentOS") } it { Facter.fact(:iptables_persistent_version).value.should be_nil } end end context "netfilter-persistent applicable" do before { 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 { 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) } it { Facter.fact(:iptables_persistent_version).value.should == ver } end end describe 'Ubuntu package not installed' do os_release = "14.10" before { 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) } it { Facter.fact(:iptables_persistent_version).value.should be_nil } end describe 'CentOS not supported' do before { allow(Facter.fact(:operatingsystem)).to receive(:value). and_return("CentOS") } it { Facter.fact(:iptables_persistent_version).value.should be_nil } end end end puppetlabs-firewall-1.7.1/spec/unit/facter/iptables_spec.rb000644 000765 000024 00000001321 12567120562 023612 0ustar00tpstaff000000 000000 require 'spec_helper' describe "Facter::Util::Fact" do before { Facter.clear allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') allow(Facter.fact(:kernelrelease)).to receive(:value).and_return('2.6') } describe 'iptables_version' do it { allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version'). and_return('iptables v1.4.7') Facter.fact(:iptables_version).value.should == '1.4.7' } end describe 'ip6tables_version' do before { allow(Facter::Util::Resolution).to receive(:exec). with('ip6tables --version').and_return('ip6tables v1.4.7') } it { Facter.fact(:ip6tables_version).value.should == '1.4.7' } end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_linux_archlinux_spec.rb000644 000765 000024 00000001622 12567120562 027305 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall::linux::archlinux', :type => :class do let(:facts) do { :osfamily => 'Archlinux', :operatingsystem => 'Archlinux' } end it { should contain_service('iptables').with( :ensure => 'running', :enable => 'true' )} it { should contain_service('ip6tables').with( :ensure => 'running', :enable => 'true' )} context 'ensure => stopped' do let(:params) {{ :ensure => 'stopped' }} it { should contain_service('iptables').with( :ensure => 'stopped' )} it { should contain_service('ip6tables').with( :ensure => 'stopped' )} end context 'enable => false' do let(:params) {{ :enable => 'false' }} it { should contain_service('iptables').with( :enable => 'false' )} it { should contain_service('ip6tables').with( :enable => 'false' )} end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_linux_debian_spec.rb000644 000765 000024 00000004705 12567120562 026537 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall::linux::debian', :type => :class do context "Debian 7" do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '7.0' }} it { should contain_package('iptables-persistent').with( :ensure => 'present' )} it { should contain_service('iptables-persistent').with( :ensure => nil, :enable => 'true', :require => 'Package[iptables-persistent]' )} end context 'deb7 enable => false' do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '7.0' }} let(:params) {{ :enable => 'false' }} it { should contain_service('iptables-persistent').with( :enable => 'false' )} end context "Debian 8" do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => 'jessie/sid' }} it { should contain_package('iptables-persistent').with( :ensure => 'present' )} it { should contain_service('netfilter-persistent').with( :ensure => nil, :enable => 'true', :require => 'Package[iptables-persistent]' )} end context 'deb8 enable => false' do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => 'jessie/sid' }} let(:params) {{ :enable => 'false' }} it { should contain_service('netfilter-persistent').with( :enable => 'false' )} end context "Debian 8, alt operatingsystem" do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '8.0' }} it { should contain_package('iptables-persistent').with( :ensure => 'present' )} it { should contain_service('netfilter-persistent').with( :ensure => nil, :enable => 'true', :require => 'Package[iptables-persistent]' )} end context 'deb8, alt operatingsystem, enable => false' do let(:facts) {{ :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '8.0' }} let(:params) {{ :enable => 'false' }} it { should contain_service('netfilter-persistent').with( :enable => 'false' )} end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_linux_gentoo_spec.rb000644 000765 000024 00000001744 12567120562 026610 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall::linux::gentoo', :type => :class do let(:facts) do { :osfamily => 'Gentoo', :operatingsystem => 'Gentoo' } end it { should contain_service('iptables').with( :ensure => 'running', :enable => 'true' )} it { should contain_service('ip6tables').with( :ensure => 'running', :enable => 'true' )} it { should contain_package('net-firewall/iptables').with( :ensure => 'present' )} context 'ensure => stopped' do let(:params) {{ :ensure => 'stopped' }} it { should contain_service('iptables').with( :ensure => 'stopped' )} it { should contain_service('ip6tables').with( :ensure => 'stopped' )} end context 'enable => false' do let(:params) {{ :enable => 'false' }} it { should contain_service('iptables').with( :enable => 'false' )} it { should contain_service('ip6tables').with( :enable => 'false' )} end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_linux_redhat_spec.rb000644 000765 000024 00000003401 12567120562 026554 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall::linux::redhat', :type => :class do %w{RedHat CentOS Fedora}.each do |os| oldreleases = (os == 'Fedora' ? ['14'] : ['6.5']) newreleases = (os == 'Fedora' ? ['15','Rawhide'] : ['7.0.1406']) oldreleases.each do |osrel| context "os #{os} and osrel #{osrel}" do let(:facts) {{ :osfamily => 'RedHat', :operatingsystem => os, :operatingsystemrelease => osrel }} it { should_not contain_service('firewalld') } it { should_not contain_package('iptables-services') } end end newreleases.each do |osrel| context "os #{os} and osrel #{osrel}" do let(:facts) {{ :osfamily => 'RedHat', :operatingsystem => os, :operatingsystemrelease => osrel }} it { should contain_service('firewalld').with( :ensure => 'stopped', :enable => false, :before => 'Package[iptables-services]' )} it { should contain_package('iptables-services').with( :ensure => 'present', :before => 'Service[iptables]' )} end end describe 'ensure' do context 'default' do it { should contain_service('iptables').with( :ensure => 'running', :enable => 'true' )} end context 'ensure => stopped' do let(:params) {{ :ensure => 'stopped' }} it { should contain_service('iptables').with( :ensure => 'stopped' )} end context 'enable => false' do let(:params) {{ :enable => 'false' }} it { should contain_service('iptables').with( :enable => 'false' )} end end end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_linux_spec.rb000644 000765 000024 00000002323 12567120562 025227 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall::linux', :type => :class do let(:facts_default) {{ :kernel => 'Linux' }} it { should contain_package('iptables').with_ensure('present') } context 'RedHat like' do %w{RedHat CentOS Fedora}.each do |os| context "operatingsystem => #{os}" do releases = (os == 'Fedora' ? ['14','15','Rawhide'] : ['6','7']) releases.each do |osrel| context "operatingsystemrelease => #{osrel}" do let(:facts) { facts_default.merge({ :operatingsystem => os, :operatingsystemrelease => osrel}) } it { should contain_class('firewall::linux::redhat').with_require('Package[iptables]') } end end end end end context 'Debian like' do %w{Debian Ubuntu}.each do |os| context "operatingsystem => #{os}" do releases = (os == 'Debian' ? ['6','7','8'] : ['10.04','12.04','14.04']) releases.each do |osrel| let(:facts) { facts_default.merge({ :operatingsystem => os, :operatingsystemrelease => osrel}) } it { should contain_class('firewall::linux::debian').with_require('Package[iptables]') } end end end end end puppetlabs-firewall-1.7.1/spec/unit/classes/firewall_spec.rb000644 000765 000024 00000002174 12567120562 024014 0ustar00tpstaff000000 000000 require 'spec_helper' describe 'firewall', :type => :class do context 'kernel => Linux' do let(:facts) {{ :kernel => 'Linux' }} it { should contain_class('firewall::linux').with_ensure('running') } end context 'kernel => Windows' do let(:facts) {{ :kernel => 'Windows' }} it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'kernel => SunOS' do let(:facts) {{ :kernel => 'SunOS' }} it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'kernel => Darwin' do let(:facts) {{ :kernel => 'Darwin' }} it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end context 'ensure => stopped' do let(:facts) {{ :kernel => 'Linux' }} let(:params) {{ :ensure => 'stopped' }} it { should contain_class('firewall::linux').with_ensure('stopped') } end context 'ensure => test' do let(:facts) {{ :kernel => 'Linux' }} let(:params) {{ :ensure => 'test' }} it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) } end end puppetlabs-firewall-1.7.1/spec/acceptance/change_source_spec.rb000644 000765 000024 00000005404 12567120562 024465 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end end describe 'when unmanaged rules exist' do it 'applies with 8.0.0.1 first' do pp = <<-EOS 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', } EOS apply_manifest(pp, :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(/-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(/-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 shell('iptables-save') do |r| expect(r.stdout).to match(/-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 'changes to 8.0.0.4 second' do pp = <<-EOS class { '::firewall': } firewall { '101 test source changes': proto => tcp, port => '101', action => accept, source => '8.0.0.4', } EOS expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/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).to_not match(/8\.0\.0\.1/) end end it 'contains the staic 8.0.0.2 rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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(/-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.7.1/spec/acceptance/class_spec.rb000644 000765 000024 00000001734 12567120562 022767 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe "firewall class:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do it 'should run 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.7.1/spec/acceptance/connlimit_spec.rb000644 000765 000024 00000004234 12567120562 023654 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all iptables rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end it 'deletes all ip6tables rules' do shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end end if default['platform'] !~ /sles-10/ describe 'connlimit_above' do context '10' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '500 - test': proto => tcp, dport => '2222', connlimit_above => '10', action => reject, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| #connlimit-saddr is added in Ubuntu 14.04. expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 2222 -m comment --comment "500 - test" -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/) end end end end describe 'connlimit_mask' do context '24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '501 - test': proto => tcp, dport => '2222', connlimit_above => '10', connlimit_mask => '24', action => reject, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| #connlimit-saddr is added in Ubuntu 14.04. expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 2222 -m comment --comment "501 - test" -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/connmark_spec.rb000644 000765 000024 00000001322 12567120562 023463 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'connmark' do context '50' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '502 - test': proto => 'all', connmark => '0x1', action => reject, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -m comment --comment "502 - test" -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable/) end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_bridging_spec.rb000644 000765 000024 00000030660 12567120562 025334 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all iptables rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end it 'deletes all ip6tables rules' do shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end end describe 'iptables physdev tests' do context 'physdev_in eth0' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '701 - test': chain => 'FORWARD', proto => tcp, port => '701', action => accept, physdev_in => 'eth0', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 -m multiport --ports 701 -m comment --comment "701 - test" -j ACCEPT/) end end end context 'physdev_out eth1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '702 - test': chain => 'FORWARD', proto => tcp, port => '702', action => accept, physdev_out => 'eth1', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 -m multiport --ports 702 -m comment --comment "702 - test" -j ACCEPT/) end end end context 'physdev_in eth0 and physdev_out eth1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '703 - test': chain => 'FORWARD', proto => tcp, port => '703', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '704 - test': chain => 'FORWARD', proto => tcp, port => '704', action => accept, physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT/) end end end context 'physdev_in eth0 and physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '705 - test': chain => 'FORWARD', proto => tcp, port => '705', action => accept, physdev_in => 'eth0', physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_out eth1 and physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '706 - test': chain => 'FORWARD', proto => tcp, port => '706', action => accept, physdev_out => 'eth1', physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '707 - test': chain => 'FORWARD', proto => tcp, port => '707', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A 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'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'ip6tables physdev tests' do context 'physdev_in eth0' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '701 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '701', action => accept, physdev_in => 'eth0', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-in eth0 -m multiport --ports 701 -m comment --comment "701 - test" -j ACCEPT/) end end end context 'physdev_out eth1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '702 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '702', action => accept, physdev_out => 'eth1', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-out eth1 -m multiport --ports 702 -m comment --comment "702 - test" -j ACCEPT/) end end end context 'physdev_in eth0 and physdev_out eth1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '703 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '703', action => accept, physdev_in => 'eth0', physdev_out => 'eth1', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '704 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '704', action => accept, physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m physdev\s+--physdev-is-bridged -m multiport --ports 704 -m comment --comment "704 - test" -j ACCEPT/) end end end context 'physdev_in eth0 and physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '705 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '705', action => accept, physdev_in => 'eth0', physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_out eth1 and physdev_is_bridged' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '706 - test': provider => 'ip6tables', chain => 'FORWARD', proto => tcp, port => '706', action => accept, physdev_out => 'eth1', physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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 'physdev_in eth0 and physdev_out eth1 and physdev_is_bridged' do it 'applies' do pp = <<-EOS 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, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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 end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_clusterip_spec.rb000644 000765 000024 00000003442 12567120562 025557 0ustar00tpstaff000000 000000 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/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_dscp_spec.rb000644 000765 000024 00000007043 12567120562 024477 0ustar00tpstaff000000 000000 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 describe 'dscp ipv4 tests' do context 'set_dscp 0x01' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '1000 - set_dscp': proto => 'tcp', jump => 'DSCP', set_dscp => '0x01', port => '997', chain => 'OUTPUT', table => 'mangle', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1000 - set_dscp" -j DSCP --set-dscp 0x01/) end end end context 'set_dscp_class EF' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '1001 EF - set_dscp_class': proto => 'tcp', jump => 'DSCP', port => '997', set_dscp_class => 'EF', chain => 'OUTPUT', table => 'mangle', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'dscp ipv6 tests' do context 'set_dscp 0x01' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '1002 - set_dscp': proto => 'tcp', jump => 'DSCP', set_dscp => '0x01', port => '997', chain => 'OUTPUT', table => 'mangle', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --ports 997 -m comment --comment "1002 - set_dscp" -j DSCP --set-dscp 0x01/) end end end context 'set_dscp_class EF' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '1003 EF - set_dscp_class': proto => 'tcp', jump => 'DSCP', port => '997', set_dscp_class => 'EF', chain => 'OUTPUT', table => 'mangle', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-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.7.1/spec/acceptance/firewall_iptmodules_spec.rb000644 000765 000024 00000021471 12567120562 025734 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all iptables rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end it 'deletes all ip6tables rules' do shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end end describe 'iptables ipt_modules tests' do context 'all the modules with multiple args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', uid => 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, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -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/) end end end context 'all the modules with single args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', gid => 404, dst_range => "100.0.0.1-100.0.0.2", dst_type => 'UNICAST', physdev_out => "eth1", physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 100.0.0.1-100.0.0.2 -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp-port-unreachable/) end end end end #iptables version 1.3.5 is not suppored by the ip6tables provider if default['platform'] =~ /debian-7/ or default['platform'] =~ /ubuntu-14\.04/ describe 'ip6tables ipt_modules tests' do context 'all the modules with multiple args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', uid => 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, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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/) end end end context 'all the modules with single args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', gid => 404, dst_range => "2003::-2004::", dst_type => 'UNICAST', physdev_out => "eth1", physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m addrtype --dst-type UNICAST -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/) end end end end # Older OSes don't have addrtype so we leave those properties out. # el-5 doesn't support ipv6 by default elsif default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'ip6tables ipt_modules tests' do context 'all the modules with multiple args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '801 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', uid => 0, gid => 404, src_range => "2001::-2002::", dst_range => "2003::-2004::", physdev_in => "eth0", physdev_out => "eth1", physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A 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/) end end end context 'all the modules with single args' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '802 - ipt_modules tests': proto => tcp, dport => '8080', action => reject, chain => 'OUTPUT', provider => 'ip6tables', gid => 404, dst_range => "2003::-2004::", physdev_out => "eth1", physdev_is_bridged => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m physdev\s+--physdev-out eth1 --physdev-is-bridged -m iprange --dst-range 2003::-2004:: -m owner --gid-owner 404 -m multiport --dports 8080 -m comment --comment "802 - ipt_modules tests" -j REJECT --reject-with icmp6-port-unreachable/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_mss_spec.rb000644 000765 000024 00000007252 12567120562 024352 0ustar00tpstaff000000 000000 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 describe 'mss ipv4 tests' do context '1360' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "502 - set_mss" -m tcpmss --mss 1361:1541 -j TCPMSS --set-mss 1360/) end end end context 'clamp_mss_to_pmtu' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '503 - clamp_mss_to_pmtu': proto => 'tcp', chain => 'FORWARD', tcp_flags => 'SYN,RST SYN', jump => 'TCPMSS', clamp_mss_to_pmtu => true, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'mss ipv6 tests' do context '1360' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "502 - set_mss" -m tcpmss --mss 1361:1541 -j TCPMSS --set-mss 1360/) end end end context 'clamp_mss_to_pmtu' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-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.7.1/spec/acceptance/firewall_spec.rb000644 000765 000024 00000210706 12567120562 023470 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end end describe 'name' do context 'valid' do it 'applies cleanly' do pp = <<-EOS class { '::firewall': } firewall { '001 - test': ensure => present } EOS apply_manifest(pp, :catch_failures => true) end end context 'invalid' do it 'fails' do pp = <<-EOS class { '::firewall': } firewall { 'test': ensure => present } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "test"./) end end end end describe 'ensure' do context 'default' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '555 - test': proto => tcp, port => '555', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/) end end end context 'present' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '555 - test': ensure => present, proto => tcp, port => '555', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/) end end end context 'absent' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '555 - test': ensure => absent, proto => tcp, port => '555', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/) end end end end describe 'source' do context '192.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '192.168.2.0/24', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -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 '! 192.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '! 192.168.2.0/24', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT (! -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 '256.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '556 - test': proto => tcp, port => '556', action => accept, source => '256.168.2.0/24', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 '192.168.1.1-192.168.1.10' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '557 - test': proto => tcp, port => '557', action => accept, src_range => '192.168.1.1-192.168.1.10', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m 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 '392.168.1.1-192.168.1.10' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '557 - test': proto => tcp, port => '557', action => accept, src_range => '392.168.1.1-192.168.1.10', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid IP address "392.168.1.1" in range "392.168.1.1-192.168.1.10"/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 '192.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '192.168.2.0/24', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -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 '! 192.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '! 192.168.2.0/24', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT (! -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 '256.168.2.0/24' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '558 - test': proto => tcp, port => '558', action => accept, destination => '256.168.2.0/24', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 '192.168.1.1-192.168.1.10' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '559 - test': proto => tcp, port => '559', action => accept, dst_range => '192.168.1.1-192.168.1.10', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m 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 '392.168.1.1-192.168.1.10' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '559 - test': proto => tcp, port => '559', action => accept, dst_range => '392.168.1.1-192.168.1.10', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid IP address "392.168.1.1" in range "392.168.1.1-192.168.1.10"/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 'single port' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '560', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --sports 560 -m comment --comment "560 - test" -j ACCEPT/) end end end context 'multiple ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '560-561', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --sports 560:561 -m comment --comment "560 - test" -j ACCEPT/) end end end context 'invalid ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '560 - test': proto => tcp, sport => '9999560-561', action => accept, } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/invalid port\/service `9999560' specified/) end end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --sports 9999560-561 -m comment --comment "560 - test" -j ACCEPT/) end end end end describe 'dport' do context 'single port' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '561', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 561 -m comment --comment "561 - test" -j ACCEPT/) end end end context 'multiple ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '561-562', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 561:562 -m comment --comment "561 - test" -j ACCEPT/) end end end context 'invalid ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '561 - test': proto => tcp, dport => '9999561-562', action => accept, } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/invalid port\/service `9999561' specified/) end end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --dports 9999561-562 -m comment --comment "560 - test" -j ACCEPT/) end end end end describe 'port' do context 'single port' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '562 - test': proto => tcp, port => '562', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 562 -m comment --comment "562 - test" -j ACCEPT/) end end end context 'multiple ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '562 - test': proto => tcp, port => '562-563', action => accept, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 562:563 -m comment --comment "562 - test" -j ACCEPT/) end end end context 'invalid ports' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '562 - test': proto => tcp, port => '9999562-563', action => accept, } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/invalid port\/service `9999562' specified/) end end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 9999562-563 -m comment --comment "562 - test" -j ACCEPT/) end end end end ['dst_type', 'src_type'].each do |type| describe "#{type}" do context 'MULTICAST' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '563 - test': proto => tcp, action => accept, #{type} => 'MULTICAST', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m addrtype\s.*\sMULTICAST -m comment --comment "563 - test" -j ACCEPT/) end end end context '! MULTICAST' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '563 - test inversion': proto => tcp, action => accept, #{type} => '! MULTICAST', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m addrtype( !\s.*\sMULTICAST|\s.*\s! MULTICAST) -m comment --comment "563 - test inversion" -j ACCEPT/) end end end context 'BROKEN' do it 'fails' do pp = <<-EOS class { '::firewall': } firewall { '563 - test': proto => tcp, action => accept, #{type} => 'BROKEN', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "BROKEN"./) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 'FIN,SYN ACK' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '564 - test': proto => tcp, action => accept, tcp_flags => 'FIN,SYN ACK', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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 'INPUT' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '565 - test': proto => tcp, action => accept, chain => 'FORWARD', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m comment --comment "565 - test" -j ACCEPT/) end end end end describe 'table' do context 'mangle' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '566 - test': proto => tcp, action => accept, table => 'mangle', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "566 - test" -j ACCEPT/) end end end context 'nat' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '566 - test2': proto => tcp, action => accept, table => 'nat', chain => 'OUTPUT', } EOS apply_manifest(pp, :catch_failures => true) end it 'should not contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-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 expect(shell('iptables -t filter -X TEST').stderr).to eq("") end context 'MARK' do it 'applies' do pp = <<-EOS class { '::firewall': } firewallchain { 'TEST:filter:IPv4': ensure => present, } firewall { '567 - test': proto => tcp, chain => 'INPUT', jump => 'TEST', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "567 - test" -j TEST/) end end end context 'jump and apply' do it 'applies' do pp = <<-EOS class { '::firewall': } firewallchain { 'TEST:filter:IPv4': ensure => present, } firewall { '568 - test': proto => tcp, chain => 'INPUT', action => 'accept', jump => 'TEST', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Only one of the parameters 'action' and 'jump' can be set/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m comment --comment "568 - test" -j TEST/) end end end end describe 'tosource' do context '192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '568 - test': proto => tcp, table => 'nat', chain => 'POSTROUTING', jump => 'SNAT', tosource => '192.168.1.1', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/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 '192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'PREROUTING', jump => 'DNAT', source => '200.200.200.200', todest => '192.168.1.1', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-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 '192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '570 - test': proto => icmp, table => 'nat', chain => 'PREROUTING', jump => 'REDIRECT', toports => '2222', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-A PREROUTING -p icmp -m comment --comment "570 - test" -j REDIRECT --to-ports 2222/) end end end end if default['platform'] !~ /el-5/ and default['platform'] !~ /ubuntu-10\.04/ and default['platform'] !~ /debian-6/ and default['platform'] !~ /sles/ describe 'checksum_fill' do context 'virbr' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '576 - test': proto => udp, table => 'mangle', outiface => 'virbr0', chain => 'POSTROUTING', dport => '68', jump => 'CHECKSUM', checksum_fill => true, provider => iptables, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-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 'virbr' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '576 - test': proto => udp, table => 'mangle', outiface => 'virbr0', chain => 'POSTROUTING', dport => '68', jump => 'CHECKSUM', checksum_fill => true, provider => ip6tables, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'random' do context '192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '570 - test 2': proto => all, table => 'nat', chain => 'POSTROUTING', jump => 'MASQUERADE', source => '172.30.0.0/16', random => true } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-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 'any' do it 'fails' do pp = <<-EOS class { '::firewall': } firewall { '571 - test': proto => icmp, icmp => 'any', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/This behaviour should be achieved by omitting or undefining the ICMP parameter/) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 if default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'hop_limit' do context '5' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, hop_limit => '5', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 571 -m comment --comment "571 - test" -m hl --hl-eq 5 -j ACCEPT/) end end end context 'invalid' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, hop_limit => 'invalid', provider => 'ip6tables', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "invalid"./) end end it 'should not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to_not match(/-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 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '587 - test': ensure => present, proto => tcp, port => '587', action => accept, ishasmorefrags => true, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/A INPUT -p tcp -m frag --fragid 0 --fragmore -m multiport --ports 587 -m comment --comment "587 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '588 - test': ensure => present, proto => tcp, port => '588', action => accept, ishasmorefrags => false, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 588 -m comment --comment "588 - test" -j ACCEPT/) end end end end describe 'islastfrag' do context 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '589 - test': ensure => present, proto => tcp, port => '589', action => accept, islastfrag => true, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m frag --fragid 0 --fraglast -m multiport --ports 589 -m comment --comment "589 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '590 - test': ensure => present, proto => tcp, port => '590', action => accept, islastfrag => false, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 590 -m comment --comment "590 - test" -j ACCEPT/) end end end end describe 'isfirstfrag' do context 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '591 - test': ensure => present, proto => tcp, port => '591', action => accept, isfirstfrag => true, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m frag --fragid 0 --fragfirst -m multiport --ports 591 -m comment --comment "591 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '592 - test': ensure => present, proto => tcp, port => '592', action => accept, isfirstfrag => false, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 592 -m comment --comment "592 - test" -j ACCEPT/) end end end end describe 'tcp_flags' do context 'FIN,SYN ACK' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '593 - test': proto => tcp, action => accept, tcp_flags => 'FIN,SYN ACK', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-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 '2001:db8::1-2001:db8::ff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '601 - test': proto => tcp, port => '601', action => accept, src_range => '2001:db8::1-2001:db8::ff', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m 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 '2001::db8::1-2001:db8::ff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '601 - test': proto => tcp, port => '601', action => accept, provider => 'ip6tables', src_range => '2001::db8::1-2001:db8::ff', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid IP address "2001::db8::1" in range "2001::db8::1-2001:db8::ff"/) end end it 'should not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to_not match(/-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 '2001:db8::1-2001:db8::ff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '602 - test': proto => tcp, port => '602', action => accept, dst_range => '2001:db8::1-2001:db8::ff', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m 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 '2001::db8::1-2001:db8::ff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '602 - test': proto => tcp, port => '602', action => accept, provider => 'ip6tables', dst_range => '2001::db8::1-2001:db8::ff', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid IP address "2001::db8::1" in range "2001::db8::1-2001:db8::ff"/) end end it 'should not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to_not match(/-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 '0A:1B:3C:4D:5E:6F' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '604 - test': ensure => present, source => '2001:db8::1/128', mac_source => '0A:1B:3C:4D:5E:6F', chain => 'INPUT', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /ubuntu-10\.04/ and default['platform'] !~ /debian-6/ and default['platform'] !~ /sles/ describe 'socket' do context 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '605 - test': ensure => present, proto => tcp, port => '605', action => accept, chain => 'INPUT', socket => true, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 605 -m socket -m comment --comment "605 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '606 - test': ensure => present, proto => tcp, port => '606', action => accept, chain => 'INPUT', socket => false, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-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 'ipsec' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "607 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp6-adm-prohibited/) end end end context 'none' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "608 - test" -m policy --dir out --pol none -j REJECT --reject-with icmp6-adm-prohibited/) end end end end describe 'ipsec_dir' do context 'out' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "609 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp6-adm-prohibited/) end end end context 'in' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -d 2001:db8::1\/(128|ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) -m comment --comment "610 - test" -m policy --dir in --pol none -j REJECT --reject-with icmp6-adm-prohibited/) end end end end describe 'set_mark' do context '0x3e8/0xffffffff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '611 - test': ensure => present, chain => 'OUTPUT', proto => tcp, port => '611', jump => 'MARK', table => 'mangle', set_mark => '0x3e8/0xffffffff', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(/-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'] =~ /el-7/ or default['platform'] =~ /debian-7/ or default['platform'] =~ /ubuntu-14\.04/ #ipset is really difficult to test, just testing on one platform if default['platform'] =~ /ubuntu-14\.04/ describe 'ipset' do it 'applies' do pp = <<-EOS 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': command => 'ipset create blacklist hash:ip,port family inet6 maxelem 1024 hashsize 65535 timeout 120', path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', require => Package['ipset'], } exec { 'add blacklist': command => 'ipset add blacklist 2001:db8::1,80', path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', require => Exec['create ipset'], } firewall { '612 - test': ensure => present, chain => 'INPUT', proto => tcp, action => drop, ipset => 'blacklist src,src', provider => 'ip6tables', require => Exec['add blacklist'], } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "612 - test" -m set --match-set blacklist src,src -j DROP/) end end end end # mask isn't supported on deb7 if default['platform'] !~ /debian-7/ describe 'mask' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '613 - test': recent => 'update', rseconds => 60, rsource => true, rname => 'test', action => 'drop', chain => 'FORWARD', mask => 'ffff::', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A FORWARD -p tcp -m comment --comment "613 - test" -m recent --update --seconds 60 --name test --mask ffff:: --rsource -j DROP/) end end end end ['dst_type', 'src_type'].each do |type| describe "#{type}" do context 'MULTICAST' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '603 - test': proto => tcp, action => accept, #{type} => 'MULTICAST', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m addrtype\s.*\sMULTICAST -m comment --comment "603 - test" -j ACCEPT/) end end end context '! MULTICAST' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '603 - test inversion': proto => tcp, action => accept, #{type} => '! MULTICAST', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m addrtype( !\s.*\sMULTICAST|\s.*\s! MULTICAST) -m comment --comment "603 - test inversion" -j ACCEPT/) end end end context 'BROKEN' do it 'fails' do pp = <<-EOS class { '::firewall': } firewall { '603 - test': proto => tcp, action => accept, #{type} => 'BROKEN', provider => 'ip6tables', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "BROKEN"./) end end it 'should not contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to_not match(/-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 '500/sec' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '572 - test': ensure => present, proto => tcp, port => '572', action => accept, limit => '500/sec', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 572 -m comment --comment "572 - test" -m limit --limit 500\/sec -j ACCEPT/) end end end end describe 'burst' do context '500' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '573 - test': ensure => present, proto => tcp, port => '573', action => accept, limit => '500/sec', burst => '1500', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 573 -m comment --comment "573 - test" -m limit --limit 500\/sec --limit-burst 1500 -j ACCEPT/) end end end context 'invalid' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '571 - test': ensure => present, proto => tcp, port => '571', action => accept, limit => '500/sec', burst => '1500/sec', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "1500\/sec"./) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 'nobody' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '574 - test': ensure => present, proto => tcp, chain => 'OUTPUT', port => '574', action => accept, uid => 'nobody', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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 'root' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '575 - test': ensure => present, proto => tcp, chain => 'OUTPUT', port => '575', action => accept, gid => 'root', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'set_mark' do context '0x3e8/0xffffffff' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '580 - test': ensure => present, chain => 'OUTPUT', proto => tcp, port => '580', jump => 'MARK', table => 'mangle', set_mark => '0x3e8/0xffffffff', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-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 'multicast' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '581 - test': ensure => present, proto => tcp, port => '581', action => accept, pkttype => 'multicast', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 581 -m pkttype --pkt-type multicast -m comment --comment "581 - test" -j ACCEPT/) end end end context 'test' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '582 - test': ensure => present, proto => tcp, port => '582', action => accept, pkttype => 'test', } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/Invalid value "test"./) end end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '583 - test': ensure => present, proto => tcp, port => '583', action => accept, isfragment => true, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -f -m multiport --ports 583 -m comment --comment "583 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '584 - test': ensure => present, proto => tcp, port => '584', action => accept, isfragment => false, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-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'] =~ /el-5/ or fact('operatingsystem') == 'SLES') do context 'true' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '585 - test': ensure => present, proto => tcp, port => '585', action => accept, chain => 'PREROUTING', table => 'nat', socket => true, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-A PREROUTING -p tcp -m multiport --ports 585 -m socket -m comment --comment "585 - test" -j ACCEPT/) end end end context 'false' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '586 - test': ensure => present, proto => tcp, port => '586', action => accept, chain => 'PREROUTING', table => 'nat', socket => false, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-A PREROUTING -p tcp -m multiport --ports 586 -m comment --comment "586 - test" -j ACCEPT/) end end end end describe 'ipsec_policy' do context 'ipsec' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "593 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/) end end end context 'none' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "594 - test" -m policy --dir out --pol none -j REJECT --reject-with icmp-net-unreachable/) end end end end describe 'ipsec_dir' do context 'out' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "595 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/) end end end context 'in' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "596 - test" -m policy --dir in --pol none -j REJECT --reject-with icmp-net-unreachable/) end end end end describe 'recent' do context 'set' do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| # Mask added as of Ubuntu 14.04. expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "597 - test" -m recent --set --name list1 (--mask 255.255.255.255 )?--rdest/) end end end context 'rcheck' do it 'applies' do pp = <<-EOS 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, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "598 - test" -m recent --rcheck --seconds 60 --hitcount 5 --rttl --name list1 (--mask 255.255.255.255 )?--rsource/) end end end context 'update' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '599 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'update', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "599 - test" -m recent --update/) end end end context 'remove' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '600 - test': ensure => 'present', chain => 'INPUT', destination => '30.0.0.0/8', proto => 'all', table => 'filter', recent => 'remove', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "600 - test" -m recent --remove/) end end end end describe 'mac_source' do context '0A:1B:3C:4D:5E:6F' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '610 - test': ensure => present, source => '10.1.5.28/32', mac_source => '0A:1B:3C:4D:5E:6F', chain => 'INPUT', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| if (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '5') or (default['platform'] =~ /sles-10/) expect(r.stdout).to match(/-A INPUT -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(/-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 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 'Destination netmap 192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'PREROUTING', jump => 'NETMAP', source => '200.200.200.200', to => '192.168.1.1', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-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 'Source netmap 192.168.1.1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '569 - test': proto => tcp, table => 'nat', chain => 'POSTROUTING', jump => 'NETMAP', destination => '200.200.200.200', to => '192.168.1.1', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t nat') do |r| expect(r.stdout).to match(/-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 'log_prefix containing -A' do it 'adds the rule' do pp = <<-EOS class { '::firewall': } firewall { '700 - test': jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "700 - test" -j LOG --log-prefix "FW-A-INPUT: "/) end end it 'removes the rule' do pp = <<-EOS class { '::firewall': } firewall { '700 - test': ensure => absent, jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } EOS apply_manifest(pp, :catch_failures => true) end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-A INPUT -p tcp -m comment --comment "700 - test" -j LOG --log-prefix "FW-A-INPUT: "/) end end end context 'comment containing "-A "' do it 'adds the rule' do pp = <<-EOS class { '::firewall': } firewall { '700 - blah-A Test Rule': jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "700 - blah-A Test Rule" -j LOG --log-prefix "FW-A-INPUT: "/) end end it 'removes the rule' do pp = <<-EOS class { '::firewall': } firewall { '700 - blah-A Test Rule': ensure => absent, jump => 'LOG', log_prefix => 'FW-A-INPUT: ', } EOS apply_manifest(pp, :catch_failures => true) end it 'should not contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/-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.7.1/spec/acceptance/firewall_tee_spec.rb000644 000765 000024 00000003775 12567120562 024333 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before(:all) do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end if default['platform'] =~ /ubuntu-1404/ or default['platform'] =~ /ubuntu-1204/ or default['platform'] =~ /debian-7/ or default['platform'] =~ /debian-8/ or default['platform'] =~ /el-7/ describe 'tee_gateway' do context '10.0.0.2' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '810 - tee_gateway': chain => 'PREROUTING', table => 'mangle', jump => 'TEE', gateway => '10.0.0.2', proto => all, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save -t mangle') do |r| expect(r.stdout).to match(/-A PREROUTING -m comment --comment "810 - tee_gateway" -j TEE --gateway 10.0.0.2/) end end end end describe 'tee_gateway6' do context '2001:db8::1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '811 - tee_gateway6': chain => 'PREROUTING', table => 'mangle', jump => 'TEE', gateway => '2001:db8::1', proto => all, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save -t mangle') do |r| expect(r.stdout).to match(/-A PREROUTING -m comment --comment "811 - tee_gateway6" -j TEE --gateway 2001:db8::1/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_time_spec.rb000644 000765 000024 00000006013 12567120562 024500 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before(:all) do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end if default['platform'] =~ /ubuntu-1404/ or default['platform'] =~ /debian-7/ or default['platform'] =~ /debian-8/ or default['platform'] =~ /el-7/ describe "time tests ipv4" do context 'set all time parameters' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '805 - test': proto => tcp, dport => '8080', action => accept, chain => 'OUTPUT', date_start => '2016-01-19T04:17:07', date_stop => '2038-01-19T04:17:07', time_start => '6:00', time_stop => '17:00:00', month_days => '7', week_days => 'Tue', kernel_timezone => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m comment --comment "805 - test" -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -j ACCEPT/) end end end end describe "time tests ipv6" do context 'set all time parameters' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '805 - test': proto => tcp, dport => '8080', action => accept, chain => 'OUTPUT', date_start => '2016-01-19T04:17:07', date_stop => '2038-01-19T04:17:07', time_start => '6:00', time_stop => '17:00:00', month_days => '7', week_days => 'Tue', kernel_timezone => true, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --dports 8080 -m comment --comment "805 - test" -m time --timestart 06:00:00 --timestop 17:00:00 --monthdays 7 --weekdays Tue --datestart 2016-01-19T04:17:07 --datestop 2038-01-19T04:17:07 --kerneltz -j ACCEPT/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewall_uid_spec.rb000644 000765 000024 00000005715 12567120562 024333 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do describe 'reset' do it 'deletes all rules' do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') end it 'deletes all ip6tables rules' do shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end end describe "uid tests" do context 'uid set to root' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '801 - test': chain => 'OUTPUT', action => accept, uid => 'root', proto => 'all', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -m owner --uid-owner (0|root) -m comment --comment "801 - test" -j ACCEPT/) end end end context 'uid set to !root' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '802 - test': chain => 'OUTPUT', action => accept, uid => '!root', proto => 'all', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -m owner ! --uid-owner (0|root) -m comment --comment "802 - test" -j ACCEPT/) end end end context 'uid set to 0' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '803 - test': chain => 'OUTPUT', action => accept, uid => '0', proto => 'all', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -m owner --uid-owner (0|root) -m comment --comment "803 - test" -j ACCEPT/) end end end context 'uid set to !0' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '804 - test': chain => 'OUTPUT', action => accept, uid => '!0', proto => 'all', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A OUTPUT -m owner ! --uid-owner (0|root) -m comment --comment "804 - test" -j ACCEPT/) end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/firewallchain_spec.rb000644 000765 000024 00000006546 12567120562 024500 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'puppet resource firewallchain command:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before :all do iptables_flush_all_tables end describe 'ensure' do context 'present' do it 'applies cleanly' do pp = <<-EOS firewallchain { 'MY_CHAIN:filter:IPv4': ensure => present, } EOS # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'finds the chain' do shell('iptables-save') do |r| expect(r.stdout).to match(/MY_CHAIN/) end end end context 'absent' do it 'applies cleanly' do pp = <<-EOS firewallchain { 'MY_CHAIN:filter:IPv4': ensure => absent, } EOS # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'fails to find the chain' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/MY_CHAIN/) end end end end # XXX purge => false is not yet implemented #context 'adding a firewall rule to a chain:' do # it 'applies cleanly' do # pp = <<-EOS # firewallchain { 'MY_CHAIN:filter:IPv4': # ensure => present, # } # firewall { '100 my rule': # chain => 'MY_CHAIN', # action => 'accept', # proto => 'tcp', # dport => 5000, # } # EOS # # Run it twice and test for idempotency # apply_manifest(pp, :catch_failures => true) # apply_manifest(pp, :catch_changes => do_catch_changes) # end #end #context 'not purge firewallchain chains:' do # it 'does not purge the rule' do # pp = <<-EOS # firewallchain { 'MY_CHAIN:filter:IPv4': # ensure => present, # purge => false, # before => Resources['firewall'], # } # resources { 'firewall': # purge => true, # } # EOS # # Run it twice and test for idempotency # apply_manifest(pp, :catch_failures => true) do |r| # expect(r.stdout).to_not match(/removed/) # expect(r.stderr).to eq('') # end # apply_manifest(pp, :catch_changes => do_catch_changes) # end # it 'still has the rule' do # pp = <<-EOS # firewall { '100 my rule': # chain => 'MY_CHAIN', # action => 'accept', # proto => 'tcp', # dport => 5000, # } # EOS # # Run it twice and test for idempotency # apply_manifest(pp, :catch_changes => do_catch_changes) # end #end describe 'policy' do after :all do shell('iptables -t filter -P FORWARD ACCEPT') end context 'DROP' do it 'applies cleanly' do pp = <<-EOS firewallchain { 'FORWARD:filter:IPv4': policy => 'drop', } EOS # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'finds the chain' do shell('iptables-save') do |r| expect(r.stdout).to match(/FORWARD DROP/) end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/invert_spec.rb000644 000765 000024 00000004525 12567120562 023172 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before(:all) do iptables_flush_all_tables end context "inverting rules" do it 'applies' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'should contain the rules' do shell('iptables-save') do |r| if (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '5') or (default['platform'] =~ /sles-10/) expect(r.stdout).to match(/-A INPUT -p ! esp -m comment --comment "601 disallow esp protocol" -j ACCEPT/) expect(r.stdout).to match(/-A INPUT -s ! 10\.0\.0\.0\/255\.0\.0\.0 -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m multiport --sports ! 80,443 -m comment --comment "602 drop NEW external website packets with FIN\/RST\/ACK set and SYN unset" -m state --state NEW -j DROP/) else expect(r.stdout).to match(/-A INPUT ! -p esp -m comment --comment "601 disallow esp protocol" -j ACCEPT/) expect(r.stdout).to match(/-A INPUT ! -s 10\.0\.0\.0\/8 -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m multiport ! --sports 80,443 -m comment --comment "602 drop NEW external website packets with FIN\/RST\/ACK set and SYN unset" -m state --state NEW -j DROP/) end end end end context "inverting partial array rules" do it 'raises a failure' do pp = <<-EOS class { '::firewall': } firewall { '603 drop 80,443 traffic': chain => 'INPUT', action => 'drop', proto => 'tcp', sport => ['! http', '443'], } EOS apply_manifest(pp, :expect_failures => true) do |r| expect(r.stderr).to match(/is not prefixed/) end end end end puppetlabs-firewall-1.7.1/spec/acceptance/ip6_fragment_spec.rb000644 000765 000024 00000010666 12567120562 024247 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' if default['platform'] =~ /el-5/ or default['platform'] =~ /sles-10/ describe "firewall ip6tables doesn't work on 1.3.5 because --comment is missing", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before :all do ip6tables_flush_all_tables end it "can't use ip6tables" do pp = <<-EOS class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', } EOS expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/ip6tables provider is not supported/) end end else describe 'firewall ishasmorefrags/islastfrag/isfirstfrag properties', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before :all do ip6tables_flush_all_tables end shared_examples "is idempotent" do |values, line_match| it "changes the values to #{values}" do pp = <<-EOS class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', #{values} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) shell('ip6tables-save') do |r| expect(r.stdout).to match(/#{line_match}/) end end end shared_examples "doesn't change" do |values, line_match| it "doesn't change the values to #{values}" do pp = <<-EOS class { '::firewall': } firewall { '599 - test': ensure => present, proto => 'tcp', provider => 'ip6tables', #{values} } EOS apply_manifest(pp, :catch_changes => do_catch_changes) shell('ip6tables-save') do |r| expect(r.stdout).to match(/#{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', '', /-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', /-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', /-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 'and current value is false' do it_behaves_like "doesn't change", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/ end context 'and current value is true' do it_behaves_like "is idempotent", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-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 'and current value is false' do it_behaves_like "is idempotent", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/ end context 'and current value is true' do it_behaves_like "doesn't change", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-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.7.1/spec/acceptance/isfragment_spec.rb000644 000765 000024 00000005627 12567120562 024026 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall isfragment property', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before :all do iptables_flush_all_tables end shared_examples "is idempotent" do |value, line_match| it "changes the value to #{value}" do pp = <<-EOS class { '::firewall': } firewall { '597 - test': ensure => present, proto => 'tcp', #{value} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) shell('iptables-save') do |r| expect(r.stdout).to match(/#{line_match}/) end end end shared_examples "doesn't change" do |value, line_match| it "doesn't change the value to #{value}" do pp = <<-EOS class { '::firewall': } firewall { '597 - test': ensure => present, proto => 'tcp', #{value} } EOS apply_manifest(pp, :catch_changes => do_catch_changes) shell('iptables-save') do |r| expect(r.stdout).to match(/#{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', '', /-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,', /-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,', /-A INPUT -p tcp -m comment --comment "597 - test"/ end end describe 'editing a rule' 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 context 'and current value is false' do it_behaves_like "doesn't change", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/ end context 'and current value is true' do it_behaves_like "is idempotent", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/ end end context 'when set to true' do before :each do iptables_flush_all_tables shell('iptables -A INPUT -p tcp -f -m comment --comment "597 - test"') end context 'and current value is false' do it_behaves_like "is idempotent", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/ end context 'and current value is true' do it_behaves_like "doesn't change", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/ end end end end puppetlabs-firewall-1.7.1/spec/acceptance/match_mark_spec.rb000644 000765 000024 00000003412 12567120562 023763 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before(:all) do shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush') shell('ip6tables --flush; ip6tables -t nat --flush; ip6tables -t mangle --flush') end if default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/ describe 'match_mark' do context '0x1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '503 match_mark - test': proto => 'all', match_mark => '0x1', action => reject, } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('iptables-save') do |r| expect(r.stdout).to match(/-A INPUT -m comment --comment "503 match_mark - test" -m mark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable/) end end end end describe 'match_mark_ip6' do context '0x1' do it 'applies' do pp = <<-EOS class { '::firewall': } firewall { '503 match_mark ip6tables - test': proto => 'all', match_mark => '0x1', action => reject, provider => 'ip6tables', } EOS apply_manifest(pp, :catch_failures => true) end it 'should contain the rule' do shell('ip6tables-save') do |r| expect(r.stdout).to match(/-A INPUT -m comment --comment "503 match_mark ip6tables - test" -m mark --mark 0x1 -j REJECT --reject-with icmp6-port-unreachable/) end end end end end end puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/000755 000765 000024 00000000000 12567122052 022136 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/spec/acceptance/params_spec.rb000644 000765 000024 00000007550 12567120562 023147 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe "param based tests:", :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 it 'test various params', :unless => (default['platform'].match(/el-5/) || fact('operatingsystem') == 'SLES') do iptables_flush_all_tables ppm = <<-EOS firewall { '100 test': table => 'raw', socket => 'true', chain => 'PREROUTING', jump => 'LOG', log_level => 'debug', } EOS expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2) expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero end it 'test log rule' do iptables_flush_all_tables ppm = <<-EOS firewall { '998 log all': proto => 'all', jump => 'LOG', log_level => 'debug', } EOS expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2) expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero end it 'test log rule - changing names' do iptables_flush_all_tables ppm1 = <<-EOS firewall { '004 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } EOS ppm2 = <<-EOS firewall { '003 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } EOS expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2) ppm = <<-EOS + "\n" + ppm2 resources { 'firewall': purge => true, } EOS expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2) end it 'test chain - changing names' do iptables_flush_all_tables ppm1 = <<-EOS firewall { '004 with a chain': chain => 'INPUT', proto => 'all', } EOS ppm2 = <<-EOS firewall { '004 with a chain': chain => 'OUTPUT', proto => 'all', } EOS apply_manifest(ppm1, :expect_changes => true) ppm = <<-EOS + "\n" + ppm2 resources { 'firewall': purge => true, } EOS expect(apply_manifest(ppm2, :expect_failures => true).stderr).to match(/is not supported/) end it 'test log rule - idempotent' do iptables_flush_all_tables ppm1 = <<-EOS firewall { '004 log all INVALID packets': chain => 'INPUT', proto => 'all', ctstate => 'INVALID', jump => 'LOG', log_level => '3', log_prefix => 'IPTABLES dropped invalid: ', } EOS expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2) expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to be_zero end it 'test src_range rule' do iptables_flush_all_tables ppm = <<-EOS firewall { '997 block src ip range': chain => 'INPUT', proto => 'all', action => 'drop', src_range => '10.0.0.1-10.0.0.10', } EOS expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2) expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero end it 'test dst_range rule' do iptables_flush_all_tables ppm = <<-EOS firewall { '998 block dst ip range': chain => 'INPUT', proto => 'all', action => 'drop', dst_range => '10.0.0.2-10.0.0.20', } EOS expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2) expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero end end puppetlabs-firewall-1.7.1/spec/acceptance/purge_spec.rb000644 000765 000024 00000013712 12567120562 023003 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe "purge tests:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do context('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 it 'make sure duplicate existing rules get purged' do pp = <<-EOS class { 'firewall': } resources { 'firewall': purge => true, } EOS apply_manifest(pp, :expect_changes => true) end it 'saves' do shell('iptables-save') do |r| expect(r.stdout).to_not match(/1\.2\.1\.2/) expect(r.stderr).to eq("") end end end context('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 it 'purges only the specified chain' do pp = <<-EOS class { 'firewall': } firewallchain { 'INPUT:filter:IPv4': purge => true, } EOS apply_manifest(pp, :expect_changes => true) shell('iptables-save') do |r| expect(r.stdout).to match(/010 output-1\.2\.1\.2/) expect(r.stdout).to_not match(/1\.2\.1\.1/) expect(r.stderr).to eq("") end end it 'ignores managed rules' do pp = <<-EOS class { 'firewall': } firewallchain { 'OUTPUT:filter:IPv4': purge => true, } firewall { '010 output-1.2.1.2': chain => 'OUTPUT', proto => 'all', source => '1.2.1.2', } EOS apply_manifest(pp, :catch_changes => do_catch_changes) end it 'ignores specified rules' do pp = <<-EOS class { 'firewall': } firewallchain { 'INPUT:filter:IPv4': purge => true, ignore => [ '-s 1\.2\.1\.1', ], } EOS apply_manifest(pp, :catch_changes => do_catch_changes) end it 'adds managed rules with ignored rules' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) expect(shell('iptables-save').stdout).to match(/-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'] !~ /el-5/ and default['platform'] !~ /sles-10/ context '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 it 'purges only the specified chain' do pp = <<-EOS class { 'firewall': } firewallchain { 'INPUT:filter:IPv6': purge => true, } EOS apply_manifest(pp, :expect_changes => true) shell('ip6tables-save') do |r| expect(r.stdout).to match(/010 output-1::50/) expect(r.stdout).to_not match(/1::42/) expect(r.stderr).to eq("") end end it 'ignores managed rules' do pp = <<-EOS class { 'firewall': } firewallchain { 'OUTPUT:filter:IPv6': purge => true, } firewall { '010 output-1::50': chain => 'OUTPUT', proto => 'all', source => '1::50', provider => 'ip6tables', } EOS apply_manifest(pp, :catch_changes => do_catch_changes) end it 'ignores specified rules' do pp = <<-EOS class { 'firewall': } firewallchain { 'INPUT:filter:IPv6': purge => true, ignore => [ '-s 1::42', ], } EOS apply_manifest(pp, :catch_changes => do_catch_changes) end it 'adds managed rules with ignored rules' do pp = <<-EOS 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', } EOS apply_manifest(pp, :catch_failures => true) expect(shell('ip6tables-save').stdout).to match(/-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.7.1/spec/acceptance/resource_cmd_spec.rb000644 000765 000024 00000015003 12567120562 024326 0ustar00tpstaff000000 000000 require '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:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) 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 '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 '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 '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 '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 '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 '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'] !~ /sles-10/ context '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 '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 '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 # version of iptables that ships with el5 doesn't work with the # ip6tables provider if default['platform'] !~ /el-5/ and default['platform'] !~ /sles-10/ context '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.7.1/spec/acceptance/rules_spec.rb000644 000765 000024 00000023165 12567120562 023016 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'complex ruleset 1', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do before :all do iptables_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 it 'applies cleanly' do pp = <<-EOS 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', } EOS # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero end it 'contains appropriate rules' do shell('iptables-save') do |r| [ /INPUT ACCEPT/, /FORWARD ACCEPT/, /OUTPUT ACCEPT/, /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) -d 10.0.0.0\/(8|255\.0\.0\.0) -m comment --comment \"090 forward allow local\" -j ACCEPT/, /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"100 forward standard allow icmp\" -j ACCEPT/, /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p tcp -m multiport --ports 80,443,21,20,22,53,123,43,873,25,465 -m comment --comment \"100 forward standard allow tcp\" -m state --state NEW -j ACCEPT/, /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p udp -m multiport --ports 53,123 -m comment --comment \"100 forward standard allow udp\" -j ACCEPT/ ].each do |line| expect(r.stdout).to match(line) 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') expect(shell('iptables -t filter -X LOCAL_INPUT').stderr).to eq("") expect(shell('iptables -t filter -X LOCAL_INPUT_PRE').stderr).to eq("") end it 'applies cleanly' do pp = <<-EOS class { '::firewall': } Firewall { proto => 'all', stage => 'pre', } Firewallchain { stage => 'pre', 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']: } EOS # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => do_catch_changes) end it 'contains appropriate rules' do shell('iptables-save') do |r| [ /INPUT DROP/, /FORWARD DROP/, /OUTPUT ACCEPT/, /LOCAL_INPUT/, /LOCAL_INPUT_PRE/, /-A INPUT -m comment --comment \"001 LOCAL_INPUT_PRE\" -j LOCAL_INPUT_PRE/, /-A INPUT -m comment --comment \"010 INPUT allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/, /-A INPUT -d 127.0.0.0\/(8|255\.0\.0\.0) (! -i|-i !) lo -m comment --comment \"011 reject local traffic not on loopback interface\" -j REJECT --reject-with icmp-port-unreachable/, /-A INPUT -i lo -m comment --comment \"012 accept loopback\" -j ACCEPT/, /-A INPUT -p icmp -m comment --comment \"013 icmp destination-unreachable\" -m icmp --icmp-type 3 -j ACCEPT/, /-A INPUT -s 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"013 icmp echo-request\" -m icmp --icmp-type 8 -j ACCEPT/, /-A INPUT -p icmp -m comment --comment \"013 icmp time-exceeded\" -m icmp --icmp-type 11 -j ACCEPT/, /-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"020 ssh\" -m state --state NEW -j ACCEPT/, /-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"001 ssh needed for beaker testing\" -j ACCEPT/, /-A OUTPUT (! -o|-o !) eth0:2 -p tcp -m multiport --dports 25 -m comment --comment \"025 smtp\" -m state --state NEW -j ACCEPT/, /-A INPUT -i eth0:3 -p tcp -m multiport --dports 443 -m comment --comment \"443 ssl on aliased interface\" -m state --state NEW -j ACCEPT/, /-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT/, /-A FORWARD -m comment --comment \"010 allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/ ].each do |line| expect(r.stdout).to match(line) end end end end puppetlabs-firewall-1.7.1/spec/acceptance/socket_spec.rb000644 000765 000024 00000006265 12567120562 023156 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' # RHEL5 does not support -m socket describe 'firewall socket property', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) || default['platform'] =~ /el-5/ || fact('operatingsystem') == 'SLES') do before :all do iptables_flush_all_tables end shared_examples "is idempotent" do |value, line_match| it "changes the value to #{value}" do pp = <<-EOS class { '::firewall': } firewall { '598 - test': ensure => present, proto => 'tcp', chain => 'PREROUTING', table => 'raw', #{value} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) shell('iptables-save -t raw') do |r| expect(r.stdout).to match(/#{line_match}/) end end end shared_examples "doesn't change" do |value, line_match| it "doesn't change the value to #{value}" do pp = <<-EOS class { '::firewall': } firewall { '598 - test': ensure => present, proto => 'tcp', chain => 'PREROUTING', table => 'raw', #{value} } EOS apply_manifest(pp, :catch_changes => true) shell('iptables-save -t raw') do |r| expect(r.stdout).to match(/#{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', '', /-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,', /-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,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/ end end describe 'editing a rule' do context 'when unset or false' do before :each do iptables_flush_all_tables shell('iptables -t raw -A PREROUTING -p tcp -m comment --comment "598 - test"') end context 'and current value is false' do it_behaves_like "doesn't change", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/ end context 'and current value is true' do it_behaves_like "is idempotent", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/ end end context 'when set to 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 context 'and current value is false' do it_behaves_like "is idempotent", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/ end context 'and current value is true' do it_behaves_like "doesn't change", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/ end end end end puppetlabs-firewall-1.7.1/spec/acceptance/standard_usage_spec.rb000644 000765 000024 00000003213 12567120562 024640 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' # Some tests for the standard recommended usage describe 'standard usage tests:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do it 'applies twice' do pp = <<-EOS 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, } EOS # 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.7.1/spec/acceptance/unsupported_spec.rb000644 000765 000024 00000000505 12567120562 024245 0ustar00tpstaff000000 000000 require 'spec_helper_acceptance' describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do it 'should fail' do pp = <<-EOS class { 'firewall': } EOS expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/not currently supported/i) end end puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-59-x64-pe.yml000644 000765 000024 00000000430 12567120562 025431 0ustar00tpstaff000000 000000 HOSTS: centos-59-x64: roles: - master - database - console platform: el-5-x86_64 box : centos-59-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: pe puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-59-x64.yml000644 000765 000024 00000000370 12567120562 025032 0ustar00tpstaff000000 000000 HOSTS: centos-59-x64: roles: - master platform: el-5-x86_64 box : centos-59-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: git puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-64-x64-fusion.yml000644 000765 000024 00000000372 12567120562 026331 0ustar00tpstaff000000 000000 HOSTS: centos-64-x64: roles: - master platform: el-6-x86_64 box : centos-64-x64-fusion503-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-fusion503-nocm.box hypervisor : fusion CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-64-x64-pe.yml000644 000765 000024 00000000432 12567120562 025427 0ustar00tpstaff000000 000000 HOSTS: centos-64-x64: roles: - master - database - dashboard platform: el-6-x86_64 box : centos-64-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: pe puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-64-x64.yml000644 000765 000024 00000000371 12567120562 025027 0ustar00tpstaff000000 000000 HOSTS: centos-64-x64: roles: - master platform: el-6-x86_64 box : centos-64-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-65-x64.yml000644 000765 000024 00000000372 12567120562 025031 0ustar00tpstaff000000 000000 HOSTS: centos-65-x64: roles: - master platform: el-6-x86_64 box : centos-65-x64-vbox436-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box hypervisor : vagrant CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/centos-7-x64.yml000644 000765 000024 00000000420 12567120562 024737 0ustar00tpstaff000000 000000 HOSTS: centos-7-x64: roles: - master platform: el-7-x86_64 box : puppetlabs/centos-7.0-64-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-7.0-64-virtualbox-nocm.box hypervisor : vagrant CONFIG: type: foss log_level: verbosepuppetlabs-firewall-1.7.1/spec/acceptance/nodesets/debian-607-x64.yml000644 000765 000024 00000000376 12567120562 025046 0ustar00tpstaff000000 000000 HOSTS: debian-607-x64: roles: - master platform: debian-6-amd64 box : debian-607-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: git puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/debian-70rc1-x64.yml000644 000765 000024 00000000404 12567120562 025356 0ustar00tpstaff000000 000000 HOSTS: debian-70rc1-x64: roles: - master platform: debian-7-amd64 box : debian-70rc1-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: git puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/default.yml000644 000765 000024 00000000371 12567120562 024312 0ustar00tpstaff000000 000000 HOSTS: centos-64-x64: roles: - master platform: el-6-x86_64 box : centos-64-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/fedora-18-x64.yml000644 000765 000024 00000000375 12567120562 024777 0ustar00tpstaff000000 000000 HOSTS: fedora-18-x64: roles: - master platform: fedora-18-x86_64 box : fedora-18-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: git puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/sles-11sp1-x64.yml000644 000765 000024 00000000376 12567120562 025123 0ustar00tpstaff000000 000000 HOSTS: sles-11sp1-x64: roles: - master platform: sles-11-x86_64 box : sles-11sp1-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: git puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml000644 000765 000024 00000000436 12567120562 026603 0ustar00tpstaff000000 000000 HOSTS: ubuntu-server-10044-x64: roles: - master platform: ubuntu-10.04-amd64 box : ubuntu-server-10044-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml000644 000765 000024 00000000436 12567120562 026603 0ustar00tpstaff000000 000000 HOSTS: ubuntu-server-12042-x64: roles: - master platform: ubuntu-12.04-amd64 box : ubuntu-server-12042-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box hypervisor : vagrant CONFIG: type: foss puppetlabs-firewall-1.7.1/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml000644 000765 000024 00000000420 12567120562 026514 0ustar00tpstaff000000 000000 HOSTS: ubuntu-server-1404-x64: roles: - master platform: ubuntu-14.04-amd64 box : puppetlabs/ubuntu-14.04-64-nocm box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm hypervisor : vagrant CONFIG: log_level : debug type: git puppetlabs-firewall-1.7.1/manifests/init.pp000644 000765 000024 00000001652 12567120562 020577 0ustar00tpstaff000000 000000 # = 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, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, ) inherits ::firewall::params { case $ensure { /^(running|stopped)$/: { # Do nothing. } default: { fail("${title}: Ensure value '${ensure}' is not supported") } } case $::kernel { 'Linux': { class { "${title}::linux": ensure => $ensure, service_name => $service_name, package_name => $package_name, } } default: { fail("${title}: Kernel '${::kernel}' is not currently supported") } } } puppetlabs-firewall-1.7.1/manifests/linux/000755 000765 000024 00000000000 12567122052 020422 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/manifests/linux.pp000644 000765 000024 00000003605 12567120562 020773 0ustar00tpstaff000000 000000 # = 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 # class firewall::linux ( $ensure = running, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, ) inherits ::firewall::params { $enable = $ensure ? { running => true, stopped => false, } package { 'iptables': ensure => present, } case $::operatingsystem { 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer': { class { "${title}::redhat": ensure => $ensure, enable => $enable, package_name => $package_name, service_name => $service_name, 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.7.1/manifests/params.pp000644 000765 000024 00000003632 12567120562 021117 0ustar00tpstaff000000 000000 class firewall::params { case $::osfamily { 'RedHat': { case $::operatingsystem { 'Amazon': { $service_name = 'iptables' $package_name = undef } 'Fedora': { if versioncmp($::operatingsystemrelease, '15') >= 0 { $package_name = 'iptables-services' } else { $package_name = undef } $service_name = 'iptables' } default: { if versioncmp($::operatingsystemrelease, '7.0') >= 0 { $package_name = 'iptables-services' } else { $package_name = 'iptables-ipv6' } $service_name = 'iptables' } } } 'Debian': { 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'] $package_name = 'net-firewall/iptables' } default: { case $::operatingsystem { 'Archlinux': { $service_name = ['iptables','ip6tables'] $package_name = undef } default: { $service_name = 'iptables' $package_name = undef } } } } } puppetlabs-firewall-1.7.1/manifests/linux/archlinux.pp000644 000765 000024 00000001731 12567120562 022766 0ustar00tpstaff000000 000000 # = 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, ) inherits ::firewall::params { if $package_name { package { $package_name: ensure => $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.7.1/manifests/linux/debian.pp000644 000765 000024 00000003556 12567120562 022222 0ustar00tpstaff000000 000000 # = 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, ) 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 => present, require => Exec['iptables-persistent-debconf'] } } if($::operatingsystemrelease =~ /^6\./ and $enable == true 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.7.1/manifests/linux/gentoo.pp000644 000765 000024 00000001725 12567120562 022267 0ustar00tpstaff000000 000000 # = 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, ) inherits ::firewall::params { if $package_name { package { $package_name: ensure => present, } } 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.7.1/manifests/linux/redhat.pp000644 000765 000024 00000004245 12567120562 022243 0ustar00tpstaff000000 000000 # = Class: firewall::linux::redhat # # Manages the `iptables` service on RedHat-alike systems. # # == Parameters: # # [*ensure*] # Ensure parameter passed onto Service[] resources. # Default: running # # [*enable*] # Enable parameter passed onto Service[] resources. # Default: true # class firewall::linux::redhat ( $ensure = running, $enable = true, $service_name = $::firewall::params::service_name, $package_name = $::firewall::params::package_name, ) inherits ::firewall::params { # RHEL 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], } } if $package_name { package { $package_name: ensure => present, 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], unless => '/usr/bin/systemctl is-active iptables' } } } service { $service_name: ensure => $ensure, enable => $enable, hasstatus => true, require => File['/etc/sysconfig/iptables'], } # Redhat 7 selinux user context for /etc/sysconfig/iptables is set to unconfined_u case $::selinux { #lint:ignore:quoted_booleans 'true',true: { $seluser = 'unconfined_u' } #lint:endignore default: { $seluser = undef } } file { '/etc/sysconfig/iptables': ensure => present, owner => 'root', group => 'root', mode => '0600', seluser => $seluser, } } puppetlabs-firewall-1.7.1/lib/facter/000755 000765 000024 00000000000 12567122052 017304 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/000755 000765 000024 00000000000 12567122052 017355 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/provider/000755 000765 000024 00000000000 12567122052 021207 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/type/000755 000765 000024 00000000000 12567122052 020336 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/util/000755 000765 000024 00000000000 12567122052 020332 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/util/firewall.rb000644 000765 000024 00000015522 12567120562 022475 0ustar00tpstaff000000 000000 require '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 =~ /\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 =~ /\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 =~ /^(tcp|udp)$/ proto = 'tcp' end m = value.to_s.match(/^(!\s+)?(\S+)/) if m[2].match(/^\d+(-\d+)?$/) return "#{m[1]}#{m[2]}" else return "#{m[1]}#{Socket.getservbyname(m[2], proto).to_s}" end end # Takes an address and returns it in CIDR notation. # # 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) begin value = Puppet::Util::IPCidr.new(value) rescue value = Puppet::Util::IPCidr.new(Resolv.getaddress(value)) end return nil if value.prefixlen == 0 value.cidr end # Takes an address mask 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) match = value.match /(!)\s?(.*)$/ return host_to_ip(value) unless match cidr = host_to_ip(match[2]) 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 # pass end return 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' 'RedHat' when 'Debian', 'Ubuntu' 'Debian' else Facter.value(:operatingsystem) end # Older iptables-persistent doesn't provide save action. if os_key == 'Debian' persist_ver = Facter.value(:iptables_persistent_version) if (persist_ver and 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' && ['RedHat','CentOS','Scientific','SL','SLC','Ascendos','CloudLinux','PSBM','OracleLinux','OVS','OEL','XenServer'].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 and 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.7.1/lib/puppet/util/ipcidr.rb000644 000765 000024 00000001646 12567120562 022144 0ustar00tpstaff000000 000000 require 'ipaddr' # IPCidr object wrapper for IPAddr module Puppet module Util class IPCidr < IPAddr def initialize(ipaddr) begin super(ipaddr) rescue ArgumentError => e if e.message =~ /invalid address/ raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}" else raise e end end 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 $1.length if /\A(1*)(0*)\z/ =~ (@mask_addr & m).to_s(2) raise "bad addr_mask format" end def cidr cidr = sprintf("%s/%s", self.to_s, self.prefixlen) cidr end end end end puppetlabs-firewall-1.7.1/lib/puppet/type/firewall.rb000644 000765 000024 00000126543 12567120562 022507 0ustar00tpstaff000000 000000 # 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 = <<-EOS 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. EOS 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 :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 :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." # provider specific features feature :iptables, "The provider provides iptables features." ensurable do desc <<-EOS Manage the state of this rule. The default action is *present*. EOS newvalue(:present) do provider.insert end newvalue(:absent) do provider.delete end defaultto :present end newparam(:name) do desc <<-EOS 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. EOS isnamevar # Keep rule names simple - they must start with a number newvalues(/^\d+[[:graph:][:space:]]+$/) end newproperty(:action) do desc <<-EOS 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*). EOS newvalues(:accept, :reject, :drop) end # Generic matching properties newproperty(:source) do desc <<-EOS 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. EOS munge do |value| begin @resource.host_to_mask(value) rescue Exception => e self.fail("host_to_ip failed for #{value}, exception #{e}") end end end # Source IP range newproperty(:src_range, :required_features => :iprange) do desc <<-EOS 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. EOS validate do |value| if matches = /^([^\-\/]+)-([^\-\/]+)$/.match(value) start_addr = matches[1] end_addr = matches[2] [start_addr, end_addr].each do |addr| begin @resource.host_to_ip(addr) rescue Exception self.fail("Invalid IP address \"#{addr}\" in range \"#{value}\"") end end else raise(ArgumentError, "The source IP range must be in 'IP1-IP2' format.") end end end newproperty(:destination) do desc <<-EOS 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. EOS munge do |value| begin @resource.host_to_mask(value) rescue Exception => e self.fail("host_to_ip failed for #{value}, exception #{e}") end end end # Destination IP range newproperty(:dst_range, :required_features => :iprange) do desc <<-EOS 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. EOS validate do |value| if matches = /^([^\-\/]+)-([^\-\/]+)$/.match(value) start_addr = matches[1] end_addr = matches[2] [start_addr, end_addr].each do |addr| begin @resource.host_to_ip(addr) rescue Exception self.fail("Invalid IP address \"#{addr}\" in range \"#{value}\"") end end else raise(ArgumentError, "The destination IP range must be in 'IP1-IP2' format.") end end end newproperty(:sport, :array_matching => :all) do desc <<-EOS 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. EOS munge do |value| @resource.string_to_port(value, :proto) end def is_to_s(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end newproperty(:dport, :array_matching => :all) do desc <<-EOS 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. EOS munge do |value| @resource.string_to_port(value, :proto) end def is_to_s(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end newproperty(:port, :array_matching => :all) do desc <<-EOS 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. EOS validate do |value| Puppet.warning("port is deprecated and will be removed. Use dport and/or sport instead.") end munge do |value| @resource.string_to_port(value, :proto) end def is_to_s(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end newproperty(:dst_type, :required_features => :address_type) do desc <<-EOS 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 EOS newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].collect do |address_type| [address_type, "! #{address_type}".to_sym] end.flatten) end newproperty(:src_type, :required_features => :address_type) do desc <<-EOS 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 EOS newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].collect do |address_type| [address_type, "! #{address_type}".to_sym] end.flatten) end newproperty(:proto) do desc <<-EOS The specific protocol to match for this rule. By default this is *tcp*. EOS newvalues(*[:tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ipv4, :ipv6, :ospf, :gre, :cbt, :all].collect do |proto| [proto, "! #{proto}".to_sym] end.flatten) defaultto "tcp" end # tcp-specific newproperty(:mss) do desc <<-EOS Match a given TCP MSS value or range. EOS end # tcp-specific newproperty(:tcp_flags, :required_features => :tcp_flags) do desc <<-EOS 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. EOS end # Iptables specific newproperty(:chain, :required_features => :iptables) do desc <<-EOS 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'. EOS defaultto "INPUT" newvalue(/^[a-zA-Z0-9\-_]+$/) end newproperty(:table, :required_features => :iptables) do desc <<-EOS Table to use. Can be one of: * nat * mangle * filter * raw * rawpost By default the setting is 'filter'. EOS newvalues(:nat, :mangle, :filter, :raw, :rawpost) defaultto "filter" end newproperty(:jump, :required_features => :iptables) do desc <<-EOS The value for the iptables --jump parameter. Normal values are: * QUEUE * RETURN * DNAT * SNAT * LOG * 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. EOS validate do |value| unless value =~ /^[a-zA-Z0-9\-_]+$/ raise ArgumentError, <<-EOS Jump destination must consist of alphanumeric characters, an underscore or a yphen. EOS end if ["accept","reject","drop"].include?(value.downcase) raise ArgumentError, <<-EOS Jump destination should not be one of ACCEPT, REJECT or DROP. Use the action property instead. EOS end end end # Interface specific matching properties newproperty(:iniface, :required_features => :interface_match) do desc <<-EOS Input interface to filter on. Supports interface alias like eth0:0. To negate the match try this: iniface => '! lo', EOS newvalues(/^!?\s?[a-zA-Z0-9\-\._\+\:]+$/) end newproperty(:outiface, :required_features => :interface_match) do desc <<-EOS Output interface to filter on. Supports interface alias like eth0:0. To negate the match try this: outiface => '! lo', EOS newvalues(/^!?\s?[a-zA-Z0-9\-\._\+\:]+$/) end # NAT specific properties newproperty(:tosource, :required_features => :snat) do desc <<-EOS When using jump => "SNAT" you can specify the new source address using this parameter. EOS end newproperty(:todest, :required_features => :dnat) do desc <<-EOS When using jump => "DNAT" you can specify the new destination address using this paramter. EOS end newproperty(:toports, :required_features => :dnat) do desc <<-EOS For DNAT this is the port that will replace the destination port. EOS end newproperty(:to, :required_features => :netmap) do desc <<-EOS For NETMAP this will replace the destination IP EOS end newproperty(:random, :required_features => :dnat) do desc <<-EOS When using a jump value of "MASQUERADE", "DNAT", "REDIRECT", or "SNAT" this boolean will enable randomized port mapping. EOS newvalues(:true, :false) end # Reject ICMP type newproperty(:reject, :required_features => :reject_type) do desc <<-EOS When combined with jump => "REJECT" you can specify a different icmp response to be sent back to the packet sender. EOS end # Logging properties newproperty(:log_level, :required_features => :log_level) do desc <<-EOS When combined with jump => "LOG" specifies the system log level to log to. EOS munge do |value| if value.kind_of?(String) value = @resource.log_level_name_to_number(value) else value end if value == nil && value != "" self.fail("Unable to determine log level") end value end end newproperty(:log_prefix, :required_features => :log_prefix) do desc <<-EOS When combined with jump => "LOG" specifies the log prefix to use when logging. EOS end # ICMP matching property newproperty(:icmp, :required_features => :icmp_match) do desc <<-EOS 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. EOS 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 end munge do |value| if value.kind_of?(String) # ICMP codes differ between IPv4 and IPv6. case @resource[:provider] when :iptables protocol = 'inet' when :ip6tables protocol = 'inet6' else self.fail("cannot work out protocol family") end value = @resource.icmp_name_to_number(value, protocol) else value end if value == nil && value != "" self.fail("cannot work out icmp type") end value end end newproperty(:state, :array_matching => :all, :required_features => :state_match) do desc <<-EOS Matches a packet based on its state in the firewall stateful inspection table. Values can be: * INVALID * ESTABLISHED * NEW * RELATED EOS newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED) # 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 is_to_s(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end newproperty(:ctstate, :array_matching => :all, :required_features => :state_match) do desc <<-EOS Matches a packet based on its state in the firewall stateful inspection table, using the conntrack module. Values can be: * INVALID * ESTABLISHED * NEW * RELATED EOS newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED) # 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 is_to_s(value) should_to_s(value) end def should_to_s(value) value = [value] unless value.is_a?(Array) value.join(',') end end # Connection mark newproperty(:connmark, :required_features => :mark) do desc <<-EOS 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. EOS 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? or (mark and match[2] and 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 <<-EOS Connection limiting value for matched connections above n. EOS newvalue(/^\d+$/) end newproperty(:connlimit_mask, :required_features => :connection_limiting) do desc <<-EOS Connection limiting by subnet mask for matched connections. IPv4: 0-32 IPv6: 0-128 EOS newvalue(/^\d+$/) end # Hop limiting properties newproperty(:hop_limit, :required_features => :hop_limiting) do desc <<-EOS Hop limiting value for matched packets. EOS newvalue(/^\d+$/) end # Rate limiting properties newproperty(:limit, :required_features => :rate_limiting) do desc <<-EOS 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'." EOS end newproperty(:burst, :required_features => :rate_limiting) do desc <<-EOS Rate limiting burst value (per second) before limit checks apply. EOS newvalue(/^\d+$/) end newproperty(:uid, :required_features => :owner) do desc <<-EOS UID or Username owner matching rule. Accepts a string argument only, as iptables does not accept multiple uid in a single statement. EOS 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(/\s+/,'') should = @should.first.to_s.gsub(/\s+/,'') # Keep track of negation, but remove the '!' is_negate = '' should_negate = '' if is.start_with?('!') is = is.gsub(/^!/,'') is_negate = '!' end if should.start_with?('!') should = should.gsub(/^!/,'') should_negate = '!' end # If 'should' contains anything other than digits, # we assume that we have to do a lookup to convert # to UID unless should[/[0-9]+/] == should should = Etc.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[/[0-9]+/] == is is = Etc.getpwnam(is).uid end return "#{is_negate}#{is}" == "#{should_negate}#{should}" end end newproperty(:gid, :required_features => :owner) do desc <<-EOS GID or Group owner matching rule. Accepts a string argument only, as iptables does not accept multiple gid in a single statement. EOS end # match mark newproperty(:match_mark, :required_features => :mark) do desc <<-EOS 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. EOS 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? or (mark and match[2] and 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 <<-EOS 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. EOS 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? or (mark and match[2] and 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 and 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 <<-EOS Sets the clamp mss to pmtu flag. EOS newvalues(:true, :false) end newproperty(:set_dscp, :required_features => :iptables) do desc <<-EOS Set DSCP Markings. EOS end newproperty(:set_dscp_class, :required_features => :iptables) do desc <<-EOS This sets the DSCP field according to a predefined DiffServ class. EOS # 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 = [ '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 <<-EOS Sets the TCP MSS value for packets. EOS end newproperty(:pkttype, :required_features => :pkttype) do desc <<-EOS Sets the packet type to match. EOS newvalues(:unicast, :broadcast, :multicast) end newproperty(:isfragment, :required_features => :isfragment) do desc <<-EOS Set to true to match tcp fragments (requires type to be set to tcp) EOS newvalues(:true, :false) end newproperty(:recent, :required_features => :recent_limiting) do desc <<-EOS 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', } EOS newvalues(:set, :update, :rcheck, :remove) munge do |value| value = "--" + value end end newproperty(:rdest, :required_features => :recent_limiting) do desc <<-EOS Recent module; add the destination IP address to the list. Must be boolean true. EOS newvalues(:true, :false) end newproperty(:rsource, :required_features => :recent_limiting) do desc <<-EOS Recent module; add the source IP address to the list. Must be boolean true. EOS newvalues(:true, :false) end newproperty(:rname, :required_features => :recent_limiting) do desc <<-EOS Recent module; The name of the list. Takes a string argument. EOS end newproperty(:rseconds, :required_features => :recent_limiting) do desc <<-EOS 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. EOS end newproperty(:reap, :required_features => :recent_limiting) do desc <<-EOS 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. EOS newvalues(:true, :false) end newproperty(:rhitcount, :required_features => :recent_limiting) do desc <<-EOS 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. EOS end newproperty(:rttl, :required_features => :recent_limiting) do desc <<-EOS 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. EOS newvalues(:true, :false) end newproperty(:socket, :required_features => :socket) do desc <<-EOS If true, matches if an open socket can be found by doing a coket lookup on the packet. EOS newvalues(:true, :false) end newproperty(:ishasmorefrags, :required_features => :ishasmorefrags) do desc <<-EOS If true, matches if the packet has it's 'more fragments' bit set. ipv6. EOS newvalues(:true, :false) end newproperty(:islastfrag, :required_features => :islastfrag) do desc <<-EOS If true, matches if the packet is the last fragment. ipv6. EOS newvalues(:true, :false) end newproperty(:isfirstfrag, :required_features => :isfirstfrag) do desc <<-EOS If true, matches if the packet is the first fragment. Sadly cannot be negated. ipv6. EOS newvalues(:true, :false) end newproperty(:ipsec_policy, :required_features => :ipsec_policy) do desc <<-EOS 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. EOS newvalues(:none, :ipsec) end newproperty(:ipsec_dir, :required_features => :ipsec_dir) do desc <<-EOS Sets the ipsec policy direction EOS newvalues(:in, :out) end newproperty(:stat_mode) do desc <<-EOS Set the matching mode for statistic matching. Supported modes are `random` and `nth`. EOS newvalues(:nth, :random) end newproperty(:stat_every) do desc <<-EOS Match one packet every nth packet. Requires `stat_mode => 'nth'` EOS validate do |value| unless value =~ /^\d+$/ raise ArgumentError, <<-EOS stat_every value must be a digit EOS end unless value.to_i > 0 raise ArgumentError, <<-EOS stat_every value must be larger than 0 EOS end end end newproperty(:stat_packet) do desc <<-EOS 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'` EOS newvalues(/^\d+$/) end newproperty(:stat_probability) do desc <<-EOS Set the probability from 0 to 1 for a packet to be randomly matched. It works only with `stat_mode => 'random'`. EOS validate do |value| unless value =~ /^([01])\.(\d+)$/ raise ArgumentError, <<-EOS stat_probability must be between 0.0 and 1.0 EOS end if $1.to_i == 1 && $2.to_i != 0 raise ArgumentError, <<-EOS start_probability must be between 0.0 and 1.0 EOS end end end newproperty(:mask, :required_features => :mask) do desc <<-EOS Sets the mask to use when `recent` is enabled. EOS end newproperty(:gateway, :required_features => :iptables) do desc <<-EOS 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. EOS end newproperty(:ipset, :required_features => :ipset) do desc <<-EOS Matches against the specified ipset list. Requires ipset kernel module. The value is the name of the blacklist, followed by a space, and then 'src' and/or 'dst' separated by a comma. For example: 'blacklist src,dst' EOS end newproperty(:checksum_fill, :required_features => :iptables) do desc <<-EOS Compute and fill missing packet checksums. EOS newvalues(:true, :false) end newparam(:line) do desc <<-EOS Read-only property for caching the rule line. EOS end newproperty(:mac_source) do desc <<-EOS MAC Source EOS newvalues(/^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$/i) end newproperty(:physdev_in, :required_features => :iptables) do desc <<-EOS Match if the packet is entering a bridge from the given interface. EOS newvalues(/^[a-zA-Z0-9\-\._\+]+$/) end newproperty(:physdev_out, :required_features => :iptables) do desc <<-EOS Match if the packet is leaving a bridge via the given interface. EOS newvalues(/^[a-zA-Z0-9\-\._\+]+$/) end newproperty(:physdev_is_bridged, :required_features => :iptables) do desc <<-EOS Match if the packet is transversing a bridge. EOS newvalues(:true, :false) end newproperty(:date_start, :required_features => :iptables) do desc <<-EOS Only match during the given time, which must be in ISO 8601 "T" notation. The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 EOS end newproperty(:date_stop, :required_features => :iptables) do desc <<-EOS Only match during the given time, which must be in ISO 8601 "T" notation. The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07 EOS end newproperty(:time_start, :required_features => :iptables) do desc <<-EOS Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. EOS munge do |value| if value =~ /^([0-9]):/ value = "0#{value}" end if value =~ /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/ value = "#{value}:00" end value end end newproperty(:time_stop, :required_features => :iptables) do desc <<-EOS Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. EOS munge do |value| if value =~ /^([0-9]):/ value = "0#{value}" end if value =~ /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/ value = "#{value}:00" end value end end newproperty(:month_days, :required_features => :iptables) do desc <<-EOS Only match on the given days of the month. Possible values are 1 to 31. Note that specifying 31 will of course not match on months which do not have a 31st day; the same goes for 28- or 29-day February. EOS validate do |value| month = value.to_i if month >= 1 and month <=31 value else raise ArgumentError, "month_days must be in the range of 1-31" end end end newproperty(:week_days, :required_features => :iptables) do desc <<-EOS Only match on the given weekdays. Possible values are Mon, Tue, Wed, Thu, Fri, Sat, Sun. EOS newvalues(:Mon, :Tue, :Wed, :Thu, :Fri, :Sat, :Sun) end newproperty(:time_contiguous, :required_features => :iptables) do desc <<-EOS When time_stop is smaller than time_start value, match this as a single time period instead distinct intervals. EOS newvalues(:true, :false) end newproperty(:kernel_timezone, :required_features => :iptables) do desc <<-EOS Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations. EOS newvalues(:true, :false) end newproperty(:clusterip_new, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Create a new ClusterIP. You always have to set this on the first rule for a given ClusterIP. EOS newvalues(:true, :false) end newproperty(:clusterip_hashmode, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Specify the hashing mode. Valid values: sourceip, sourceip-sourceport, sourceip-sourceport-destport. EOS newvalues(:sourceip, :'sourceip-sourceport', :'sourceip-sourceport-destport') end newproperty(:clusterip_clustermac, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Specify the ClusterIP MAC address. Has to be a link-layer multicast address. EOS newvalues(/^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$/i) end newproperty(:clusterip_total_nodes, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Number of total nodes within this cluster. EOS newvalues(/\d+/) end newproperty(:clusterip_local_node, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Specify the random seed used for hash initialization. EOS newvalues(/\d+/) end newproperty(:clusterip_hash_init, :required_features => :clusterip) do desc <<-EOS Used with the CLUSTERIP jump target. Specify the random seed used for hash initialization. EOS 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? || (['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 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. if ! value(:ensure) return end # First we make sure the chains and tables are valid combinations if value(:table).to_s == "filter" && value(:chain) =~ /PREROUTING|POSTROUTING/ self.fail "PREROUTING and POSTROUTING cannot be used in table 'filter'" end if value(:table).to_s == "nat" && value(:chain) =~ /INPUT|FORWARD/ self.fail "INPUT and FORWARD cannot be used in table 'nat'" end if value(:table).to_s == "raw" && value(:chain) =~ /INPUT|FORWARD|POSTROUTING/ self.fail "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 =~ /OUTPUT|POSTROUTING/ self.fail "Parameter uid only applies to chains " \ "OUTPUT,POSTROUTING" end end if value(:gid) unless value(:chain).to_s =~ /OUTPUT|POSTROUTING/ self.fail "Parameter gid only applies to chains " \ "OUTPUT,POSTROUTING" end end if value(:set_mark) unless value(:jump).to_s =~ /MARK/ && value(:table).to_s =~ /mangle/ self.fail "Parameter set_mark only applies to " \ "the mangle table and when jump => MARK" end end if value(:dport) unless value(:proto).to_s =~ /tcp|udp|sctp/ self.fail "[%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) self.fail "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) self.fail "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) self.fail "When using jump => TEE, the gateway property is required" end end if value(:jump).to_s == "DNAT" unless value(:table).to_s =~ /nat/ self.fail "Parameter jump => DNAT only applies to table => nat" end unless value(:todest) self.fail "Parameter jump => DNAT must have todest parameter" end end if value(:jump).to_s == "SNAT" unless value(:table).to_s =~ /nat/ self.fail "Parameter jump => SNAT only applies to table => nat" end unless value(:tosource) self.fail "Parameter jump => SNAT must have tosource parameter" end end if value(:jump).to_s == "MASQUERADE" unless value(:table).to_s =~ /nat/ self.fail "Parameter jump => MASQUERADE only applies to table => nat" end end if value(:log_prefix) || value(:log_level) unless value(:jump).to_s == "LOG" self.fail "Parameter log_prefix and log_level require jump => LOG" end end if value(:burst) && ! value(:limit) self.fail "burst makes no sense without limit" end if value(:action) && value(:jump) self.fail "Only one of the parameters 'action' and 'jump' can be set" end if value(:connlimit_mask) && ! value(:connlimit_above) self.fail "Parameter 'connlimit_mask' requires 'connlimit_above'" end if value(:mask) && ! value(:recent) self.fail "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) self.fail "Parameter '#{param.to_s}' requires 'stat_mode' to be set" end end if value(:stat_packet) && value(:stat_mode) != :nth self.fail "Parameter 'stat_packet' requires 'stat_mode' to be set to 'nth'" end if value(:stat_every) && value(:stat_mode) != :nth self.fail "Parameter 'stat_every' requires 'stat_mode' to be set to 'nth'" end if value(:stat_probability) && value(:stat_mode) != :random self.fail "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" self.fail "Parameter checksum_fill requires jump => CHECKSUM and table => mangle" end end end end puppetlabs-firewall-1.7.1/lib/puppet/type/firewallchain.rb000644 000765 000024 00000017651 12567120562 023511 0ustar00tpstaff000000 000000 # 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 = <<-EOS 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. EOS 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 <<-EOS The canonical name of the chain. For iptables the format must be {chain}:{table}:{protocol}. EOS isnamevar validate do |value| if value !~ Nameformat then raise ArgumentError, "Inbuilt chains must be in the form {chain}:{table}:{protocol} where {table} is one of FILTER, NAT, MANGLE, RAW, RAWPOST, BROUTE 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:'#{$1}' chain:'#{$2}' protocol:'#{$3}'" else chain = $1 table = $2 protocol = $3 case table when 'filter' if chain =~ /^(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 =~ InternalChains && 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 =~ /^(BROUTING|FORWARD)$/ raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, and OUTPUT are the only inbuilt chains that can be used in table 'nat'" end if protocol =~/^(IP(v6)?)?$/ raise ArgumentError, "table nat isn't valid in IPv6. You must specify ':IPv4' as the name suffix" end when 'raw' if chain =~ /^(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 =~ /^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$/ raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'broute\'' 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 <<-EOS 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 EOS newvalues(:accept, :drop, :queue, :return) defaultto do # ethernet chain have an ACCEPT default while other haven't got an # allowed value if @resource[:name] =~ /:ethernet$/ :accept else nil end end end newparam(:purge, :boolean => true) do desc <<-EOS Purge unmanaged firewall rules in this chain EOS newvalues(:false, :true) defaultto :false end newparam(:ignore) do desc <<-EOS 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 ], } EOS validate do |value| unless value.is_a?(Array) or value.is_a?(String) or value == false self.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(Nameformat) chain = $1 table = $2 protocol = $3 # Check that we're not removing an internal chain if chain =~ InternalChains && value(:ensure) == :absent self.fail "Cannot remove in-built chains" end if value(:policy).nil? && protocol == 'ethernet' self.fail "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 !~ InternalChains && !value(:policy).nil? && protocol != 'ethernet' self.fail "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 self.fail 'The "nat" table is not intended for filtering, the use of DROP is therefore inhibited' end end def generate return [] unless self.purge? value(:name).match(Nameformat) chain = $1 table = $2 protocol = $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 or res.provider.properties[:table].to_s != table or 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.7.1/lib/puppet/provider/firewall/000755 000765 000024 00000000000 12567122052 023014 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/provider/firewall.rb000644 000765 000024 00000002010 12567120562 023336 0ustar00tpstaff000000 000000 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| if resource = resources[prov.name] || resources[prov.name.downcase] 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 == self.name or instance.name.downcase == self.name return instance.properties end end nil end end puppetlabs-firewall-1.7.1/lib/puppet/provider/firewallchain/000755 000765 000024 00000000000 12567122052 024017 5ustar00tpstaff000000 000000 puppetlabs-firewall-1.7.1/lib/puppet/provider/firewallchain/iptables_chain.rb000644 000765 000024 00000011603 12567120562 027316 0ustar00tpstaff000000 000000 Puppet::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 => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/, }, :IPv6 => { :tables => method(:ip6tables), :save => method(:ip6tables_save), :re => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/, }, :ethernet => { :tables => method(:ebtables), :save => method(:ebtables_save), :re => /^:(.+)\s(\S+)$/, } } InternalChains = /^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$/ Tables = 'nat|mangle|filter|raw|rawpost|broute' Nameformat = /^(.+):(#{Tables}):(IP(v[46])?|ethernet)$/ def create allvalidchains do |t, chain, table, protocol| if chain =~ InternalChains # 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 =~ InternalChains # 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 =~ InternalChains # 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}" return @property_hash[:policy].to_s.downcase end def self.prefetch(resources) debug("[prefetch(resources)]") instances.each do |prov| if resource = resources[prov.name] resource.provider = prov end end end def flush debug("[flush]") persist_iptables(@resource[:name].match(Nameformat)[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 == self.name debug "query found #{self.name}" % instance.properties.inspect return instance.properties end end nil end def self.instances debug "[instances]" table = nil chains = [] Mapping.each { |p, c| begin c[:save].call.each_line do |line| if line =~ c[:re] then name = $1 + ':' + (table == 'filter' ? 'filter' : table) + ':' + p.to_s policy = $2 == '-' ? nil : $2.downcase.to_sym chains << new({ :name => name, :policy => policy, :ensure => :present, }) debug "[instance] '#{name}' #{policy}" elsif line =~ /^\*(\S+)/ table = $1 else next end end rescue Puppet::Error # ignore command not found for ebtables or anything that doesn't exist end } chains end def allvalidchains @resource[:name].match(Nameformat) chain = $1 table = $2 protocol = $3 yield Mapping[protocol.to_sym][:tables],chain,table,protocol.to_sym end end puppetlabs-firewall-1.7.1/lib/puppet/provider/firewall/ip6tables.rb000644 000765 000024 00000020503 12567120562 025236 0ustar00tpstaff000000 000000 Puppet::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 :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 optional_commands({ :ip6tables => 'ip6tables', :ip6tables_save => 'ip6tables-save', }) confine :kernel => :linux ip6tables_version = Facter.value('ip6tables_version') if (ip6tables_version and Puppet::Util::Package.versioncmp(ip6tables_version, '1.4.1') < 0) mark_flag = '--set-mark' else mark_flag = '--set-xmark' end def initialize(*args) ip6tables_version = Facter.value('ip6tables_version') if ip6tables_version and ip6tables_version.match /1\.3\.\d/ raise ArgumentError, 'The ip6tables provider is not supported on version 1.3 of iptables' else super end 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", :limit => "-m limit --limit", :log_level => "--log-level", :log_prefix => "--log-prefix", :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", :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", :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", :date_start => "--datestart", :date_stop => "--datestop", :time_start => "--timestart", :time_stop => "--timestop", :month_days => "--monthdays", :week_days => "--weekdays", :time_contiguous => "--contiguous", :kernel_timezone => "--kerneltz", } # These are known booleans that do not take a value, but we want to munge # to true if they exist. @known_booleans = [ :checksum_fill, :clamp_mss_to_pmtu, :ishasmorefrags, :islastfrag, :isfirstfrag, :rsource, :rdest, :reap, :rttl, :socket, :physdev_is_bridged, :time_contiguous, :kernel_timezone, ] # 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], :addrtype => [:src_type, :dst_type], :iprange => [:src_range, :dst_range], :owner => [:uid, :gid], :time => [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone] } # Create property methods dynamically (@resource_map.keys << :chain << :table << :action).each do |property| if @known_booleans.include?(property) then # The boolean properties default to '' which should be read as false define_method "#{property}" do @property_hash[property] = :false if @property_hash[property] == nil @property_hash[property.to_sym] end else define_method "#{property}" 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, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type, :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state, :ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :clamp_mss_to_pmtu, :gateway, :todest, :tosource, :toports, :checksum_fill, :log_level, :log_prefix, :reject, :set_mss, :set_dscp, :set_dscp_class, :mss, :set_mark, :match_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone] end puppetlabs-firewall-1.7.1/lib/puppet/provider/firewall/iptables.rb000644 000765 000024 00000060767 12567120562 025170 0ustar00tpstaff000000 000000 require '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 :mark has_feature :mss 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 optional_commands({ :iptables => 'iptables', :iptables_save => 'iptables-save', }) defaultfor :kernel => :linux confine :kernel => :linux iptables_version = Facter.value('iptables_version') if (iptables_version and Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') < 0) mark_flag = '--set-mark' else mark_flag = '--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", :limit => "-m limit --limit", :log_level => "--log-level", :log_prefix => "--log-prefix", :mac_source => ["-m mac --mac-source", "--mac-source"], :mask => '--mask', :match_mark => "-m mark --mark", :mss => '-m tcpmss --mss', :name => "-m comment --comment", :outiface => "-o", :pkttype => "-m pkttype --pkt-type", :port => '-m multiport --ports', :proto => "-p", :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", :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", :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", } # 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, :random, :rdest, :reap, :rsource, :rttl, :socket, :physdev_is_bridged, :time_contiguous, :kernel_timezone, :clusterip_new, ] # 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], :addrtype => [:src_type, :dst_type], :iprange => [:src_range, :dst_range], :owner => [:uid, :gid], :time => [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone] } def self.munge_resource_map_from_existing_values(resource_map_original, compare) resource_map_new = resource_map_original.clone @module_to_argument_mapping.each do |ipt_module, arg_array| arg_array.each do |argument| if resource_map_original[argument].is_a?(Array) if compare.include?(resource_map_original[argument].first) resource_map_new[argument] = resource_map_original[argument].clone resource_map_new[argument][0] = "-m #{ipt_module.to_s} #{resource_map_original[argument].first}" break end else if compare.include?(resource_map_original[argument]) resource_map_new[argument] = "-m #{ipt_module.to_s} #{resource_map_original[argument]}" break end end end end resource_map_new end def munge_resource_map_from_resource(resource_map_original, compare) resource_map_new = resource_map_original.clone module_to_argument_mapping = self.class.instance_variable_get('@module_to_argument_mapping') module_to_argument_mapping.each do |ipt_module, arg_array| arg_array.each do |argument| if compare[argument] if resource_map_original[argument].is_a?(Array) resource_map_new[argument] = resource_map_original[argument].clone resource_map_new[argument][0] = "-m #{ipt_module.to_s} #{resource_map_original[argument].first}" else resource_map_new[argument] = "-m #{ipt_module.to_s} #{resource_map_original[argument]}" end break end end end resource_map_new end # Create property methods dynamically (@resource_map.keys << :chain << :table << :action).each do |property| if @known_booleans.include?(property) then # The boolean properties default to '' which should be read as false define_method "#{property}" do @property_hash[property] = :false if @property_hash[property] == nil @property_hash[property.to_sym] end else define_method "#{property}" 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, :proto, :isfragment, :stat_mode, :stat_every, :stat_packet, :stat_probability, :src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type, :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :clusterip_new, :clusterip_hashmode, :clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init, :clamp_mss_to_pmtu, :gateway, :set_mss, :set_dscp, :set_dscp_class, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix, :log_level, :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 ] 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] iptables delete_args 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 =~ /^\#\s+|^\:\S+|^COMMIT|^FATAL/ if line =~ /^\*/ table = line.sub(/\*/, "") else if hash = rule_to_hash(line, table, counter) 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 #################### # --tcp-flags takes two values; we cheat by adding " around it # so it behaves like --comment values = values.gsub(/(!\s+)?--tcp-flags (\S*) (\S*)/, '--tcp-flags "\1\2 \3"') # ditto for --match-set values = values.sub(/(!\s+)?--match-set (\S*) (\S*)/, '--match-set "\1\2 \3"') # we do a similar thing for negated address masks (source and destination). values = values.gsub(/(-\S+) (!)\s?(\S*)/,'\1 "\2 \3"') # the actual rule will have the ! mark before the option. values = values.gsub(/(!)\s*(-\S+)\s*(\S*)/, '\2 "\1 \3"') # The match extension for tcp & udp are optional and throws off the @resource_map. values = values.gsub(/(?!-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(/\s{2}--physdev/, ' --physdev') # '--pol ipsec' takes many optional arguments; we cheat again by adding " around them values = values.sub(/ --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" ' ) 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 if bool == :isfragment then # -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 = values.sub(/-f(?!l)(?=.*--comment)/, '-f true') else values = values.sub(/#{resource_map[bool]}/, "#{resource_map[bool]} true") end end ############ # Populate parser_list with used value, in the correct order ############ map_index={} resource_map.each_pair do |map_k,map_v| [map_v].flatten.each do |v| ind=values.index(/\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!(/\s#{opt}/) keys << k break end end end # Manually remove chain values.slice!('-A') keys << :chain # Here we generate the main hash by scanning arguments off the values # string, handling any quoted characters present in the value, and then # zipping the values with the array of keys. keys.zip(values.scan(/("([^"\\]|\\.)*"|\S+)/).transpose[0].reverse) do |f, v| if v =~ /^".*"$/ then hash[f] = v.sub(/^"(.*)"$/, '\1').gsub(/\\(\\|'|")/, '\1') else hash[f] = v.dup end end ##################### # POST PARSE CLUDGING ##################### [:dport, :sport, :port, :state, :ctstate].each do |prop| hash[prop] = hash[prop].split(',') if ! hash[prop].nil? end ## clean up DSCP class to HEX mappings 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| if hash[bool] != nil then if hash[bool] != "true" then raise "Parser error: #{bool} was meant to be a boolean but received value: #{hash[bool]}." end 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].collect do |elem| elem.gsub(/:/,'-') end end # Invert any rules that are prefixed with a '!' [ :connmark, :ctstate, :destination, :dport, :dst_range, :dst_type, :ipset, :port, :proto, :source, :sport, :src_range, :src_type, :state, ].each do |prop| if hash[prop] and hash[prop].is_a?(Array) # find if any are negated, then negate all if so should_negate = hash[prop].index do |value| value.match(/^(!)\s+/) end hash[prop] = hash[prop].collect { |v| "! #{v.sub(/^!\s+/,'')}" } if should_negate elsif hash[prop] m = hash[prop].match(/^(!?)\s?(.*)/) neg = "! " if m[1] == "!" if [:source,:destination].include?(prop) # Normalise all rules to CIDR notation. hash[prop] = "#{neg}#{Puppet::Util::IPCidr.new(m[2]).cidr}" else hash[prop] = "#{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 /^\d+[[:graph:][:space:]]+$/ =~ hash[:name] num = 9000 + counter hash[:name] = "#{num} #{/([[: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] = self.name.to_s hash[:table] = table hash[:ensure] = :present # Munge some vars here ... # Proto should equal 'all' if undefined hash[:proto] = "all" if !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 ['ACCEPT','REJECT','DROP'].include?(hash[:jump]) then 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(/^\-A /, '-D ').split(/\s(?=(?:[^"]|"[^"]*")*$)/).map{|v| v.gsub(/"/, '')} 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) resource_list.each do |res| resource_value = nil if (resource[res]) then resource_value = resource[res] # If socket is true then do not add the value as -m socket is standalone if known_booleans.include?(res) then if resource[res] == :true then resource_value = nil else # If the property is not :true then we don't want to add the value # to the args list next end end elsif res == :jump and resource[:action] then # 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) and resource_value.sub!(/^!\s*/, '') then # 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) and resource_value.to_s.match(/^!/) then #ruby 1.8.7 can't .match Symbols ------------------ ^ resource_value = resource_value.to_s.sub!(/^!\s*/, '').to_sym args.insert(-2, '!') elsif resource_value.is_a?(Array) should_negate = resource_value.index do |value| #ruby 1.8.7 can't .match symbols value.to_s.match(/^(!)\s+/) end if should_negate resource_value, wrong_values = resource_value.collect do |value| if value.is_a?(String) wrong = value if ! value.match(/^!\s+/) [value.sub(/^!\s*/, ''),wrong] else [value,nil] end end.transpose wrong_values = wrong_values.compact if ! wrong_values.empty? fail "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" end args.insert(-2, '!') 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) then resource_value = resource_value.collect do |elem| elem.gsub(/-/, ':') end end # our tcp_flags takes a single string with comma lists separated # by space # --tcp-flags expects two arguments if res == :tcp_flags or res == :ipset 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 and 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 = /^9[0-9]{3}\s[a-f0-9]{32}$/ # 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) if new_rule_location == 0 # The rule will be the first rule in the chain because nothing came # before it. offset_rule = rules[0] else # This rule will come after other managed rules, so find the rule # immediately preceeding it. offset_rule = 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)].inject(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) and ! my_rule.match(/^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.7.1/lib/facter/ip6tables_version.rb000644 000765 000024 00000000354 12567120562 023275 0ustar00tpstaff000000 000000 Facter.add(:ip6tables_version) do confine :kernel => :linux setcode do version = Facter::Util::Resolution.exec('ip6tables --version') if version version.match(/\d+\.\d+\.\d+/).to_s else nil end end end puppetlabs-firewall-1.7.1/lib/facter/iptables_persistent_version.rb000644 000765 000024 00000001454 12567120562 025471 0ustar00tpstaff000000 000000 Facter.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) if (os == 'Debian' and (Puppet::Util::Package.versioncmp(os_release, '8.0') >= 0)) or (os == 'Ubuntu' and (Puppet::Util::Package.versioncmp(os_release, '14.10') >= 0)) cmd = "dpkg-query -Wf '${Version}' netfilter-persistent 2>/dev/null" else cmd = "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" end version = Facter::Util::Resolution.exec(cmd) if version.nil? or !version.match(/\d+\.\d+/) nil else version end end end puppetlabs-firewall-1.7.1/lib/facter/iptables_version.rb000644 000765 000024 00000000352 12567120562 023205 0ustar00tpstaff000000 000000 Facter.add(:iptables_version) do confine :kernel => :linux setcode do version = Facter::Util::Resolution.exec('iptables --version') if version version.match(/\d+\.\d+\.\d+/).to_s else nil end end end