]> review.fuel-infra Code Review - puppet-modules/puppetlabs-firewall.git/commitdiff
Added code for physdev_is_bridged
authorJonathan Tripathy <jt@puppetlabs.com>
Fri, 13 Feb 2015 18:41:29 +0000 (18:41 +0000)
committerJonathan Tripathy <jonnyt@Jonathans-MacBook-Pro.local>
Fri, 13 Feb 2015 23:57:36 +0000 (23:57 +0000)
README.markdown
lib/puppet/provider/firewall/ip6tables.rb
lib/puppet/provider/firewall/iptables.rb
lib/puppet/type/firewall.rb
spec/acceptance/firewall_bridging_spec.rb

index d14143ed7390f0e82604b473aa6eccc10851c10c..2d146debb313849c4fa6cf1d5cc790ed8abc8e9b 100644 (file)
@@ -518,6 +518,8 @@ firewall { '999 this runs last':
 
 * `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`: 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.
index 6ddcee28058173be59bc54fe37e5d670eb965122..b0ebbcd8a82003583d6c8d7d80ff6178a7119a19 100644 (file)
@@ -64,64 +64,65 @@ Puppet::Type.type(:firewall).provide :ip6tables, :parent => :iptables, :source =
   @protocol = "IPv6"
 
   @resource_map = {
-    :burst            => "--limit-burst",
-    :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        => '-m iprange --dst-range',
-    :dst_type         => "-m addrtype --dst-type",
-    :gid              => "-m owner --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",
-    :name             => "-m comment --comment",
-    :mac_source       => ["-m mac --mac-source", "--mac-source"],
-    :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_mark         => mark_flag,
-    :socket           => "-m socket",
-    :source           => "-s",
-    :sport            => ["-m multiport --sports", "--sport"],
-    :src_range        => '-m iprange --src-range',
-    :src_type         => "-m addrtype --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              => "-m owner --uid-owner",
-    :physdev_in       => "-m physdev --physdev-in",
-    :physdev_out      => "-m physdev --physdev-out",
+    :burst              => "--limit-burst",
+    :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          => '-m iprange --dst-range',
+    :dst_type           => "-m addrtype --dst-type",
+    :gid                => "-m owner --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",
+    :name               => "-m comment --comment",
+    :mac_source         => ["-m mac --mac-source", "--mac-source"],
+    :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_mark           => mark_flag,
+    :socket             => "-m socket",
+    :source             => "-s",
+    :sport              => ["-m multiport --sports", "--sport"],
+    :src_range          => '-m iprange --src-range',
+    :src_type           => "-m addrtype --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                => "-m owner --uid-owner",
+    :physdev_in         => "-m physdev --physdev-in",
+    :physdev_out        => "-m physdev --physdev-out",
+    :physdev_is_bridged => "-m physdev --physdev-is-bridged"
   }
 
   # These are known booleans that do not take a value, but we want to munge
@@ -134,7 +135,8 @@ Puppet::Type.type(:firewall).provide :ip6tables, :parent => :iptables, :source =
     :rdest,
     :reap,
     :rttl,
-    :socket
+    :socket,
+    :physdev_is_bridged
   ]
 
   # Create property methods dynamically
@@ -172,7 +174,7 @@ Puppet::Type.type(:firewall).provide :ip6tables, :parent => :iptables, :source =
   # 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, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range,
+    :physdev_out, :physdev_is_bridged, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range,
     :tcp_flags, :gid, :uid, :mac_source, :sport, :dport, :port, :dst_type,
     :src_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state,
     :ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap,
index 74fa219a31cc6ad5fa9763edec3ca5f409e4b275..0aa5d7172abd5c05ac94e6e35b1792699558ed3f 100644 (file)
@@ -50,63 +50,64 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
   @protocol = "IPv4"
 
   @resource_map = {
-    :burst            => "--limit-burst",
-    :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        => "-m iprange --dst-range",
-    :dst_type         => "-m addrtype --dst-type",
-    :gid              => "-m owner --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',
-    :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_mark         => mark_flag,
-    :socket           => "-m socket",
-    :source           => "-s",
-    :sport            => ["-m multiport --sports", "--sport"],
-    :src_range        => "-m iprange --src-range",
-    :src_type         => "-m addrtype --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              => "-m owner --uid-owner",
-    :physdev_in       => "-m physdev --physdev-in",
-    :physdev_out      => "-m physdev --physdev-out",
+    :burst              => "--limit-burst",
+    :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          => "-m iprange --dst-range",
+    :dst_type           => "-m addrtype --dst-type",
+    :gid                => "-m owner --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',
+    :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_mark           => mark_flag,
+    :socket             => "-m socket",
+    :source             => "-s",
+    :sport              => ["-m multiport --sports", "--sport"],
+    :src_range          => "-m iprange --src-range",
+    :src_type           => "-m addrtype --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                => "-m owner --uid-owner",
+    :physdev_in         => "-m physdev --physdev-in",
+    :physdev_out        => "-m physdev --physdev-out",
+    :physdev_is_bridged => "-m physdev --physdev-is-bridged"
   }
 
   # These are known booleans that do not take a value, but we want to munge
@@ -118,7 +119,8 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
     :reap,
     :rsource,
     :rttl,
-    :socket
+    :socket,
+    :physdev_is_bridged
   ]
 
 
@@ -154,7 +156,7 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
   # 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, :proto, :isfragment,
+    :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, :gid, :uid, :mac_source, :sport, :dport, :port,
     :dst_type, :src_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
@@ -250,6 +252,18 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
         '--pol "ipsec\1\2\3\4\5\6\7\8" '
     )
 
+    # Handle resource_map values depending on whether physdev-in, physdev-out, ,physdev-is-bridged, or all three are specified
+    if values.include? "--physdev-in"
+      @resource_map[:physdev_in] = "-m physdev --physdev-in"
+      @resource_map[:physdev_out] = "--physdev-out"
+      @resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
+    elsif values.include? "--physdev-out"
+      @resource_map[:physdev_out] = "-m physdev --physdev-out"
+      @resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
+    else
+      @resource_map[:physdev_is_bridged] = "-m physdev --physdev-is-bridged"
+    end
+
     # Trick the system for booleans
     @known_booleans.each do |bool|
       # append "true" because all params are expected to have values
@@ -263,14 +277,6 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
       end
     end
 
-    # Handle resource_map values depending on whether physdev-in, physdev-out, or both are specified
-    if values.include? "--physdev-in" and values.include? "--physdev-out" then
-      #values = values.sub("--physdev-out","-m physdev --physdev-out")
-      @resource_map[:physdev_out] = "--physdev-out"
-    else
-      @resource_map[:physdev_out] = "-m physdev --physdev-out"
-    end
-
     ############
     # Populate parser_list with used value, in the correct order
     ############
@@ -452,11 +458,16 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
     resource_map = self.class.instance_variable_get('@resource_map')
     known_booleans = self.class.instance_variable_get('@known_booleans')
 
-    # Handle physdev args depending on whether physdev-in, physdev-out, or both are specified
+    # Handle physdev args depending on whether physdev-in, physdev-out, physdev-is-bridged, or all three are specified
     if (resource[:physdev_in])
+      resource_map[:physdev_in] = "-m physdev --physdev-in"
       resource_map[:physdev_out] = "--physdev-out"
-    else
+      resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
+    elsif (resource[:physdev_out])
       resource_map[:physdev_out] = "-m physdev --physdev-out"
+      resource_map[:physdev_is_bridged] = "--physdev-is-bridged"
+    else
+      resource_map[:physdev_is_bridged] = "-m physdev --physdev-is-bridged"
     end
 
     resource_list.each do |res|
index 6209c88407bc0f9a3c16f6ca5da62d244e4a8700..46756e341adaacb6cc6f26f3f9dea52e3574f54b 100644 (file)
@@ -1087,6 +1087,13 @@ Puppet::Type.newtype(:firewall) do
     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
+
   autorequire(:firewallchain) do
     reqs = []
     protocol = nil
index 109806a424dd496af290cf2da658c618184a998a..b3cf9b6bd32a1ba15667a527f565f7da4190df44 100644 (file)
@@ -90,6 +90,115 @@ describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfami
            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)
+          unless fact('selinux') == 'true'
+            apply_manifest(pp, :catch_changes => true)
+          end
+        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)
+          unless fact('selinux') == 'true'
+            apply_manifest(pp, :catch_changes => true)
+          end
+        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)
+          unless fact('selinux') == 'true'
+            apply_manifest(pp, :catch_changes => true)
+          end
+        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)
+          unless fact('selinux') == 'true'
+            apply_manifest(pp, :catch_changes => true)
+          end
+        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
@@ -176,6 +285,118 @@ describe 'firewall type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfami
              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)
+            unless fact('selinux') == 'true'
+              apply_manifest(pp, :catch_changes => true)
+            end
+          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)
+            unless fact('selinux') == 'true'
+              apply_manifest(pp, :catch_changes => true)
+            end
+          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)
+            unless fact('selinux') == 'true'
+              apply_manifest(pp, :catch_changes => true)
+            end
+          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)
+            unless fact('selinux') == 'true'
+              apply_manifest(pp, :catch_changes => true)
+            end
+          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