From: Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
Date: Fri, 14 Jun 2013 11:08:38 +0000 (+0100)
Subject: Add support for --src-type and --dst-type
X-Git-Tag: list~7^2~1
X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=1890e0a30232cc05af840a2a0343756e06c76862;p=puppet-modules%2Fpuppetlabs-firewall.git

Add support for --src-type and --dst-type

Add support for filtering by source and destination address types. Supported by
iptables only, this feature allows filtering packets by the address type (such
as whether the packet came from a local address, a broadcast address, a
multicast address, etc).

Adds the `:address_type` feature to allow a provider to declare support for
filtering on the basis of address type.
---

diff --git a/lib/puppet/provider/firewall/iptables.rb b/lib/puppet/provider/firewall/iptables.rb
index 39f50a7..2616bc7 100644
--- a/lib/puppet/provider/firewall/iptables.rb
+++ b/lib/puppet/provider/firewall/iptables.rb
@@ -22,6 +22,7 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
   has_feature :pkttype
   has_feature :isfragment
   has_feature :socket
+  has_feature :address_type
 
   optional_commands({
     :iptables => 'iptables',
@@ -42,6 +43,7 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
   @resource_map = {
     :burst => "--limit-burst",
     :destination => "-d",
+    :destination_type => "-m addrtype --dst-type",
     :dport => ["-m multiport --dports", "-m (udp|tcp) --dport"],
     :gid => "-m owner --gid-owner",
     :icmp => "-m icmp --icmp-type",
@@ -58,6 +60,7 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir
     :set_mark => mark_flag,
     :socket => "-m socket",
     :source => "-s",
+    :source_type => "-m addrtype --src-type",
     :sport => ["-m multiport --sports", "-m (udp|tcp) --sport"],
     :state => "-m state --state",
     :table => "-t",
@@ -86,8 +89,10 @@ 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,
-    :proto, :isfragment, :tcp_flags, :gid, :uid, :sport, :dport, :port, :socket, :pkttype, :name, :state, :icmp, :limit, :burst,
-    :jump, :todest, :tosource, :toports, :log_prefix, :log_level, :reject, :set_mark]
+    :proto, :isfragment, :tcp_flags, :gid, :uid, :sport, :dport, :port,
+    :destination_type, :source_type, :socket, :pkttype, :name, :state, :icmp,
+    :limit, :burst, :jump, :todest, :tosource, :toports, :log_prefix,
+    :log_level, :reject, :set_mark]
 
   def insert
     debug 'Inserting rule %s' % resource[:name]
diff --git a/lib/puppet/type/firewall.rb b/lib/puppet/type/firewall.rb
index e451699..5ef40df 100644
--- a/lib/puppet/type/firewall.rb
+++ b/lib/puppet/type/firewall.rb
@@ -43,6 +43,7 @@ Puppet::Type.newtype(:firewall) do
   feature :pkttype, "Match a packet type"
   feature :socket, "Match open sockets"
   feature :isfragment, "Match fragments"
+  feature :address_type, "The ability match on source or destination address type"
 
   # provider specific features
   feature :iptables, "The provider provides iptables features."
@@ -221,6 +222,58 @@ Puppet::Type.newtype(:firewall) do
     end
   end
 
+  newproperty(:destination_type, :required_features => :address_type) do
+    desc <<-EOS
+      The destination address type. For example:
+
+          destination_type => 'LOCAL'
+
+      Can be one of:
+
+      * UNSPEC - an unspecified address
+      * UNICAST - a unicast address
+      * LOCAL - a local address
+      * BROADCAST - a broadcast address
+      * ANYCAST - an anycast packet
+      * MULTICAST - a multicast address
+      * BLACKHOLE - a blackhole address
+      * UNREACHABLE - an unreachable address
+      * PROHIBIT - a prohibited address
+      * THROW - undocumented
+      * NAT - undocumented
+      * XRESOLVE - undocumented
+    EOS
+
+    newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
+              :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
+  end
+
+  newproperty(:source_type, :required_features => :address_type) do
+    desc <<-EOS
+      The source address type. For example:
+
+          source_type => 'LOCAL'
+
+      Can be one of:
+
+      * UNSPEC - an unspecified address
+      * UNICAST - a unicast address
+      * LOCAL - a local address
+      * BROADCAST - a broadcast address
+      * ANYCAST - an anycast packet
+      * MULTICAST - a multicast address
+      * BLACKHOLE - a blackhole address
+      * UNREACHABLE - an unreachable address
+      * PROHIBIT - a prohibited address
+      * THROW - undocumented
+      * NAT - undocumented
+      * XRESOLVE - undocumented
+    EOS
+
+    newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
+              :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
+  end
+
   newproperty(:proto) do
     desc <<-EOS
       The specific protocol to match for this rule. By default this is
diff --git a/spec/fixtures/iptables/conversion_hash.rb b/spec/fixtures/iptables/conversion_hash.rb
index 2f30e5e..417c798 100644
--- a/spec/fixtures/iptables/conversion_hash.rb
+++ b/spec/fixtures/iptables/conversion_hash.rb
@@ -117,6 +117,20 @@ ARGS_TO_HASH = {
       :sport => ["15","512-1024"],
     },
   },
+  'destination_type_1' => {
+    :line => '-A INPUT -m addrtype --dst-type LOCAL',
+    :table => 'filter',
+    :params => {
+      :destination_type => 'LOCAL',
+    },
+  },
+  'source_type_1' => {
+    :line => '-A INPUT -m addrtype --src-type LOCAL',
+    :table => 'filter',
+    :params => {
+      :source_type => 'LOCAL',
+    },
+  },
   'tcp_flags_1' => {
     :line => '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"',
     :table => 'filter',
@@ -489,6 +503,22 @@ HASH_TO_ARGS = {
     },
     :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "15,512:1024", "-m", "comment", "--comment", "100 sport range"],
   },
+  'destination_type_1' => {
+    :params => {
+      :name => '000 destination_type',
+      :table => 'filter',
+      :destination_type => 'LOCAL',
+    },
+    :args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', :LOCAL, '-m', 'comment', '--comment', '000 destination_type'],
+  },
+  'source_type_1' => {
+    :params => {
+      :name => '000 source_type',
+      :table => 'filter',
+      :source_type => 'LOCAL',
+    },
+    :args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', :LOCAL, '-m', 'comment', '--comment', '000 source_type'],
+  },
   'tcp_flags_1' => {
     :params => {
       :name => "000 initiation",
diff --git a/spec/unit/puppet/type/firewall_spec.rb b/spec/unit/puppet/type/firewall_spec.rb
index db28b92..ac2ac55 100755
--- a/spec/unit/puppet/type/firewall_spec.rb
+++ b/spec/unit/puppet/type/firewall_spec.rb
@@ -172,6 +172,27 @@ describe firewall do
     end
   end
 
+  [:destination_type, :source_type].each do |addrtype|
+    describe addrtype do
+      it "should have no default" do
+        res = @class.new(:name => "000 test")
+        res.parameters[addrtype].should == nil
+      end
+    end
+
+    [:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE,
+     :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type|
+      it "should accept #{addrtype} value #{type}" do
+        @resource[addrtype] = type
+        @resource[addrtype].should == type
+      end
+    end
+
+    it "should fail when #{addrtype} value is not recognized" do
+      lambda { @resource[addrtype] = 'foo' }.should raise_error(Puppet::Error)
+    end
+  end
+
   [:iniface, :outiface].each do |iface|
     describe iface do
       it "should accept #{iface} value as a string" do