From: Eric Putnam Date: Wed, 3 May 2017 20:17:21 +0000 (-0700) Subject: (FM-4896) add NFLOG support X-Git-Tag: 1.9.0~4^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=c0e4053f0693ee797eda8e50b6d5cbf21b89b949;p=puppet-modules%2Fpuppetlabs-firewall.git (FM-4896) add NFLOG support This adds four new features to the firewall type: nflog_groups, _range, _prefix, and _threshold. Unit tests and acceptance tests were also added. --- diff --git a/README.markdown b/README.markdown index a207425..3f747f8 100644 --- a/README.markdown +++ b/README.markdown @@ -341,6 +341,19 @@ firewall { '100 my rule': } ~~~ +Setup NFLOG for a rule. + +~~~puppet +firewall {'666 for NFLOG': + proto => 'all', + jump => 'NFLOG', + nflog_group => 3, + nflog_prefix => "nflog-test", + nflog_range = 256, + nflog_threshold => 1, +} +~~~ + ### Additional Information Access the inline documentation: @@ -590,7 +603,7 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov * `islastfrag`: If true, matches when the packet is the last fragment of a fragmented ipv6 packet. Supported by ipv6 only. Valid values are 'true', 'false'. Requires the `islastfrag`. -* `jump`: The value for the iptables `--jump` parameter. Any valid chain name is allowed, but normal values are: 'QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK', 'TCPMSS', 'DSCP'. +* `jump`: The value for the iptables `--jump` parameter. Any valid chain name is allowed, but normal values are: 'QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK', 'TCPMSS', 'DSCP', 'NFLOG'. For the values 'ACCEPT', 'DROP', and 'REJECT', you must use the generic `action` parameter. This is to enforce the use of generic parameters where possible for maximum cross-platform modeling. @@ -610,6 +623,14 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov * `log_uid`: The ability to log the userid of the process which generated the packet. +* `nflog_group`: When combined with `jump => 'NFLOG'` grants the ability to specify the NFLOG group number. Requires the `nflog_group` feature. + +* `nflog_prefix`: When combined with `jump => 'NFLOG'` grants the ability to specify a prefix for log entries. Requires the `nflog_prefix` feature. + +* `nflog_range`: When combined with `jump => 'NFLOG'` grants the ability to specify the number of bytes to be copied to userspace. Requires the `nflog_range` feature. + +* `nflog_threshold`: When combined with `jump => 'NFLOG'` grants the ability to specify the size of the NFLOG threshold. Requires the `nflog_threshold` feature. + * `mask`: Sets the mask to use when `recent` is enabled. Requires the `mask` feature. * `month_days`: Only match on the given days of the month. Possible values are '1' to '31'. Note that specifying '31' will not match on months that do not have a 31st day; the same goes for 28- or 29-day February. diff --git a/lib/puppet/provider/firewall/iptables.rb b/lib/puppet/provider/firewall/iptables.rb index 7416085..35142d0 100644 --- a/lib/puppet/provider/firewall/iptables.rb +++ b/lib/puppet/provider/firewall/iptables.rb @@ -23,6 +23,10 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir has_feature :log_uid has_feature :mark has_feature :mss + has_feature :nflog_group + has_feature :nflog_prefix + has_feature :nflog_range + has_feature :nflog_threshold has_feature :tcp_flags has_feature :pkttype has_feature :isfragment @@ -88,6 +92,10 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir :match_mark => "-m mark --mark", :mss => '-m tcpmss --mss', :name => "-m comment --comment", + :nflog_group => "--nflog-group", + :nflog_prefix => "--nflog-prefix", + :nflog_range => "--nflog-range", + :nflog_threshold => "--nflog-threshold", :outiface => "-o", :pkttype => "-m pkttype --pkt-type", :port => '-m multiport --ports', @@ -279,11 +287,11 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo, :string_from, :string_to, :jump, :goto, :clusterip_new, :clusterip_hashmode, :clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init, :queue_num, :queue_bypass, - :clamp_mss_to_pmtu, :gateway, :set_mss, :set_dscp, :set_dscp_class, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix, + :nflog_group, :nflog_prefix, :nflog_range, :nflog_threshold, :clamp_mss_to_pmtu, :gateway, + :set_mss, :set_dscp, :set_dscp_class, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix, :log_level, :log_uid, :reject, :set_mark, :match_mark, :mss, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone, - :src_cc, :dst_cc - ] + :src_cc, :dst_cc ] def insert debug 'Inserting rule %s' % resource[:name] @@ -501,7 +509,6 @@ Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Fir end end - # Convert booleans removing the previous cludge we did @known_booleans.each do |bool| unless [nil, 'true', '!'].include?(hash[bool]) diff --git a/lib/puppet/type/firewall.rb b/lib/puppet/type/firewall.rb index 2fa4609..c480beb 100644 --- a/lib/puppet/type/firewall.rb +++ b/lib/puppet/type/firewall.rb @@ -57,6 +57,10 @@ Puppet::Type.newtype(:firewall) do feature :ipsec_policy, "Match IPsec policy" feature :ipsec_dir, "Match IPsec policy direction" feature :mask, "Ability to match recent rules based on the ipv4 mask" + feature :nflog_group, "netlink group to subscribe to for logging" + feature :nflog_prefix, "" + feature :nflog_range, "" + feature :nflog_threshold, "" feature :ipset, "Match against specified ipset list" feature :clusterip, "Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them." feature :length, "Match the length of layer-3 payload" @@ -448,6 +452,7 @@ Puppet::Type.newtype(:firewall) do * DNAT * SNAT * LOG + * NFLOG * MASQUERADE * REDIRECT * MARK @@ -618,6 +623,67 @@ Puppet::Type.newtype(:firewall) do newvalues(:true, :false) end + newproperty(:nflog_group, :required_features => :nflog_group) do + desc <<-EOS + Used with the jump target NFLOG. + The netlink group (0 - 2^16-1) to which packets are (only applicable + for nfnetlink_log). Defaults to 0. + EOS + + validate do |value| + if value.to_i > (2**16)-1 || value.to_i < 0 + raise ArgumentError, "nflog_group must be between 0 and 2^16-1" + end + end + + munge do |value| + if value.is_a?(String) and value =~ /^[-0-9]+$/ + Integer(value) + else + value + end + end + end + + newproperty(:nflog_prefix, :required_features => :nflog_prefix) do + desc <<-EOS + Used with the jump target NFLOG. + A prefix string to include in the log message, up to 64 characters long, + useful for distinguishing messages in the logs. + EOS + + validate do |value| + if value.length > 64 + raise ArgumentError, "nflog_prefix must be less than 64 characters." + end + end + end + + newproperty(:nflog_range, :required_features => :nflog_range) do + desc <<-EOS + Used with the jump target NFLOG. + The number of bytes to be copied to userspace (only applicable for nfnetlink_log). + nfnetlink_log instances may specify their own range, this option overrides it. + EOS + end + + newproperty(:nflog_threshold, :required_features => :nflog_threshold) do + desc <<-EOS + Used with the jump target NFLOG. + Number of packets to queue inside the kernel before sending them to userspace + (only applicable for nfnetlink_log). Higher values result in less overhead + per packet, but increase delay until the packets reach userspace. Defaults to 1. + EOS + + munge do |value| + if value.is_a?(String) and value =~ /^[-0-9]+$/ + Integer(value) + else + value + end + end + end + # ICMP matching property newproperty(:icmp, :required_features => :icmp_match) do desc <<-EOS diff --git a/spec/acceptance/nflog_spec.rb b/spec/acceptance/nflog_spec.rb new file mode 100644 index 0000000..d5f7a70 --- /dev/null +++ b/spec/acceptance/nflog_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper_acceptance' + +describe 'nflog' do + describe 'nflog_group' do + + let(:group) { 3 } + + it 'applies' do + pp = <<-EOS + class {'::firewall': } + firewall { '503 - test': + jump => 'NFLOG', + proto => 'all', + nflog_group => #{group}, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'contains the rule' do + shell('iptables-save') do |r| + expect(r.stdout).to match(/NFLOG --nflog-group #{group}/) + end + end + end + + describe 'nflog_prefix' do + + let(:prefix) { "TEST PREFIX" } + + it 'applies' do + pp = <<-EOS + class {'::firewall': } + firewall { '503 - test': + jump => 'NFLOG', + proto => 'all', + nflog_prefix => '#{prefix}', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'contains the rule' do + shell('iptables-save') do |r| + expect(r.stdout).to match(/NFLOG --nflog-prefix "#{prefix}"/) + end + end + end + + describe 'nflog_range' do + + let(:range) { 16 } + + it 'applies' do + pp = <<-EOS + class {'::firewall': } + firewall { '503 - test': + jump => 'NFLOG', + proto => 'all', + nflog_range => #{range}, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'contains the rule' do + shell('iptables-save') do |r| + expect(r.stdout).to match(/NFLOG --nflog-range #{range}/) + end + end + end + + describe 'nflog_threshold' do + + let(:threshold) { 2 } + + it 'applies' do + pp = <<-EOS + class {'::firewall': } + firewall { '503 - test': + jump => 'NFLOG', + proto => 'all', + nflog_threshold => #{threshold}, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'contains the rule' do + shell('iptables-save') do |r| + expect(r.stdout).to match(/NFLOG --nflog-threshold #{threshold}/) + end + end + end + + describe 'multiple rules' do + let(:threshold) { 2 } + let(:group) { 3 } + + it 'applies' do + pp = <<-EOS + class {'::firewall': } + firewall { '503 - test': + jump => 'NFLOG', + proto => 'all', + nflog_threshold => #{threshold}, + nflog_group => #{group} + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'contains the rules' do + shell('iptables-save') do |r| + expect(r.stdout).to match(/NFLOG --nflog-group #{group} --nflog-threshold #{threshold}/) + end + end + + end +end diff --git a/spec/unit/puppet/type/firewall_spec.rb b/spec/unit/puppet/type/firewall_spec.rb index a34963c..793c0fa 100755 --- a/spec/unit/puppet/type/firewall_spec.rb +++ b/spec/unit/puppet/type/firewall_spec.rb @@ -100,7 +100,7 @@ describe firewall do expect(res.parameters[:jump]).to eql nil end - ['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump| + ['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'NFLOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump| it "should accept jump value #{jump}" do @resource[:jump] = jump expect(@resource[:jump]).to eql jump @@ -263,6 +263,38 @@ describe firewall do end end + describe 'NFLOG' do + describe ':nflog_group' do + + [0,1,5,10].each do |v| + it { + @resource[:nflog_group] = v + expect(@resource[:nflog_group]).to eq v + } + end + + [-3,999999].each do |v| + it { + expect(lambda { @resource[:nflog_group] = v }).to raise_error(Puppet::Error, /2\^16\-1/) + } + end + end + + describe ':nflog_prefix' do + let(:valid_prefix) { "This is a valid prefix" } + let(:invalid_prefix) { "This is not a valid prefix. !t is longer than 64 char@cters for sure. How do I know? I c0unted." } + + it { + @resource[:nflog_prefix] = valid_prefix + expect(@resource[:nflog_prefix]).to eq valid_prefix + } + + it { + expect(lambda { @resource[:nflog_prefix] = invalid_prefix }).to raise_error(Puppet::Error, /64 characters/) + } + end + end + describe ':icmp' do icmp_codes = { :iptables => {