changeset 398:66c406eec60d

Update and fix firewall for Ubuntu * Use later version of module (not latest because our Puppet isn't supported) * Change how we define "ensure" because Ubuntu doesn't use IPv6 methods
author IBBoard <dev@ibboard.co.uk>
date Wed, 20 Apr 2022 19:04:13 +0100
parents e22eee1d79ef
children 2c6065b5be5e
files modules/firewall/CHANGELOG.md modules/firewall/CONTRIBUTING.md modules/firewall/HISTORY.md modules/firewall/NOTICE modules/firewall/README.md modules/firewall/REFERENCE.md modules/firewall/lib/facter/ip6tables_version.rb modules/firewall/lib/facter/iptables_persistent_version.rb modules/firewall/lib/facter/iptables_version.rb modules/firewall/lib/puppet/provider/firewall.rb modules/firewall/lib/puppet/provider/firewall/ip6tables.rb modules/firewall/lib/puppet/provider/firewall/iptables.rb modules/firewall/lib/puppet/provider/firewallchain/iptables_chain.rb modules/firewall/lib/puppet/type/firewall.rb modules/firewall/lib/puppet/type/firewallchain.rb modules/firewall/lib/puppet/util/firewall.rb modules/firewall/lib/puppet/util/ipcidr.rb modules/firewall/manifests/init.pp modules/firewall/manifests/linux.pp modules/firewall/manifests/linux/archlinux.pp modules/firewall/manifests/linux/debian.pp modules/firewall/manifests/linux/gentoo.pp modules/firewall/manifests/linux/redhat.pp modules/firewall/manifests/params.pp modules/firewall/metadata.json modules/firewall/provision.yaml modules/my_fw/manifests/init.pp
diffstat 27 files changed, 423 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/modules/firewall/CHANGELOG.md	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/CHANGELOG.md	Wed Apr 20 19:04:13 2022 +0100
@@ -2,6 +2,48 @@
 
 All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).
 
+## [v2.8.1](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.8.1) (2021-02-08)
+
+[Full Changelog](https://github.com/puppetlabs/puppetlabs-firewall/compare/v2.8.0...v2.8.1)
+
+### Fixed
+
+- \[MODULES-10907\] Do not remove spaces from hex string with ! [\#967](https://github.com/puppetlabs/puppetlabs-firewall/pull/967) ([adrianiurca](https://github.com/adrianiurca))
+
+## [v2.8.0](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.8.0) (2020-12-14)
+
+[Full Changelog](https://github.com/puppetlabs/puppetlabs-firewall/compare/v2.7.0...v2.8.0)
+
+### Added
+
+- pdksync - \(feat\) - Add support for Puppet 7 [\#959](https://github.com/puppetlabs/puppetlabs-firewall/pull/959) ([daianamezdrea](https://github.com/daianamezdrea))
+- \(IAC-966\) - MODULES-10522: Add support for the --condition parameter [\#941](https://github.com/puppetlabs/puppetlabs-firewall/pull/941) ([adrianiurca](https://github.com/adrianiurca))
+
+### Fixed
+
+- Restore copyright names [\#951](https://github.com/puppetlabs/puppetlabs-firewall/pull/951) ([hunner](https://github.com/hunner))
+
+## [v2.7.0](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.7.0) (2020-10-15)
+
+[Full Changelog](https://github.com/puppetlabs/puppetlabs-firewall/compare/v2.6.0...v2.7.0)
+
+### Added
+
+- \(IAC-1190\) add `ignore\_foreign` when purging firewallchains [\#948](https://github.com/puppetlabs/puppetlabs-firewall/pull/948) ([DavidS](https://github.com/DavidS))
+
+## [v2.6.0](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.6.0) (2020-10-01)
+
+[Full Changelog](https://github.com/puppetlabs/puppetlabs-firewall/compare/v2.5.0...v2.6.0)
+
+### Added
+
+- pdksync - \(IAC-973\) - Update travis/appveyor to run on new default branch main [\#933](https://github.com/puppetlabs/puppetlabs-firewall/pull/933) ([david22swan](https://github.com/david22swan))
+
+### Fixed
+
+- Fix extra quotes in firewall string matching [\#944](https://github.com/puppetlabs/puppetlabs-firewall/pull/944) ([IBBoard](https://github.com/IBBoard))
+- \(IAC-987\) - Removal of inappropriate terminology [\#942](https://github.com/puppetlabs/puppetlabs-firewall/pull/942) ([david22swan](https://github.com/david22swan))
+
 ## [v2.5.0](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.5.0) (2020-07-28)
 
 [Full Changelog](https://github.com/puppetlabs/puppetlabs-firewall/compare/v2.4.0...v2.5.0)
@@ -40,7 +82,6 @@
 ### Fixed
 
 - \(maint\) Use fact.flush only when available [\#906](https://github.com/puppetlabs/puppetlabs-firewall/pull/906) ([Filipovici-Andrei](https://github.com/Filipovici-Andrei))
-- \(MODULES-10358\) - Clarification added to Boolean validation checks [\#886](https://github.com/puppetlabs/puppetlabs-firewall/pull/886) ([david22swan](https://github.com/david22swan))
 - Merge and remove duplicate README file, lint code snippets [\#878](https://github.com/puppetlabs/puppetlabs-firewall/pull/878) ([runejuhl](https://github.com/runejuhl))
 
 ## [v2.2.0](https://github.com/puppetlabs/puppetlabs-firewall/tree/v2.2.0) (2019-12-09)
@@ -56,6 +97,7 @@
 
 ### Fixed
 
+- \(MODULES-10358\) - Clarification added to Boolean validation checks [\#886](https://github.com/puppetlabs/puppetlabs-firewall/pull/886) ([david22swan](https://github.com/david22swan))
 - Change - Avoid puppet failures on windows nodes [\#874](https://github.com/puppetlabs/puppetlabs-firewall/pull/874) ([blackknight36](https://github.com/blackknight36))
 - Fix parsing iptables rules with hyphen in comments [\#861](https://github.com/puppetlabs/puppetlabs-firewall/pull/861) ([Hexta](https://github.com/Hexta))
 
@@ -830,7 +872,7 @@
 
 ##### Changes
 
-* (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppetmaster
+* (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppet server
 * (#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
@@ -857,4 +899,4 @@
 \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
 
 
-\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
+\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
--- a/modules/firewall/CONTRIBUTING.md	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/CONTRIBUTING.md	Wed Apr 20 19:04:13 2022 +0100
@@ -108,7 +108,7 @@
 
       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".
+      directly on "main".
       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.
--- a/modules/firewall/HISTORY.md	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/HISTORY.md	Wed Apr 20 19:04:13 2022 +0100
@@ -679,7 +679,7 @@
 
 ##### Changes
 
-* (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppetmaster
+* (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppet server
 * (#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
--- a/modules/firewall/NOTICE	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/NOTICE	Wed Apr 20 19:04:13 2022 +0100
@@ -1,6 +1,14 @@
 Puppet Module - puppetlabs-firewall
 
 Copyright 2018 Puppet, Inc.
+Copyright 2011 Jonathan Boyett
+Copyright 2011 Media Temple, Inc.
+
+Some of the iptables code was taken from puppet-iptables which was:
+
+Copyright 2011 Bob.sh Limited
+Copyright 2008 Camptocamp Association
+Copyright 2007 Dmitri Priimak
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -12,4 +20,4 @@
 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.
\ No newline at end of file
+limitations under the License.
--- a/modules/firewall/README.md	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/README.md	Wed Apr 20 19:04:13 2022 +0100
@@ -1,6 +1,6 @@
 # firewall
 
-[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-firewall.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-firewall)
+[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-firewall.png?branch=main)](https://travis-ci.org/puppetlabs/puppetlabs-firewall)
 
 #### Table of Contents
 
@@ -49,9 +49,9 @@
 
 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.
+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 server.
 
-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.
+The following steps are designed to ensure that you keep your SSH and other connections, primarily your connection to your Puppet server. 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
 
@@ -127,7 +127,28 @@
 
 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.
+1. Use the following code to set up the default parameters for all of the firewall rules that you will establish later. These defaults will ensure that the `pre` and `post` classes are run in the correct order and avoid locking you out of your box during the first Puppet run.
+
+```puppet
+Firewall {
+  before  => Class['my_fw::post'],
+  require => Class['my_fw::pre'],
+}
+```
+
+2. 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']: }
+```
+
+3. Include the `firewall` class to ensure the correct packages are installed:
+
+```puppet
+class { 'firewall': }
+```
+
+4. If you want to remove unmanaged firewall rules, add the following code to set up a metatype to purge unmanaged firewall resources in your site.pp or another top-scope file. This will clear any existing rules and make sure that only rules defined in Puppet exist on the machine.
 
 ```puppet
 resources { 'firewall':
@@ -168,28 +189,9 @@
 }
 ```
 
-  **Note** - If there are unmanaged rules in unmanaged chains, it will take two Puppet runs for the firewall chain to be 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 that you will establish later. These defaults will ensure that the `pre` and `post` classes are run in the correct order and avoid locking you out of your box during the first Puppet run.
-
-```puppet
-Firewall {
-  before  => Class['my_fw::post'],
-  require => Class['my_fw::pre'],
-}
-```
+> **Note:** If there are unmanaged rules in unmanaged chains, it will take a second Puppet run for the firewall chain to be purged.
 
-3. 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': }
-```
+> **Note:** If you need more fine-grained control about which unmananged rules get removed, investigate the `purge` and `ignore_foreign` parameters available in `firewallchain`.
 
 ### Upgrading
 
@@ -398,7 +400,7 @@
 
 ## Reference
 
-For information on the classes and types, see the [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-firewall/blob/master/REFERENCE.md). For information on the facts, see below.
+For information on the classes and types, see the [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-firewall/blob//REFERENCE.md). For information on the facts, see below.
 
 Facts:
 
@@ -420,7 +422,7 @@
 
 ## Limitations
 
-For an extensive list of supported operating systems, see [metadata.json](https://github.com/puppetlabs/puppetlabs-firewall/blob/master/metadata.json)
+For an extensive list of supported operating systems, see [metadata.json](https://github.com/puppetlabs/puppetlabs-firewall/blob/main/metadata.json)
 
 ### SLES
 
@@ -474,6 +476,20 @@
 * Use a cron job.
 * Click [Run Puppet](https://docs.puppet.com/pe/2016.1/console_classes_groups_running_puppet.html#run-puppet-on-an-individual-node) in the console.
 
+### condition parameter
+
+The `condition` parameter requires `xtables-addons` to be installed locally.
+For ubuntu distributions `xtables-addons-common` package can be installed by running command: `apt-get install xtables-addons-common` or
+running a manifest:
+
+```puppet
+package { 'xtables-addons-common':
+  ensure => 'latest',
+}
+```
+
+For other distributions (RedHat, Debian, Centos etc) manual installation of the `xtables-addons` package is required.
+
 #### Reporting Issues
 
 Please report any bugs in the Puppetlabs JIRA issue tracker:
--- a/modules/firewall/REFERENCE.md	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/REFERENCE.md	Wed Apr 20 19:04:13 2022 +0100
@@ -26,7 +26,7 @@
 
 ## Classes
 
-### `firewall`
+### <a name="firewall"></a>`firewall`
 
 Performs the basic setup tasks required for using the firewall resources.
 
@@ -45,9 +45,17 @@
 
 #### Parameters
 
-The following parameters are available in the `firewall` class.
+The following parameters are available in the `firewall` class:
 
-##### `ensure`
+* [`ensure`](#ensure)
+* [`ensure_v6`](#ensure_v6)
+* [`pkg_ensure`](#pkg_ensure)
+* [`service_name`](#service_name)
+* [`service_name_v6`](#service_name_v6)
+* [`package_name`](#package_name)
+* [`ebtables_manage`](#ebtables_manage)
+
+##### <a name="ensure"></a>`ensure`
 
 Data type: `Any`
 
@@ -55,7 +63,7 @@
 
 Default value: `running`
 
-##### `ensure_v6`
+##### <a name="ensure_v6"></a>`ensure_v6`
 
 Data type: `Any`
 
@@ -63,7 +71,7 @@
 
 Default value: ``undef``
 
-##### `pkg_ensure`
+##### <a name="pkg_ensure"></a>`pkg_ensure`
 
 Data type: `Any`
 
@@ -71,31 +79,31 @@
 
 Default value: `present`
 
-##### `service_name`
+##### <a name="service_name"></a>`service_name`
 
 Data type: `Any`
 
 Specify the name of the IPv4 iptables service.
 
-Default value: `$::firewall::params::service_name`
+Default value: `$firewall::params::service_name`
 
-##### `service_name_v6`
+##### <a name="service_name_v6"></a>`service_name_v6`
 
 Data type: `Any`
 
 Specify the name of the IPv6 iptables service.
 
-Default value: `$::firewall::params::service_name_v6`
+Default value: `$firewall::params::service_name_v6`
 
-##### `package_name`
+##### <a name="package_name"></a>`package_name`
 
 Data type: `Any`
 
 Specify the platform-specific package(s) to install.
 
-Default value: `$::firewall::params::package_name`
+Default value: `$firewall::params::package_name`
 
-##### `ebtables_manage`
+##### <a name="ebtables_manage"></a>`ebtables_manage`
 
 Data type: `Any`
 
@@ -105,7 +113,7 @@
 
 ## Resource types
 
-### `firewall`
+### <a name="firewall"></a>`firewall`
 
 **Autorequires:**
 
@@ -147,6 +155,8 @@
 
   * clusterip: Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them.
 
+  * condition: Match if a specific condition variable is (un)set (requires xtables-addons)
+
   * connection_limiting: Connection limiting features.
 
   * conntrack: Connection tracking features.
@@ -335,6 +345,10 @@
 Used with the CLUSTERIP jump target.
 Number of total nodes within this cluster.
 
+##### `condition`
+
+Match on boolean value (0/1) stored in /proc/net/nf_condition/name.
+
 ##### `connlimit_above`
 
 Valid values: `%r{^\d+$}`
@@ -1361,11 +1375,15 @@
 
 The following parameters are available in the `firewall` type.
 
-##### `line`
+* [`line`](#line)
+* [`name`](#name)
+* [`provider`](#provider)
+
+##### <a name="line"></a>`line`
 
 Read-only property for caching the rule line.
 
-##### `name`
+##### <a name="name"></a>`name`
 
 Valid values: `%r{^\d+[[:graph:][:space:]]+$}`
 
@@ -1380,12 +1398,12 @@
 Depending on the provider, the name of the rule can be stored using
 the comment feature of the underlying firewall subsystem.
 
-##### `provider`
+##### <a name="provider"></a>`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.
 
-### `firewallchain`
+### <a name="firewallchain"></a>`firewallchain`
 
 Currently this supports only iptables, ip6tables and ebtables on Linux. And
 provides support for setting the default policy on chains and tables that
@@ -1433,7 +1451,13 @@
 
 The following parameters are available in the `firewallchain` type.
 
-##### `ignore`
+* [`ignore`](#ignore)
+* [`ignore_foreign`](#ignore_foreign)
+* [`name`](#name)
+* [`provider`](#provider)
+* [`purge`](#purge)
+
+##### <a name="ignore"></a>`ignore`
 
 Regex to perform on firewall rules to exempt unmanaged rules from purging (when enabled).
 This is matched against the output of `iptables-save`.
@@ -1456,7 +1480,19 @@
 }
 ```
 
-##### `name`
+##### <a name="ignore_foreign"></a>`ignore_foreign`
+
+Valid values: ``false``, ``true``
+
+Ignore rules that do not match the puppet title pattern "^\d+[[:graph:][:space:]]" when purging unmanaged firewall rules
+in this chain.
+This can be used to ignore rules that were not put in by puppet. Beware that nothing keeps other systems from
+configuring firewall rules with a comment that starts with digits, and is indistinguishable from puppet-configured
+rules.
+
+Default value: ``false``
+
+##### <a name="name"></a>`name`
 
 namevar
 
@@ -1464,12 +1500,12 @@
 
 For iptables the format must be {chain}:{table}:{protocol}.
 
-##### `provider`
+##### <a name="provider"></a>`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.
 
-##### `purge`
+##### <a name="purge"></a>`purge`
 
 Valid values: ``false``, ``true``
 
--- a/modules/firewall/lib/facter/ip6tables_version.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/facter/ip6tables_version.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 Facter.add(:ip6tables_version) do
   confine kernel: :Linux
   setcode do
--- a/modules/firewall/lib/facter/iptables_persistent_version.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/facter/iptables_persistent_version.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 Facter.add(:iptables_persistent_version) do
   confine operatingsystem: ['Debian', 'Ubuntu']
   setcode do
--- a/modules/firewall/lib/facter/iptables_version.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/facter/iptables_version.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 Facter.add(:iptables_version) do
   confine kernel: :Linux
   setcode do
--- a/modules/firewall/lib/puppet/provider/firewall.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/provider/firewall.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 #
 # firewall.rb
 #
--- a/modules/firewall/lib/puppet/provider/firewall/ip6tables.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/provider/firewall/ip6tables.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,7 +1,10 @@
+# frozen_string_literal: true
+
 Puppet::Type.type(:firewall).provide :ip6tables, parent: :iptables, source: :ip6tables do
   @doc = 'Ip6tables type provider'
 
   has_feature :iptables
+  has_feature :condition
   has_feature :connection_limiting
   has_feature :conntrack
   has_feature :hop_limiting
@@ -65,7 +68,7 @@
 
   def initialize(*args)
     ip6tables_version = Facter.value('ip6tables_version')
-    raise ArgumentError, 'The ip6tables provider is not supported on version 1.3 of iptables' if ip6tables_version && ip6tables_version.match(%r{1\.3\.\d})
+    raise ArgumentError, 'The ip6tables provider is not supported on version 1.3 of iptables' if ip6tables_version&.match(%r{1\.3\.\d})
     super
   end
 
@@ -83,6 +86,7 @@
     burst: '--limit-burst',
     checksum_fill: '--checksum-fill',
     clamp_mss_to_pmtu: '--clamp-mss-to-pmtu',
+    condition: '--condition',
     connlimit_above: '-m connlimit --connlimit-above',
     connlimit_mask: '--connlimit-mask',
     connmark: '-m connmark --mark',
@@ -250,6 +254,7 @@
     addrtype: [:src_type, :dst_type],
     iprange: [:src_range, :dst_range],
     owner: [:uid, :gid],
+    condition: [:condition],
     conntrack: [:ctstate, :ctproto, :ctorigsrc, :ctorigdst, :ctreplsrc, :ctrepldst,
                 :ctorigsrcport, :ctorigdstport, :ctreplsrcport, :ctrepldstport, :ctstatus, :ctexpire, :ctdir],
     time: [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone],
@@ -308,5 +313,5 @@
                     :set_mark, :match_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone,
                     :src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst,
                     :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size,
-                    :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :bytecode, :zone, :helper, :rpfilter, :name, :notrack]
+                    :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :bytecode, :zone, :helper, :rpfilter, :condition, :name, :notrack]
 end
--- a/modules/firewall/lib/puppet/provider/firewall/iptables.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/provider/firewall/iptables.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'puppet/provider/firewall'
 require 'digest'
 
@@ -7,6 +9,7 @@
   @doc = 'Iptables type provider'
 
   has_feature :iptables
+  has_feature :condition
   has_feature :connection_limiting
   has_feature :conntrack
   has_feature :rate_limiting
@@ -75,6 +78,7 @@
     burst: '--limit-burst',
     checksum_fill: '--checksum-fill',
     clamp_mss_to_pmtu: '--clamp-mss-to-pmtu',
+    condition: '--condition',
     connlimit_above: '-m connlimit --connlimit-above',
     connlimit_mask: '--connlimit-mask',
     connmark: '-m connmark --mark',
@@ -252,6 +256,7 @@
     addrtype: [:src_type, :dst_type],
     iprange: [:src_range, :dst_range],
     owner: [:uid, :gid],
+    condition: [:condition],
     conntrack: [:ctstate, :ctproto, :ctorigsrc, :ctorigdst, :ctreplsrc, :ctrepldst,
                 :ctorigsrcport, :ctorigdstport, :ctreplsrcport, :ctrepldstport, :ctstatus, :ctexpire, :ctdir],
     time: [:time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone],
@@ -348,7 +353,7 @@
     :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone,
     :src_cc, :dst_cc, :hashlimit_upto, :hashlimit_above, :hashlimit_name, :hashlimit_burst,
     :hashlimit_mode, :hashlimit_srcmask, :hashlimit_dstmask, :hashlimit_htable_size,
-    :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :bytecode, :ipvs, :zone, :helper, :cgroup, :rpfilter, :name, :notrack
+    :hashlimit_htable_max, :hashlimit_htable_expire, :hashlimit_htable_gcinterval, :bytecode, :ipvs, :zone, :helper, :cgroup, :rpfilter, :condition, :name, :notrack
   ]
 
   def insert
@@ -373,14 +378,12 @@
       #
       # This tries deleting again with -p all to see if that helps.
       #
-      # rubocop:disable Lint/HandleExceptions
       if self.class.instance_variable_get(:@protocol) == 'IPv6' && properties[:proto] == 'all'
         begin
           iptables delete_args.concat(['-p', 'all'])
-        rescue Puppet::ExecutionFailure => e
+        rescue Puppet::ExecutionFailure => e # rubocop:disable Lint/SuppressedException
         end
       end
-      # rubocop:enable Lint/HandleExceptions
 
       # Check to see if the iptables rule is already gone. This can sometimes
       # happen as a side effect of other resource changes. If it's not gone,
@@ -421,8 +424,8 @@
     # String#lines would be nice, but we need to support Ruby 1.8.5
     nf_warning_msg = "# Warning: ip6?tables-legacy tables present, use ip6?tables-legacy-save to see them\n"
     iptables_save.gsub(%r{#{nf_warning_msg}}, '').split("\n").each do |line|
-      unless line =~ %r{^\#\s+|^\:\S+|^COMMIT|^FATAL}
-        if line =~ %r{^\*}
+      unless %r{^\#\s+|^\:\S+|^COMMIT|^FATAL}.match?(line)
+        if %r{^\*}.match?(line)
           table = line.sub(%r{\*}, '')
         else
           hash = rule_to_hash(line, table, counter)
@@ -452,8 +455,10 @@
     values = values.gsub(%r{(!\s+)?--tcp-flags (\S*) (\S*)}, '--tcp-flags "\1\2 \3"')
     # --hex-string output is in quotes, need to move ! inside quotes
     values = values.gsub(%r{(!\s+)?--hex-string "(\S*?)"}, '--hex-string "\1\2"')
+    # --condition output is in quotes, need to move ! inside quotes
+    values.gsub!(%r{(!\s+)?--condition "(\S*?)"}, '--condition "\1\2"')
     # --match-set can have multiple values with weird iptables format
-    if values =~ %r{-m set (!\s+)?--match-set}
+    if %r{-m set (!\s+)?--match-set}.match?(values)
       values = values.gsub(%r{(!\s+)?--match-set (\S*) (\S*)}, '--match-set \1\2 \3')
       ind  = values.index('-m set --match-set')
       sets = values.scan(%r{-m set --match-set ((?:!\s+)?\S* \S*)})
@@ -461,22 +466,22 @@
       values.insert(ind, "-m set --match-set \"#{sets.join(';')}\" ")
     end
     # --comment can have multiple values, the same as --match-set
-    if values =~ %r{-m comment --comment}
+    if %r{-m comment --comment}.match?(values)
       ind = values.index('-m comment --comment')
       comments = values.scan(%r{-m comment --comment "((?:\\"|[^"])*)"})
       comments += values.scan(%r{-m comment --comment ([^"\s]+)\b})
-      values = values.gsub(%r{-m comment --comment (".*?[^\\"]"|[^ ].*)( |$)}, '')
+      values = values.gsub(%r{-m comment --comment (".*?[^\\"]")( |$)}, '')
       values = values.gsub(%r{-m comment --comment ([^"].*?)[ $]}, '')
       values.insert(ind, "-m comment --comment \"#{comments.join(';')}\" ")
     end
-    if values =~ %r{-m addrtype (!\s+)?--src-type}
+    if %r{-m addrtype (!\s+)?--src-type}.match?(values)
       values = values.gsub(%r{(!\s+)?--src-type (\S*)(\s--limit-iface-(in|out))?}, '--src-type \1\2\3')
       ind = values.index('-m addrtype --src-type')
       types = values.scan(%r{-m addrtype --src-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?)})
       values = values.gsub(%r{-m addrtype --src-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?) ?}, '')
       values.insert(ind, "-m addrtype --src-type \"#{types.join(';')}\" ")
     end
-    if values =~ %r{-m addrtype (!\s+)?--dst-type}
+    if %r{-m addrtype (!\s+)?--dst-type}.match?(values)
       values = values.gsub(%r{(!\s+)?--dst-type (\S*)(\s--limit-iface-(in|out))?}, '--dst-type \1\2\3')
       ind = values.index('-m addrtype --dst-type')
       types = values.scan(%r{-m addrtype --dst-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?)})
@@ -548,7 +553,7 @@
     ############
 
     # Here we iterate across our values to generate an array of keys
-    parser_list.reverse.each do |k|
+    parser_list.reverse_each do |k|
       resource_map_key = resource_map[k]
       [resource_map_key].flatten.each do |opt|
         if values.slice!(%r{\s#{opt}})
@@ -559,13 +564,13 @@
     end
 
     # Manually remove chain
-    if values =~ %r{(\s|^)-A\s}
+    if %r{(\s|^)-A\s}.match?(values)
       values = values.sub(%r{(\s|^)-A\s}, '\1')
       keys << :chain
     end
 
     # Manually remove table (used in some tests)
-    if values =~ %r{^-t\s}
+    if %r{^-t\s}.match?(values)
       values = values.sub(%r{^-t\s}, '')
       keys << :table
     end
@@ -581,7 +586,7 @@
     # string, handling any quoted characters present in the value, and then
     # zipping the values with the array of keys.
     keys.zip(valrev) do |f, v|
-      hash[f] = if v =~ %r{^".*"$}
+      hash[f] = if %r{^".*"$}.match?(v)
                   v.sub(%r{^"(.*)"$}, '\1').gsub(%r{\\(\\|'|")}, '\1')
                 else
                   v.dup
@@ -646,13 +651,12 @@
         elem.tr(':', '-')
       end
     end
-    if hash[:length]
-      hash[:length].tr!(':', '-')
-    end
+    hash[:length]&.tr!(':', '-')
 
     # Invert any rules that are prefixed with a '!'
     [
       :connmark,
+      :condition,
       :ctstate,
       :ctproto,
       :ctorigsrc,
@@ -678,7 +682,7 @@
       :src_range,
       :state,
     ].each do |prop|
-      if hash[prop] && hash[prop].is_a?(Array)
+      if hash[prop]&.is_a?(Array)
         # find if any are negated, then negate all if so
         should_negate = hash[prop].index do |value|
           value.match(%r{^(!)\s+})
@@ -807,6 +811,8 @@
       raise "#{prop} elements must be unique" if resource[prop].map { |type| type.to_s.gsub(%r{--limit-iface-(in|out)}, '') }.uniq.length != resource[prop].length
     end
 
+    complex_args = [:ipset, :dst_type, :src_type]
+
     resource_list.each do |res|
       resource_value = nil
       if resource[res]
@@ -827,24 +833,23 @@
       args = args.flatten
 
       # On negations, the '!' has to be before the option (eg: "! -d 1.2.3.4")
-      if resource_value.is_a?(String) && resource_value.sub!(%r{^!\s*}, '')
+      if resource_value.is_a?(String) && resource_value.start_with?('!')
+        resource_value = resource_value.sub(%r{^!\s*}, '')
         # we do this after adding the 'dash' argument because of ones like "-m multiport --dports", where we want it before the "--dports" but after "-m multiport".
         # so we insert before whatever the last argument is
         args.insert(-2, '!')
       elsif resource_value.is_a?(Symbol) && resource_value.to_s.match(%r{^!})
-        # ruby 1.8.7 can't .match Symbols ------------------ ^
         resource_value = resource_value.to_s.sub!(%r{^!\s*}, '').to_sym
         args.insert(-2, '!')
-      elsif resource_value.is_a?(Array) && ![:ipset, :dst_type, :src_type].include?(res)
+      elsif resource_value.is_a?(Array) && !complex_args.include?(res)
+
         should_negate = resource_value.index do |value|
-          # ruby 1.8.7 can't .match symbols
           value.to_s.match(%r{^(!)\s+})
         end
         if should_negate
           resource_value, wrong_values = resource_value.map { |value|
             if value.is_a?(String)
-              # rubocop:disable Metrics/BlockNesting
-              wrong = value unless value =~ %r{^!\s+}
+              wrong = value unless %r{^!\s+}.match?(value)
               [value.sub(%r{^!\s*}, ''), wrong]
             else
               [value, nil]
@@ -852,7 +857,8 @@
           }.transpose
           wrong_values = wrong_values.compact
           unless wrong_values.empty?
-            raise "All values of the '#{res}' property must be prefixed with a '!' when inverting, but '#{wrong_values.join("', '")}' #{(wrong_values.length > 1) ? 'are' : 'is'} not prefixed; aborting" # rubocop:disable Metrics/LineLength : Line length cannot be reduced
+            raise "All values of the '#{res}' property must be prefixed with a '!' when inverting, but " \
+              "'#{wrong_values.join("', '")}' #{(wrong_values.length > 1) ? 'are' : 'is'} not prefixed; aborting"
           end
           args.insert(-2, '!')
           # rubocop:enable Metrics/BlockNesting
@@ -868,7 +874,8 @@
       end
 
       # ipset can accept multiple values with weird iptables arguments
-      if [:ipset, :dst_type, :src_type].include?(res)
+      if complex_args.include?(res)
+
         resource_value.join(" #{[resource_map[res]].flatten.first} ").split(' ').each do |a|
           if a.sub!(%r{^!\s*}, '')
             # Negate ipset options
--- a/modules/firewall/lib/puppet/provider/firewallchain/iptables_chain.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/provider/firewallchain/iptables_chain.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 Puppet::Type.type(:firewallchain).provide :iptables_chain do
   include Puppet::Util::Firewall
 
@@ -35,13 +37,13 @@
       re: %r{^:(.+)\s(\S+)$},
     },
   }.freeze
-  INTERNAL_CHAINS = %r{^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$}
-  TABLES = 'nat|mangle|filter|raw|rawpost|broute|security'.freeze
-  NAME_FORMAT = %r{^(.+):(#{TABLES}):(IP(v[46])?|ethernet)$}
+  INTERNAL_CHAINS = %r{^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$}.freeze
+  TABLES = 'nat|mangle|filter|raw|rawpost|broute|security'
+  NAME_FORMAT = %r{^(.+):(#{TABLES}):(IP(v[46])?|ethernet)$}.freeze
 
   def create
     allvalidchains do |t, chain, table, protocol|
-      if chain =~ INTERNAL_CHAINS
+      if INTERNAL_CHAINS.match?(chain)
         # can't create internal chains
         warning "Attempting to create internal chain #{@resource[:name]}"
       end
@@ -59,7 +61,7 @@
 
   def destroy
     allvalidchains do |t, chain, table|
-      if chain =~ INTERNAL_CHAINS
+      if INTERNAL_CHAINS.match?(chain)
         # can't delete internal chains
         warning "Attempting to destroy internal chain #{@resource[:name]}"
       else
@@ -71,7 +73,7 @@
 
   def exists?
     allvalidchains do |_t, chain|
-      if chain =~ INTERNAL_CHAINS
+      if INTERNAL_CHAINS.match?(chain)
         # 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
@@ -158,7 +160,7 @@
             next
           end
         end
-      rescue Puppet::Error # rubocop:disable Lint/HandleExceptions
+      rescue Puppet::Error
         # ignore command not found for ebtables or anything that doesn't exist
       end
     end
--- a/modules/firewall/lib/puppet/type/firewall.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/type/firewall.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
 # 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
+# provider/type path do not load until pluginsync has occured on the puppet server
 #
 # 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
@@ -56,6 +58,8 @@
 
       * clusterip: Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them.
 
+      * condition: Match if a specific condition variable is (un)set (requires xtables-addons)
+
       * connection_limiting: Connection limiting features.
 
       * conntrack: Connection tracking features.
@@ -146,6 +150,7 @@
   PUPPETCODE
 
   feature :connection_limiting, 'Connection limiting features.'
+  feature :condition, 'Match if a specific condition variable is (un)set.'
   feature :conntrack, 'Connection tracking features.'
   feature :hop_limiting, 'Hop limiting features.'
   feature :rate_limiting, 'Rate limiting features.'
@@ -636,7 +641,7 @@
     PUPPETCODE
 
     validate do |value|
-      unless value =~ %r{^[a-zA-Z0-9\-_]+$}
+      unless %r{^[a-zA-Z0-9\-_]+$}.match?(value)
         raise ArgumentError, <<-PUPPETCODE
           Jump destination must consist of alphanumeric characters, an
           underscore or a hyphen.
@@ -669,7 +674,7 @@
     PUPPETCODE
 
     validate do |value|
-      unless value =~ %r{^[a-zA-Z0-9\-_]+$}
+      unless %r{^[a-zA-Z0-9\-_]+$}.match?(value)
         raise ArgumentError, <<-PUPPETCODE
           Goto destination must consist of alphanumeric characters, an
           underscore or a hyphen.
@@ -1752,7 +1757,7 @@
     PUPPETCODE
 
     validate do |value|
-      unless value =~ %r{^\d+$}
+      unless %r{^\d+$}.match?(value)
         raise ArgumentError, <<-PUPPETCODE
           stat_every value must be a digit
         PUPPETCODE
@@ -1903,11 +1908,11 @@
     PUPPETCODE
 
     munge do |value|
-      if value =~ %r{^([0-9]):}
+      if %r{^([0-9]):}.match?(value)
         value = "0#{value}"
       end
 
-      if value =~ %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$}
+      if %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$}.match?(value)
         value = "#{value}:00"
       end
 
@@ -1922,11 +1927,11 @@
     PUPPETCODE
 
     munge do |value|
-      if value =~ %r{^([0-9]):}
+      if %r{^([0-9]):}.match?(value)
         value = "0#{value}"
       end
 
-      if value =~ %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$}
+      if %r{^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$}.match?(value)
         value = "#{value}:00"
       end
 
@@ -2070,7 +2075,11 @@
       given as an argument.
     PUPPETCODE
     munge do |value|
-      _value = value.delete(' ')
+      _value = if value.include?('!')
+                 value.split('|').map { |x| x.include?('!') ? x : "|#{x.delete(' ')}|" }.join
+               else
+                 value.delete(' ')
+               end
     end
   end
 
@@ -2248,6 +2257,19 @@
     newvalues(:true, :false)
   end
 
+  newproperty(:condition, required_features: :condition) do
+    desc <<-PUPPETCODE
+      Match on boolean value (0/1) stored in /proc/net/nf_condition/name.
+    PUPPETCODE
+    validate do |value|
+      unless value.is_a?(String)
+        raise ArgumentError, <<-PUPPETCODE
+          Condition must be a string.
+        PUPPETCODE
+      end
+    end
+  end
+
   autorequire(:firewallchain) do
     reqs = []
     protocol = nil
@@ -2261,8 +2283,9 @@
 
     unless protocol.nil?
       table = value(:table)
+      main_chains = ['INPUT', 'OUTPUT', 'FORWARD']
       [value(:chain), value(:jump)].each do |chain|
-        reqs << "#{chain}:#{table}:#{protocol}" unless chain.nil? || (['INPUT', 'OUTPUT', 'FORWARD'].include?(chain) && table == :filter)
+        reqs << "#{chain}:#{table}:#{protocol}" unless chain.nil? || (main_chains.include?(chain) && table == :filter)
       end
     end
 
@@ -2328,29 +2351,29 @@
     # Now we analyse the individual properties to make sure they apply to
     # the correct combinations.
     if value(:uid)
-      unless value(:chain).to_s =~ %r{OUTPUT|POSTROUTING}
+      unless %r{OUTPUT|POSTROUTING}.match?(value(:chain).to_s)
         raise 'Parameter uid only applies to chains ' \
           'OUTPUT,POSTROUTING'
       end
     end
 
     if value(:gid)
-      unless value(:chain).to_s =~ %r{OUTPUT|POSTROUTING}
+      unless %r{OUTPUT|POSTROUTING}.match?(value(:chain).to_s)
         raise 'Parameter gid only applies to chains ' \
           'OUTPUT,POSTROUTING'
       end
     end
 
     if value(:set_mark)
-      unless value(:jump).to_s  =~ %r{MARK} &&
-             value(:table).to_s =~ %r{mangle}
+      unless value(:jump).to_s.include?('MARK') &&
+             value(:table).to_s.include?('mangle')
         raise 'Parameter set_mark only applies to ' \
           'the mangle table and when jump => MARK'
       end
     end
 
     if value(:dport)
-      unless value(:proto).to_s =~ %r{tcp|udp|sctp}
+      unless %r{tcp|udp|sctp}.match?(value(:proto).to_s)
         raise '[%s] Parameter dport only applies to sctp, tcp and udp ' \
           'protocols. Current protocol is [%s] and dport is [%s]' %
               [value(:name), should(:proto), should(:dport)]
@@ -2376,7 +2399,7 @@
     end
 
     if value(:jump).to_s == 'DNAT'
-      unless value(:table).to_s =~ %r{nat}
+      unless %r{nat}.match?(value(:table).to_s)
         raise 'Parameter jump => DNAT only applies to table => nat'
       end
 
@@ -2386,7 +2409,7 @@
     end
 
     if value(:jump).to_s == 'SNAT'
-      unless value(:table).to_s =~ %r{nat}
+      unless %r{nat}.match?(value(:table).to_s)
         raise 'Parameter jump => SNAT only applies to table => nat'
       end
 
@@ -2396,7 +2419,7 @@
     end
 
     if value(:jump).to_s == 'MASQUERADE'
-      unless value(:table).to_s =~ %r{nat}
+      unless %r{nat}.match?(value(:table).to_s)
         raise 'Parameter jump => MASQUERADE only applies to table => nat'
       end
     end
@@ -2479,7 +2502,7 @@
     end
 
     if value(:jump).to_s == 'CT'
-      unless value(:table).to_s =~ %r{raw}
+      unless %r{raw}.match?(value(:table).to_s)
         raise 'Parameter jump => CT only applies to table => raw'
       end
     end
--- a/modules/firewall/lib/puppet/type/firewallchain.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/type/firewallchain.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
 # 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
+# provider/type path do not load until pluginsync has occured on the puppet server
 #
 # 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
@@ -59,7 +61,7 @@
         protocol = Regexp.last_match(3)
         case table
         when 'filter'
-          if chain =~ %r{^(PREROUTING|POSTROUTING|BROUTING)$}
+          if %r{^(PREROUTING|POSTROUTING|BROUTING)$}.match?(chain)
             raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'filter'"
           end
         when 'mangle'
@@ -67,25 +69,25 @@
             raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, FORWARD and OUTPUT are the only inbuilt chains that can be used in table 'mangle'"
           end
         when 'nat'
-          if chain =~ %r{^(BROUTING|FORWARD)$}
+          if %r{^(BROUTING|FORWARD)$}.match?(chain)
             raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, and OUTPUT are the only inbuilt chains that can be used in table 'nat'"
           end
           if Gem::Version.new(Facter['kernelmajversion'].value.dup) < Gem::Version.new('3.7') && protocol =~ %r{^(IP(v6)?)?$}
             raise ArgumentError, "table nat isn't valid in IPv6. You must specify ':IPv4' as the name suffix"
           end
         when 'raw'
-          if chain =~ %r{^(POSTROUTING|BROUTING|INPUT|FORWARD)$}
+          if %r{^(POSTROUTING|BROUTING|INPUT|FORWARD)$}.match?(chain)
             raise ArgumentError, 'PREROUTING and OUTPUT are the only inbuilt chains in the table \'raw\''
           end
         when 'broute'
           if protocol != 'ethernet'
             raise ArgumentError, 'BROUTE is only valid with protocol \'ethernet\''
           end
-          if chain =~ %r{^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$}
+          if %r{^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$}.match?(chain)
             raise ArgumentError, 'BROUTING is the only inbuilt chain allowed on on table \'broute\''
           end
         when 'security'
-          if chain =~ %r{^(PREROUTING|POSTROUTING|BROUTING)$}
+          if %r{^(PREROUTING|POSTROUTING|BROUTING)$}.match?(chain)
             raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'security'"
           end
         end
@@ -163,6 +165,15 @@
     end
   end
 
+  newparam(:ignore_foreign, boolean: true) do
+    desc <<-PUPPETCODE
+      Ignore rules that do not match the puppet title pattern "^\d+[[:graph:][:space:]]" when purging unmanaged firewall rules in this chain.
+      This can be used to ignore rules that were not put in by puppet. Beware that nothing keeps other systems from configuring firewall rules with a comment that starts with digits, and is indistinguishable from puppet-configured rules.
+    PUPPETCODE
+    newvalues(false, true)
+    defaultto false
+  end
+
   # Classes would be a better abstraction, pending:
   # http://projects.puppetlabs.com/issues/19001
   autorequire(:package) do
@@ -240,6 +251,9 @@
     # 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)
 
+    # Remove rules that were (presumably) not put in by puppet
+    rules_resources.delete_if { |res| res.provider.properties[:name].match(%r{^(\d+)[[:graph:][:space:]]})[1].to_i >= 9000 } if value(:ignore_foreign) == :true
+
     # 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 }
 
--- a/modules/firewall/lib/puppet/util/firewall.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/util/firewall.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'socket'
 require 'resolv'
 require 'puppet/util/ipcidr'
@@ -6,7 +8,7 @@
 module Puppet::Util::Firewall
   # Translate the symbolic names for icmp packet types to integers
   def icmp_name_to_number(value_icmp, protocol)
-    if value_icmp =~ %r{\d{1,2}$}
+    if %r{\d{1,2}$}.match?(value_icmp)
       value_icmp
     elsif protocol == 'inet'
       case value_icmp
@@ -47,7 +49,7 @@
 
   # Convert log_level names to their respective numbers
   def log_level_name_to_number(value)
-    if value =~ %r{\A[0-7]\z}
+    if %r{\A[0-7]\z}.match?(value)
       value
     else
       case value
@@ -75,12 +77,12 @@
   # nothing.
   def string_to_port(value, proto)
     proto = proto.to_s
-    unless proto =~ %r{^(tcp|udp)$}
+    unless %r{^(tcp|udp)$}.match?(proto)
       proto = 'tcp'
     end
 
     m = value.to_s.match(%r{^(!\s+)?(\S+)})
-    return "#{m[1]}#{m[2]}" if m[2] =~ %r{^\d+(-\d+)?$}
+    return "#{m[1]}#{m[2]}" if %r{^\d+(-\d+)?$}.match?(m[2])
     "#{m[1]}#{Socket.getservbyname(m[2], proto)}"
   end
 
@@ -123,7 +125,7 @@
         begin
           new_value = Puppet::Util::IPCidr.new(addr, family)
           break
-        rescue # rubocop:disable Lint/HandleExceptions
+        rescue # looking for the one that works # rubocop:disable Lint/SuppressedException
         end
       end
 
@@ -158,7 +160,7 @@
       if value.between?(0, 0xffffffff)
         return '0x' + value.to_s(16)
       end
-    rescue ArgumentError # rubocop:disable Lint/HandleExceptions
+    rescue ArgumentError
       # pass
     end
     nil
--- a/modules/firewall/lib/puppet/util/ipcidr.rb	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/lib/puppet/util/ipcidr.rb	Wed Apr 20 19:04:13 2022 +0100
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
 
 require 'ipaddr'
 
@@ -7,7 +8,7 @@
     def initialize(ipaddr, family = Socket::AF_UNSPEC)
       super(ipaddr, family)
     rescue ArgumentError => e
-      raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}" if e.message =~ %r{invalid address}
+      raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}" if %r{invalid address}.match?(e.message)
       raise e
     end
 
@@ -29,8 +30,7 @@
     end
 
     def cidr
-      cidr = '%s/%s' % [to_s, prefixlen]
-      cidr
+      "#{self}/#{prefixlen}"
     end
   end
 end
--- a/modules/firewall/manifests/init.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/init.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -34,9 +34,9 @@
   $ensure          = running,
   $ensure_v6       = undef,
   $pkg_ensure      = present,
-  $service_name    = $::firewall::params::service_name,
-  $service_name_v6 = $::firewall::params::service_name_v6,
-  $package_name    = $::firewall::params::package_name,
+  $service_name    = $firewall::params::service_name,
+  $service_name_v6 = $firewall::params::service_name_v6,
+  $package_name    = $firewall::params::package_name,
   $ebtables_manage = false,
 ) inherits ::firewall::params {
   $_ensure_v6 = pick($ensure_v6, $ensure)
--- a/modules/firewall/manifests/linux.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/linux.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -27,9 +27,9 @@
   $ensure          = running,
   $ensure_v6       = undef,
   $pkg_ensure      = present,
-  $service_name    = $::firewall::params::service_name,
-  $service_name_v6 = $::firewall::params::service_name_v6,
-  $package_name    = $::firewall::params::package_name,
+  $service_name    = $firewall::params::service_name,
+  $service_name_v6 = $firewall::params::service_name_v6,
+  $package_name    = $firewall::params::package_name,
   $ebtables_manage = false,
 ) inherits ::firewall::params {
   $enable = $ensure ? {
@@ -40,8 +40,8 @@
   $_ensure_v6 = pick($ensure_v6, $ensure)
 
   $_enable_v6 = $_ensure_v6 ? {
-    running => true,
-    stopped => false,
+    'running' => true,
+    'stopped' => false,
   }
 
   package { 'iptables':
--- a/modules/firewall/manifests/linux/archlinux.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/linux/archlinux.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -21,9 +21,9 @@
 class firewall::linux::archlinux (
   $ensure         = 'running',
   $enable         = true,
-  $service_name   = $::firewall::params::service_name,
-  $package_name   = $::firewall::params::package_name,
-  $package_ensure = $::firewall::params::package_ensure,
+  $service_name   = $firewall::params::service_name,
+  $package_name   = $firewall::params::package_name,
+  $package_ensure = $firewall::params::package_ensure,
 ) inherits ::firewall::params {
   if $package_name {
     package { $package_name:
@@ -38,12 +38,12 @@
   }
 
   file { '/etc/iptables/iptables.rules':
-    ensure => present,
+    ensure => file,
     before => Service[$service_name],
   }
 
   file { '/etc/iptables/ip6tables.rules':
-    ensure => present,
+    ensure => file,
     before => Service[$service_name],
   }
 }
--- a/modules/firewall/manifests/linux/debian.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/linux/debian.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -21,23 +21,22 @@
 class firewall::linux::debian (
   $ensure         = running,
   $enable         = true,
-  $service_name   = $::firewall::params::service_name,
-  $package_name   = $::firewall::params::package_name,
-  $package_ensure = $::firewall::params::package_ensure,
+  $service_name   = $firewall::params::service_name,
+  $package_name   = $firewall::params::package_name,
+  $package_ensure = $firewall::params::package_ensure,
 ) inherits ::firewall::params {
-
   if $package_name {
     #Fixes hang while installing iptables-persistent on debian 8
-    exec {'iptables-persistent-debconf':
-        command     => "/bin/echo \"${package_name} ${package_name}/autosave_v4 boolean false\" |
+    exec { 'iptables-persistent-debconf':
+      command     => "/bin/echo \"${package_name} ${package_name}/autosave_v4 boolean false\" |
                       /usr/bin/debconf-set-selections && /bin/echo \"${package_name} ${package_name}/autosave_v6 boolean false\" |
                       /usr/bin/debconf-set-selections",
 
-        refreshonly => true,
+      refreshonly => true,
     }
     ensure_packages([$package_name],{
-      ensure  => $package_ensure,
-      require => Exec['iptables-persistent-debconf']
+        ensure  => $package_ensure,
+        require => Exec['iptables-persistent-debconf']
     })
   }
 
--- a/modules/firewall/manifests/linux/gentoo.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/linux/gentoo.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -21,9 +21,9 @@
 class firewall::linux::gentoo (
   $ensure         = 'running',
   $enable         = true,
-  $service_name   = $::firewall::params::service_name,
-  $package_name   = $::firewall::params::package_name,
-  $package_ensure = $::firewall::params::package_ensure,
+  $service_name   = $firewall::params::service_name,
+  $package_name   = $firewall::params::package_name,
+  $package_ensure = $firewall::params::package_ensure,
 ) inherits ::firewall::params {
   if $package_name {
     package { $package_name:
@@ -38,12 +38,12 @@
   }
 
   file { '/var/lib/iptables/rules-save':
-    ensure => present,
+    ensure => file,
     before => Service[$service_name],
   }
 
   file { '/var/lib/iptables/rules-save6':
-    ensure => present,
+    ensure => file,
     before => Service[$service_name],
   }
 }
--- a/modules/firewall/manifests/linux/redhat.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/linux/redhat.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -26,7 +26,8 @@
 #   Controls the state of the iptables package on your system. Valid options: 'present' or 'latest'. Defaults to 'latest'.
 #
 # @param sysconfig_manage
-#   Enable sysconfig configuration for iptables/ip6tables files. Defaults defined in firewall::params. This is disabled for RedHat/CentOS 8+.
+#   Enable sysconfig configuration for iptables/ip6tables files. Defaults defined in firewall::params.
+#   This is disabled for RedHat/CentOS 8+.
 #
 # @api private
 #
@@ -35,11 +36,11 @@
   $ensure_v6        = undef,
   $enable           = true,
   $enable_v6        = undef,
-  $service_name     = $::firewall::params::service_name,
-  $service_name_v6  = $::firewall::params::service_name_v6,
-  $package_name     = $::firewall::params::package_name,
-  $package_ensure   = $::firewall::params::package_ensure,
-  $sysconfig_manage = $::firewall::params::sysconfig_manage,
+  $service_name     = $firewall::params::service_name,
+  $service_name_v6  = $firewall::params::service_name_v6,
+  $package_name     = $firewall::params::package_name,
+  $package_ensure   = $firewall::params::package_ensure,
+  $sysconfig_manage = $firewall::params::sysconfig_manage,
 ) inherits ::firewall::params {
   $_ensure_v6 = pick($ensure_v6, $ensure)
   $_enable_v6 = pick($enable_v6, $enable)
@@ -48,8 +49,8 @@
   # package, which provides the /usr/libexec/iptables/iptables.init used by
   # lib/puppet/util/firewall.rb.
   if ($::operatingsystem != 'Amazon')
-    and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
-    or  ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
+  and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
+  or  ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
     service { 'firewalld':
       ensure => stopped,
       enable => false,
@@ -66,13 +67,13 @@
   if $package_name {
     ensure_packages($package_name, {
         'ensure' => $package_ensure,
-        'before' => Service[$service_name]}
+      'before' => Service[$service_name] }
     )
   }
 
   if ($::operatingsystem != 'Amazon')
-    and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
-    or  ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
+  and (($::operatingsystem != 'Fedora' and versioncmp($::operatingsystemrelease, '7.0') >= 0)
+  or  ($::operatingsystem == 'Fedora' and versioncmp($::operatingsystemrelease, '15') >= 0)) {
     if $ensure == 'running' {
       exec { '/usr/bin/systemctl daemon-reload':
         require     => Package[$package_name],
@@ -84,7 +85,7 @@
   }
 
   if ($::operatingsystem == 'Amazon') and (versioncmp($::operatingsystemmajrelease, '4') >= 0)
-    or ($::operatingsystem == 'Amazon') and (versioncmp($::operatingsystemmajrelease, '2') >= 0) {
+  or ($::operatingsystem == 'Amazon') and (versioncmp($::operatingsystemmajrelease, '2') >= 0) {
     service { $service_name:
       ensure    => $ensure,
       enable    => $enable,
@@ -116,14 +117,14 @@
 
   if $sysconfig_manage {
     file { "/etc/sysconfig/${service_name}":
-      ensure => present,
+      ensure => file,
       owner  => 'root',
       group  => 'root',
       mode   => '0600',
     }
     if $service_name_v6 {
       file { "/etc/sysconfig/${service_name_v6}":
-        ensure => present,
+        ensure => file,
         owner  => 'root',
         group  => 'root',
         mode   => '0600',
@@ -178,7 +179,6 @@
           }
 
           default: {}
-
         }
       }
       default: {}
--- a/modules/firewall/manifests/params.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/manifests/params.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -57,7 +57,6 @@
             $service_name = 'iptables-persistent'
             $package_name = 'iptables-persistent'
           }
-
         }
         'Ubuntu': {
           if versioncmp($::operatingsystemrelease, '14.10') >= 0 {
@@ -67,7 +66,6 @@
             $service_name = 'iptables-persistent'
             $package_name = 'iptables-persistent'
           }
-
         }
         default: {
           $service_name = 'iptables-persistent'
--- a/modules/firewall/metadata.json	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/metadata.json	Wed Apr 20 19:04:13 2022 +0100
@@ -1,6 +1,6 @@
 {
   "name": "puppetlabs-firewall",
-  "version": "2.5.0",
+  "version": "2.8.1",
   "author": "puppetlabs",
   "summary": "Manages Firewalls such as iptables",
   "license": "Apache-2.0",
@@ -75,10 +75,10 @@
   "requirements": [
     {
       "name": "puppet",
-      "version_requirement": ">= 5.5.10 < 7.0.0"
+      "version_requirement": ">= 5.5.10 < 8.0.0"
     }
   ],
-  "template-url": "https://github.com/puppetlabs/pdk-templates#master",
-  "template-ref": "heads/master-0-g88b05c7",
-  "pdk-version": "1.17.0"
+  "template-url": "https://github.com/puppetlabs/pdk-templates.git#main",
+  "template-ref": "heads/main-0-g1862b96",
+  "pdk-version": "1.19.0.pre (47)"
 }
--- a/modules/firewall/provision.yaml	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/firewall/provision.yaml	Wed Apr 20 19:04:13 2022 +0100
@@ -1,28 +1,92 @@
 ---
 default:
   provisioner: docker
-  images: ['litmusimage/centos:7']
+  images:
+  - litmusimage/centos:7
 vagrant:
   provisioner: vagrant
-  images: ['centos/7', 'generic/ubuntu1804']
+  images:
+  - centos/7
+  - generic/ubuntu1804
 travis_deb:
   provisioner: docker
-  images: ['litmusimage/debian:8', 'litmusimage/debian:9'] # 'litmusimage/debian10' removed due to failures present only on Docker
+  images:
+  - litmusimage/debian:8
+  - litmusimage/debian:9
 travis_ub_5:
   provisioner: docker
-  images: ['litmusimage/ubuntu:14.04', 'litmusimage/ubuntu:16.04', 'litmusimage/ubuntu:18.04']
+  images:
+  - litmusimage/ubuntu:14.04
+  - litmusimage/ubuntu:16.04
+  - litmusimage/ubuntu:18.04
 travis_ub_6:
   provisioner: docker
-  images: ['litmusimage/ubuntu:14.04', 'litmusimage/ubuntu:16.04', 'litmusimage/ubuntu:18.04', 'litmusimage/ubuntu:20.04']
-travis_el6:
-  provisioner: docker
-  images: []
+  images:
+  - litmusimage/ubuntu:14.04
+  - litmusimage/ubuntu:16.04
+  - litmusimage/ubuntu:18.04
+  - litmusimage/ubuntu:20.04
 travis_el7:
   provisioner: docker
-  images: ['litmusimage/centos:7']
+  images:
+  - litmusimage/centos:7
+travis_el8:
+  provisioner: docker
+  images:
+  - litmusimage/centos:8
 release_checks_5:
   provisioner: abs
-  images: ['redhat-5-x86_64', 'redhat-6-x86_64', 'redhat-7-x86_64', 'redhat-8-x86_64', 'centos-5-x86_64', 'centos-6-x86_64', 'centos-7-x86_64', 'centos-8-x86_64', 'oracle-6-x86_64', 'scientific-6-x86_64', 'scientific-7-x86_64', 'debian-8-x86_64', 'debian-9-x86_64', 'debian-10-x86_64', 'sles-12-x86_64', 'sles-15-x86_64', 'ubuntu-1404-x86_64', 'ubuntu-1604-x86_64', 'ubuntu-1804-x86_64']
+  images:
+  - redhat-6-x86_64
+  - redhat-7-x86_64
+  - redhat-8-x86_64
+  - centos-6-x86_64
+  - centos-7-x86_64
+  - centos-8-x86_64
+  - oracle-6-x86_64
+  - scientific-6-x86_64
+  - scientific-7-x86_64
+  - debian-8-x86_64
+  - debian-9-x86_64
+  - debian-10-x86_64
+  - sles-12-x86_64
+  - sles-15-x86_64
+  - ubuntu-1404-x86_64
+  - ubuntu-1604-x86_64
+  - ubuntu-1804-x86_64
 release_checks_6:
   provisioner: abs
-  images: ['redhat-5-x86_64', 'redhat-6-x86_64', 'redhat-7-x86_64', 'redhat-8-x86_64', 'centos-5-x86_64', 'centos-6-x86_64', 'centos-7-x86_64', 'centos-8-x86_64', 'oracle-6-x86_64', 'scientific-6-x86_64', 'scientific-7-x86_64', 'debian-8-x86_64', 'debian-9-x86_64', 'debian-10-x86_64', 'sles-12-x86_64', 'sles-15-x86_64', 'ubuntu-1404-x86_64', 'ubuntu-1604-x86_64', 'ubuntu-1804-x86_64', 'ubuntu-2004-x86_64']
+  images:
+  - redhat-6-x86_64
+  - redhat-7-x86_64
+  - redhat-8-x86_64
+  - centos-6-x86_64
+  - centos-7-x86_64
+  - centos-8-x86_64
+  - oracle-6-x86_64
+  - scientific-6-x86_64
+  - scientific-7-x86_64
+  - debian-8-x86_64
+  - debian-9-x86_64
+  - debian-10-x86_64
+  - sles-12-x86_64
+  - sles-15-x86_64
+  - ubuntu-1404-x86_64
+  - ubuntu-1604-x86_64
+  - ubuntu-1804-x86_64
+  - ubuntu-2004-x86_64
+release_checks_7:
+  provisioner: abs
+  images:
+  - redhat-7-x86_64
+  - redhat-8-x86_64
+  - centos-7-x86_64
+  - centos-8-x86_64
+  - oracle-7-x86_64
+  - scientific-7-x86_64
+  - sles-12-x86_64
+  - sles-15-x86_64
+  - debian-9-x86_64
+  - debian-10-x86_64
+  - ubuntu-1804-x86_64
+  - ubuntu-2004-x86_64
--- a/modules/my_fw/manifests/init.pp	Mon Apr 18 10:49:52 2022 +0100
+++ b/modules/my_fw/manifests/init.pp	Wed Apr 20 19:04:13 2022 +0100
@@ -1,10 +1,23 @@
 class my_fw ($ip_version) {
+  $real_ensure_v4 = $ip_version == "IPv6" ? { true => 'stopped', default => 'running'}
+  $real_ensure_v6 = $ip_version == "IPv6" ? { true => 'running', default => 'stopped'}
+  case $::operatingsystem {
+    'CentOS': {
+      $ensure_v4 = $real_ensure_v4
+      $ensure_v6 = $real_ensure_v6
+    }
+    # Ubuntu doesn't understand IPv4 vs IPv6
+    'Ubuntu': {
+      $ensure_v4 = ($real_ensure_v4 == 'running' or $real_ensure_v6 == 'running') ? { true => 'running', default => 'stopped' }
+      $ensure_v6 = undef
+    }
+  }
   Firewall <| |> {
     provider => $ip_version == "IPv6" ? { true => 'ip6tables', default => 'iptables'},
   }
   class { ['my_fw::pre', 'my_fw::post']: }
   class { 'firewall':
-    ensure => $ip_version == "IPv6" ? { true => 'stopped', default => 'running'},
-    ensure_v6 => $ip_version == "IPv6" ? { true => 'running', default => 'stopped'},
+    ensure => $ensure_v4,
+    ensure_v6 => $ensure_v6,
   }
 }
\ No newline at end of file