commit 3d29a6eb9af41d3310e261d3cd10536ff0e8b92d
Author: tr <tr@immerda.ch>
Date:   Mon Aug 31 12:13:17 2020 +0200

    Add a rule to create snat

diff --git a/manifests/rules/snat4.pp b/manifests/rules/snat4.pp
new file mode 100644
index 0000000..3450d40
--- /dev/null
+++ b/manifests/rules/snat4.pp
@@ -0,0 +1,53 @@
+# manage a ipv4 snat rule
+define nftables::rules::snat4(
+  String[1]
+    $snat,
+  Pattern[/^[a-zA-Z0-9_]+$/]
+    $rulename = $title,
+  Pattern[/^\d\d$/]
+    $order = '70',
+  String[1]
+    $chain = 'POSTROUTING',
+  Optional[String[1]]
+    $oif = undef,
+  Optional[String[1]]
+    $saddr = undef,
+  Optional[Pattern[/^(tcp|udp)$/]]
+    $proto = undef,
+  Optional[Variant[String,Integer[1,65535]]]
+    $dport = undef,
+  Enum['present','absent']
+    $ensure = 'present',
+) {
+
+  $oifname = $oif ? {
+    undef   => '',
+    default => "oifname ${oif} ",
+  }
+  $src = $saddr ? {
+    undef   => '',
+    default => "ip saddr ${saddr} ",
+  }
+
+  if $proto and $dport {
+    $protocol = ''
+    $port     = "${proto} dport ${dport} "
+  } elsif $proto {
+    $protocol = "${proto} "
+    $port     = ''
+  } elsif $dport {
+    $protocol = ''
+    $port     = "tcp dport ${dport} "
+  } else {
+    $protocol = ''
+    $port     = ''
+  }
+
+  nftables::rule{
+    "${chain}-${rulename}":
+      ensure  => $ensure,
+      table   => 'ip-nat',
+      order   => $order,
+      content => "${oifname}${src}${protocol}${port}snat ${snat}";
+  }
+}
diff --git a/spec/classes/snat4_spec.rb b/spec/classes/snat4_spec.rb
new file mode 100644
index 0000000..1c70025
--- /dev/null
+++ b/spec/classes/snat4_spec.rb
@@ -0,0 +1,88 @@
+require 'spec_helper'
+
+describe 'nftables' do
+  let(:pre_condition) { 'Exec{path => "/bin"}' }
+
+  on_supported_os.each do |os, os_facts|
+    context "on #{os}" do
+      let(:facts) { os_facts }
+
+      context 'with snat4' do
+        let(:pre_condition) do
+          """
+          nftables::rules::snat4{
+            'static':
+              order => '60',
+              snat  => '198.51.100.1',
+              oif   => 'eth0';
+            '1_1':
+              order => '61',
+              saddr => '192.0.2.2',
+              snat  => '198.51.100.3',
+              oif   => 'eth0';
+            '1_1_smtp':
+              saddr => '192.0.2.2',
+              snat  => '198.51.100.2',
+              dport => '25';
+            '1_1_wireguard':
+              saddr => '192.0.2.2',
+              snat  => '198.51.100.2',
+              proto => 'udp',
+              dport => '51820';
+          }
+          """
+        end
+
+        it { is_expected.to compile }
+
+        it { is_expected.to contain_concat('nftables-ip-nat-chain-POSTROUTING').with(
+          :path           => '/etc/nftables/puppet/ip-nat-chain-POSTROUTING.nft',
+          :owner          => 'root',
+          :group          => 'root',
+          :mode           => '0640',
+          :ensure_newline => true,
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-header').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^chain POSTROUTING {$/,
+          :order   => '00',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-type').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  type nat hook postrouting priority 100$/,
+          :order   => '01',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-policy').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  policy accept$/,
+          :order   => '02',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-static').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  oifname eth0 snat 198\.51\.100\.1$/,
+          :order   => '60',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-1_1').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  oifname eth0 ip saddr 192\.0\.2\.2 snat 198\.51\.100\.3$/,
+          :order   => '61',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-1_1_smtp').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  ip saddr 192\.0\.2\.2 tcp dport 25 snat 198\.51\.100\.2$/,
+          :order   => '70',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-rule-1_1_wireguard').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^  ip saddr 192\.0\.2\.2 udp dport 51820 snat 198\.51\.100\.2$/,
+          :order   => '70',
+        )}
+        it { is_expected.to contain_concat__fragment('nftables-ip-nat-chain-POSTROUTING-footer').with(
+          :target  => 'nftables-ip-nat-chain-POSTROUTING',
+          :content => /^}$/,
+          :order   => '99',
+        )}
+      end
+    end
+  end
+end
