]> review.fuel-infra Code Review - puppet-modules/puppetlabs-firewall.git/commitdiff
add firewall type to module
authorJonathan Boyett <jonathan@failingservers.com>
Mon, 9 May 2011 17:31:14 +0000 (10:31 -0700)
committerJonathan Boyett <jonathan@failingservers.com>
Mon, 9 May 2011 17:31:14 +0000 (10:31 -0700)
lib/puppet/type/firewall.rb [new file with mode: 0644]

diff --git a/lib/puppet/type/firewall.rb b/lib/puppet/type/firewall.rb
new file mode 100644 (file)
index 0000000..e29f4eb
--- /dev/null
@@ -0,0 +1,268 @@
+# Puppet Firewall Module
+#
+# Copyright (C) 2011 Bob.sh Limited
+# Copyright (C) 2008 Camptocamp Association
+# Copyright (C) 2007 Dmitri Priimak
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+require 'puppet/util/firewall'
+require 'puppet/util/ipcidr'
+
+Puppet::Type.newtype(:firewall) do
+  @doc = "Manipulate firewall rules"
+
+  ensurable do
+    desc "Create or remove this rule."
+
+    newvalue(:present) do
+      provider.insert
+    end
+
+    newvalue(:absent) do
+      provider.delete
+    end
+
+    defaultto :present
+  end
+
+  newparam(:name) do
+    desc "The name of the rule."
+    isnamevar
+
+    # Keep rule names simple
+    validate do |value|
+      if value !~ /^[a-zA-Z0-9 \-_]+$/ then
+        self.fail "Not a valid rule name. Make sure it contains ASCII " \
+          "alphanumeric, spaces, hyphens or underscoares."
+      end
+    end
+  end
+
+  newproperty(:rulenum) do
+    desc "A read only parameter which indicates the row number for this
+      rule."
+
+    validate do
+      fail "rulenum is read-only"
+    end
+  end
+
+  newproperty(:chain) do
+    desc "The value for the iptables -A parameter.
+      Possible values are: 'INPUT', 'FORWARD', 'OUTPUT', 'PREROUTING', 'POSTROUTING'.
+      Default value is 'INPUT'"
+    newvalues(:INPUT, :FORWARD, :OUTPUT, :PREROUTING, :POSTROUTING)
+    defaultto "INPUT"
+  end
+
+  newproperty(:table) do
+    desc "The value for the iptables -t parameter.
+      Possible values are: 'nat', 'mangle', 'filter' and 'raw'.
+      Default value is 'filter'"
+    newvalues(:nat, :mangle, :filter, :raw)
+    defaultto "filter"
+  end
+
+  newproperty(:proto) do
+    desc "The value for the iptables --protocol parameter.
+      Possible values are: 'tcp', 'udp', 'icmp', 'esp', 'ah', 'vrrp',
+      'igmp', 'all'.
+      Default value is 'tcp'"
+    newvalues(:tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :all)
+    defaultto "tcp"
+  end
+
+  newproperty(:jump) do
+    desc "The value for the iptables --jump parameter.
+      Possible values are: 'ACCEPT', 'DROP', 'QUEUE', 'RETURN',
+      REJECT', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT'.
+      Default value is 'ACCEPT'"
+    newvalues(:ACCEPT, :DROP, :QUEUE, :RETURN, :REJECT, :DNAT, :SNAT, :LOG,
+              :MASQUERADE, :REDIRECT)
+    defaultto "ACCEPT"
+  end
+
+  newproperty(:source) do
+    desc "The value for the iptables --source parameter.
+      Accepts a single string or array."
+  end
+
+  newproperty(:destination) do
+    desc "The value for the iptables --destination parameter.
+      Accepts a single string or array."
+  end
+
+  newproperty(:sport) do
+    desc "The value for the iptables --destination-port parameter.
+      If an array is specified, values will be passed to multiport module."
+
+    validate do |value|
+      if value.is_a?(Array) && value.length > 15
+        self.fail "multiport module only accepts <= 15 ports"
+      end
+    end
+  end
+
+  newproperty(:iniface) do
+    desc "The value for the iptables --in-interface parameter"
+  end
+
+  newproperty(:outiface) do
+    desc "The value for the iptables --out-interface parameter"
+  end
+
+  newproperty(:tosource) do
+    desc "The value for the iptables --to-source parameter"
+  end
+
+  newproperty(:todest) do
+    desc "The value for the iptables --to-destination parameter"
+  end
+
+  newproperty(:toports) do
+    desc "The value for the iptables --to-ports parameter"
+  end
+
+  newproperty(:reject) do
+    desc "The value for the iptables --reject-with parameter"
+  end
+
+  newproperty(:log_level) do
+    desc "The value for the iptables --log-level parameter"
+  end
+
+  newproperty(:log_prefix) do
+    desc "The value for the iptables --log-level parameter"
+  end
+
+  newproperty(:icmp) do
+    desc "The value for the iptables --icmp-type parameter"
+
+    munge do |value|
+      num = @resource.icmp_name_to_number(value)
+      if num == nil && value != ""
+        self.fail("cannot work out icmp type")
+      end
+      num
+    end
+  end
+
+  newproperty(:state) do
+    desc "The value for the iptables -m state --state parameter.
+      Possible values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED'.
+      Accepts a single string or array."
+  end
+
+  newproperty(:limit) do
+    desc "The value for the iptables -m limit --limit parameter.
+      Example values are: '50/sec', '40/min', '30/hour', '10/day'."
+  end
+
+  newproperty(:burst) do
+    desc "The value for the iptables --limit-burst parameter."
+
+    validate do |value|
+      if value.to_s !~ /^[0-9]+$/
+        self.fail "burst accepts only numeric values"
+      end
+    end
+  end
+  
+  validate do
+    debug("[validate]")
+
+    # TODO: this is put here to skip validation if ensure is not set. This
+    # is because there is a revalidation stage called later where the values
+    # are not set correctly. I tried tracing it - but have put in this
+    # workaround instead to skip. Must get to the bottom of this.
+    if ! value(:ensure)
+      return
+    end
+
+    # First we make sure the chains and tables are valid combinations
+    if value(:table).to_s == "filter" && value(:chain) =~ /PREROUTING|POSTROUTING/
+      self.fail "PREROUTING and POSTROUTING cannot be used in table 'filter'"
+    end
+
+    if value(:table).to_s == "nat" && value(:chain) =~ /INPUT|FORWARD/
+      self.fail "INPUT and FORWARD cannot be used in table 'nat'"
+    end
+
+    if value(:table).to_s == "raw" && value(:chain) =~ /INPUT|FORWARD|POSTROUTING/
+      self.fail "INPUT, FORWARD and POSTROUTING cannot be used in table raw"
+    end
+
+    # Now we analyse the individual properties to make sure they apply to
+    # the correct combinations.
+    if value(:iniface)
+      unless value(:chain) =~ /INPUT|FORWARD|PREROUTING/
+        self.fail "Parameter iniface only applies to chains " \
+          "INPUT,FORWARD,PREROUTING"
+      end
+    end
+
+    if value(:outiface)
+      unless value(:chain) =~ /INPUT|FORWARD|PREROUTING/
+        self.fail "Parameter outiface only applies to chains " \
+          "INPUT,FORWARD,PREROUTING"
+      end
+    end
+
+    if value(:dport)
+      unless value(:proto) =~ /tcp|udp|sctp/
+        self.fail "[%s] Parameter dport only applies to sctp, tcp and udp " \
+          "protocols. Current protocol is [%s] and dport is [%s]" %
+          [value(:name), should(:proto), should(:dport)]
+      end
+    end
+
+    if value(:jump).to_s == "DNAT"
+      unless value(:table).to_s =~ /nat/
+        self.fail "Parameter jump => DNAT only applies to table => nat"
+      end
+
+      unless value(:todest)
+        self.fail "Parameter jump => DNAT must have todest parameter"
+      end
+    end
+
+    if value(:jump).to_s == "SNAT"
+      unless value(:table).to_s =~ /nat/
+        self.fail "Parameter jump => SNAT only applies to table => nat"
+      end
+
+      unless value(:tosource)
+        self.fail "Parameter jump => DNAT must have tosource parameter"
+      end
+    end
+
+    if value(:jump).to_s == "REDIRECT"
+      unless value(:toports)
+        self.fail "Parameter jump => REDIRECT missing mandatory toports " \
+          "parameter"
+      end
+    end
+
+    if value(:jump).to_s == "MASQUERADE"
+      unless value(:table) =~ /nat/
+        self.fail "Parameter jump => MASQUERADE only applies to table => nat"
+      end
+    end
+
+    if value(:burst) && ! value(:limit)
+      self.fail "burst makes no sense without limit"
+    end
+  end
+end