]> review.fuel-infra Code Review - puppet-modules/puppetlabs-firewall.git/commitdiff
(FM-4896) add NFLOG support
authorEric Putnam <eric.putnam@eric.putnam-C02L5064FFT1>
Wed, 3 May 2017 20:17:21 +0000 (13:17 -0700)
committerEric Putnam <putnam.eric@gmail.com>
Thu, 4 May 2017 00:04:53 +0000 (17:04 -0700)
This adds four new features to the firewall type: nflog_groups, _range, _prefix, and _threshold. Unit tests and acceptance tests were also added.

README.markdown
lib/puppet/provider/firewall/iptables.rb
lib/puppet/type/firewall.rb
spec/acceptance/nflog_spec.rb [new file with mode: 0644]
spec/unit/puppet/type/firewall_spec.rb

index a2074256455eae23d75b4aed0186e0c0bd7519dd..3f747f85e30bb681a78e3b77591a07c9addc8fa8 100644 (file)
@@ -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.
index 7416085f669763fc92f8c6e587eef483b081939e..35142d0ea967b303446c8022978fcf7ccbc32dcf 100644 (file)
@@ -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])
index 2fa46092bf71c993aaef516596dde91c1a8be7b0..c480beb4a411827d99cba073570e6a28d49c1c97 100644 (file)
@@ -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 (file)
index 0000000..d5f7a70
--- /dev/null
@@ -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
index a34963cb82a0bd1a1b5f395d2771c984e639b477..793c0fa450aa5e97136d5d0666966f062a82d0b7 100755 (executable)
@@ -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 => {