commit fd0eaeca0ae49894d698a47671455c990760b78a
Author: tr <tr@immerda.ch>
Date:   Wed Sep 23 17:33:49 2020 +0200

    Add class bridges
    
    Allow traffic from any bridge to itself by default

diff --git a/manifests/bridges.pp b/manifests/bridges.pp
new file mode 100644
index 0000000..2d7cb99
--- /dev/null
+++ b/manifests/bridges.pp
@@ -0,0 +1,19 @@
+# allow forwarding traffic on bridges
+class nftables::bridges(
+  Enum['present','absent']
+    $ensure = 'present',
+  Regexp
+    $bridgenames = /br+/
+) {
+  if $ensure == 'present' {
+    $interfaces = keys($facts['networking']['interfaces'])
+    $bridges = $interfaces.filter |$items| { $items =~ $bridgenames }
+
+    $bridges.each |String $bridge| {
+      nftables::rule { "default_fwd-bridge_${bridge}_${bridge}":
+        order   => '08',
+        content => "iifname ${bridge} oifname ${bridge} accept",
+      }
+    }
+  }
+}
diff --git a/manifests/inet_filter.pp b/manifests/inet_filter.pp
index 072ae07..6c27600 100644
--- a/manifests/inet_filter.pp
+++ b/manifests/inet_filter.pp
@@ -95,6 +95,9 @@ class nftables::inet_filter inherits nftables {
     }
   }
 
+  # allow forwarding traffic on bridges
+  include nftables::bridges
+
   # basic ingoing rules
   if $nftables::in_ssh {
     include nftables::rules::ssh
diff --git a/spec/classes/bridges_spec.rb b/spec/classes/bridges_spec.rb
new file mode 100644
index 0000000..0187299
--- /dev/null
+++ b/spec/classes/bridges_spec.rb
@@ -0,0 +1,53 @@
+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 }
+
+      it { is_expected.to compile }
+
+      it {
+        is_expected.to contain_concat('nftables-inet-filter-chain-default_fwd').with(
+          path:           '/etc/nftables/puppet/inet-filter-chain-default_fwd.nft',
+          owner:          'root',
+          group:          'root',
+          mode:           '0640',
+          ensure_newline: true,
+        )
+      }
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-header').with(
+          target:  'nftables-inet-filter-chain-default_fwd',
+          content: %r{^chain default_fwd \{$},
+          order:   '00',
+        )
+      }
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-rule-bridge_br0_br0').with(
+          target:  'nftables-inet-filter-chain-default_fwd',
+          content: %r{^  iifname br0 oifname br0 accept$},
+          order:   '08',
+        )
+      }
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-rule-bridge_br1_br1').with(
+          target:  'nftables-inet-filter-chain-default_fwd',
+          content: %r{^  iifname br1 oifname br1 accept$},
+          order:   '08',
+        )
+      }
+      it { is_expected.not_to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-bridge_br0_br1') }
+      it { is_expected.not_to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-bridge_br1_br0') }
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-chain-default_fwd-footer').with(
+          target:  'nftables-inet-filter-chain-default_fwd',
+          content: %r{^\}$},
+          order:   '99',
+        )
+      }
+    end
+  end
+end
diff --git a/spec/default_module_facts.yml b/spec/default_module_facts.yml
new file mode 100644
index 0000000..9a8246f
--- /dev/null
+++ b/spec/default_module_facts.yml
@@ -0,0 +1,89 @@
+---
+networking:
+  dhcp: 192.0.2.1
+  domain: example.com
+  fqdn: centos8.example.com
+  hostname: centos8
+  interfaces:
+    ens3:
+      bindings:
+      - address: 192.0.2.2
+        netmask: 255.255.255.0
+        network: 192.0.2.0
+      bindings6:
+      - address: 2001:db8::2
+        netmask: 'ffff:ffff:ffff:ffff::'
+        network: '2001:db8::'
+      dhcp: 192.0.2.1
+      ip: 192.0.2.2
+      ip6: 2001:db8::1
+      mac: 00:00:00:00:00:00
+      mtu: 1500
+      netmask: 255.255.255.0
+      netmask6: 'ffff:ffff:ffff:ffff::'
+      network: 192.0.2.0
+      network6: '2001:db8::'
+      scope6: global
+    br0:
+      bindings:
+      - address: 198.51.100.1
+        netmask: 255.255.255.224
+        network: 198.51.100.0
+      bindings6:
+      - address: 2001:db8:1::1
+        netmask: 'ffff:ffff:ffff:ffff:ffff::'
+        network: '2001:db8:1::'
+      ip: 198.51.100.1
+      ip6: 2001:db8:1::1
+      mac: AA:AA:AA:AA:AA:AA
+      mtu: 1500
+      netmask: 255.255.255.224
+      netmask6: 'ffff:ffff:ffff:ffff:ffff::'
+      network: 198.51.100.0
+      network6: '2001:db8:1::'
+      scope6: global
+    br1:
+      bindings:
+      - address: 198.51.100.33
+        netmask: 255.255.255.224
+        network: 198.51.100.32
+      bindings6:
+      - address: 2001:db8:2::1
+        netmask: 'ffff:ffff:ffff:ffff:ffff::'
+        network: '2001:db8:2::'
+      ip: 198.51.100.33
+      ip6: 2001:db8:2::1
+      mac: BB:BB:BB:BB:BB:BB
+      mtu: 1500
+      netmask: 255.255.255.224
+      netmask6: 'ffff:ffff:ffff:ffff:ffff::'
+      network: 198.51.100.32
+      network6: '2001:db8:2::'
+      scope6: global
+    lo:
+      bindings:
+      - address: 127.0.0.1
+        netmask: 255.0.0.0
+        network: 127.0.0.0
+      bindings6:
+      - address: "::1"
+        netmask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+        network: "::1"
+      ip: 127.0.0.1
+      ip6: "::1"
+      mtu: 65536
+      netmask: 255.0.0.0
+      netmask6: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+      network: 127.0.0.0
+      network6: "::1"
+      scope6: host
+  ip: 192.0.2.2
+  ip6: 2001:db8::2
+  mac: 00:00:00:00:00:00
+  mtu: 1500
+  netmask: 255.255.255.0
+  netmask6: 'ffff:ffff:ffff:ffff::'
+  network: 192.0.2.0
+  network6: '2001:db8::'
+  primary: ens3
+  scope6: global
