--- /dev/null
+class Puppet::Provider::Firewall < Puppet::Provider
+
+ # Prefetch our rule list. This is ran once every time before any other
+ # action (besides initialization of each object).
+ def self.prefetch(resources)
+ debug("[prefetch(resources)]")
+ instances.each do |prov|
+ if resource = resources[prov.name] || resources[prov.name.downcase]
+ resource.provider = prov
+ end
+ end
+ end
+
+ # Look up the current status. This allows us to conventiently look up
+ # existing status with properties[:foo].
+ def properties
+ if @property_hash.empty?
+ @property_hash = query || {:ensure => :absent}
+ @property_hash[:ensure] = :absent if @property_hash.empty?
+ end
+ @property_hash.dup
+ end
+
+ # Pull the current state of the list from the full list. We're
+ # getting some double entendre here....
+ def query
+ self.class.instances.each do |instance|
+ if instance.name == self.name or instance.name.downcase == self.name
+ return instance.properties
+ end
+ end
+ nil
+ end
+
+ # Executed if method is missing. In this case we are going to catch
+ # unqualified property methods for dynamic property setting and getting.
+ def method_missing(meth, *args, &block)
+ if @property_hash.keys.include?(meth) then
+ return @property_hash[meth.to_sym]
+ elsif @property_hash.keys.include?(meth.to_s.chomp("=").to_sym) then
+ @property_hash[:needs_change] = true
+ return true
+ end
+
+ super
+ end
+end
--- /dev/null
+require 'puppet/provider/firewall'
+
+Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Firewall do
+ include Puppet::Util::Firewall
+
+ @doc = "Iptables type provider"
+
+ commands :iptables => '/sbin/iptables'
+ commands :iptables_save => '/sbin/iptables-save'
+
+ defaultfor :operatingsystem => [:redhat, :debian, :ubuntu, :fedora, :suse, :centos, :sles, :oel, :ovm]
+ confine :operatingsystem => [:redhat, :debian, :ubuntu, :fedora, :suse, :centos, :sles, :oel, :ovm]
+
+ mk_resource_methods
+
+ @@resource_map = {
+ :burst => "--limit-burst",
+ :destination => "-d",
+ :dport => "-m multiport --dports",
+ :icmp => "-m icmp --icmp-type",
+ :iniface => "-i",
+ :jump => "-j",
+ :limit => "--limit",
+ :log_level => "--log-level",
+ :log_prefix => "--log-prefix",
+ :name => "-m comment --comment",
+ :outiface => "-o",
+ :proto => "-p",
+ :reject => "--reject-with",
+ :source => "-s",
+ :state => "-m state --state",
+ :sport => "-m multiport --sports",
+ :table => "-t",
+ :todest => "--to-destination",
+ :toports => "--to-ports",
+ :tosource => "--to-source",
+ }
+
+ @@resource_list = [:table, :source, :destination, :iniface, :outiface, :proto, :sport, :dport, :tosource, :todest,
+ :reject, :log_level, :log_prefix, :name, :state, :icmp, :limit, :burst, :toports, :jump]
+
+
+ def insert
+ debug 'Inserting rule %s' % resource[:name]
+ iptables insert_args
+ end
+
+ def update
+ debug 'Updating rule %s' % resource[:name]
+ iptables update_args
+ end
+
+ def delete
+ debug 'Deleting rule %s' % resource[:name]
+ iptables "-D", properties[:chain], properties[:rulenum]
+ end
+
+ def exists?
+ properties[:ensure] != :absent
+ end
+
+ # Flush the property hash once done.
+ def flush
+ debug("[flush]")
+ needs_change = @property_hash.delete(:needs_change)
+ if needs_change
+ notice("Properties changed - updating rule")
+ update
+ end
+ @property_hash.clear
+ end
+
+ def self.instances
+ debug "[instances]"
+ table = nil
+ rules = []
+ iptables_save.lines do |line|
+ unless line =~ /^\#\s+|^\:\S+|^COMMIT/
+ if line =~ /^\*/
+ table = line.sub(/\*/, "").chomp!
+ else
+ if hash = rule_to_hash(line, table)
+ rules << new(hash)
+ end
+ end
+ end
+ end
+ rules
+ end
+
+ def self.rule_to_hash(line, table)
+ hash = {}
+ keys = []
+ values = line.dup
+
+ @@resource_list.reverse.each do |k|
+ if values.slice!(@@resource_map[k])
+ keys << k
+ end
+ end
+
+ # Manually remove chain
+ values.slice!('-A')
+ keys << :chain
+
+ keys.zip(values.scan(/"[^"]*"|\S+/).reverse) { |f, v| hash[f] = v.gsub(/"/, '') }
+ hash[:provider] = self.name.to_s
+ hash[:table] = table
+ hash[:ensure] = :present
+ hash
+ end
+
+ def insert_args
+ args = []
+ args << ["-I", resource[:chain], insert_order]
+ args << general_args
+ args
+ end
+
+ def update_args
+ args = []
+ args << ["-R", resource[:chain], properties[:rulenum]]
+ args << general_args
+ args
+ end
+
+ def general_args
+ debug "Current resource: %s" % resource.class
+ args = []
+ @@resource_list.each do |res|
+ if(resource.value(res))
+ args << @@resource_map[res].split(' ')
+ args << resource[res]
+ end
+ end
+ args
+ end
+
+ def insert_order
+ debug("[insert_order]")
+ rules = []
+
+ # Find list of current rules based on chain
+ self.class.instances.each do |rule|
+ next unless rule.chain == resource[:chain]
+ rules << rule
+ end
+
+ # No rules at all? Just bail now.
+ return 1 if rules.empty?
+
+ my_rule = resource[:name].to_s
+ rules << my_rule
+ rules.sort.index(my_rule) + 1
+ end
+end