From 1890e0a30232cc05af840a2a0343756e06c76862 Mon Sep 17 00:00:00 2001 From: Nick Stenning Date: Fri, 14 Jun 2013 12:08:38 +0100 Subject: [PATCH] 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. --- lib/puppet/provider/firewall/iptables.rb | 9 +++- lib/puppet/type/firewall.rb | 53 +++++++++++++++++++++++ spec/fixtures/iptables/conversion_hash.rb | 30 +++++++++++++ spec/unit/puppet/type/firewall_spec.rb | 21 +++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) 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 -- 2.45.2