fuel-plugin-vxlan/deployment_scripts/puppet/modules/firewall/lib/puppet/provider/firewallchain/iptables_chain.rb

179 lines
4.9 KiB
Ruby

Puppet::Type.type(:firewallchain).provide :iptables_chain do
include Puppet::Util::Firewall
@doc = "Iptables chain provider"
has_feature :iptables_chain
has_feature :policy
optional_commands({
:iptables => 'iptables',
:iptables_save => 'iptables-save',
:ip6tables => 'ip6tables',
:ip6tables_save => 'ip6tables-save',
:ebtables => 'ebtables',
:ebtables_save => 'ebtables-save',
})
defaultfor :kernel => :linux
# chain name is greedy so we anchor from the end.
# [\d+:\d+] doesn't exist on ebtables
Mapping = {
:IPv4 => {
:tables => method(:iptables),
:save => method(:iptables_save),
:re => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
},
:IPv6 => {
:tables => method(:ip6tables),
:save => method(:ip6tables_save),
:re => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
},
:ethernet => {
:tables => method(:ebtables),
:save => method(:ebtables_save),
:re => /^:(.+)\s(\S+)$/,
}
}
InternalChains = /^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$/
Tables = 'nat|mangle|filter|raw|rawpost|broute'
Nameformat = /^(.+):(#{Tables}):(IP(v[46])?|ethernet)$/
def create
allvalidchains do |t, chain, table, protocol|
if chain =~ InternalChains
# can't create internal chains
warning "Attempting to create internal chain #{@resource[:name]}"
end
if properties[:ensure] == protocol
debug "Skipping Inserting chain #{chain} on table #{table} (#{protocol}) already exists"
else
debug "Inserting chain #{chain} on table #{table} (#{protocol}) using #{t}"
t.call ['-t',table,'-N',chain]
unless @resource[:policy].nil?
t.call ['-t',table,'-P',chain,@resource[:policy].to_s.upcase]
end
end
end
end
def destroy
allvalidchains do |t, chain, table|
if chain =~ InternalChains
# can't delete internal chains
warning "Attempting to destroy internal chain #{@resource[:name]}"
end
debug "Deleting chain #{chain} on table #{table}"
t.call ['-t',table,'-X',chain]
end
end
def exists?
allvalidchains do |t, chain|
if chain =~ InternalChains
# If the chain isn't present, it's likely because the module isn't loaded.
# If this is true, then we fall into 2 cases
# 1) It'll be loaded on demand
# 2) It won't be loaded on demand, and we throw an error
# This is the intended behavior as it's not the provider's job to load kernel modules
# So we pretend it exists...
return true
end
end
properties[:ensure] == :present
end
def policy=(value)
return if value == :empty
allvalidchains do |t, chain, table|
p = ['-t',table,'-P',chain,value.to_s.upcase]
debug "[set policy] #{t} #{p}"
t.call p
end
end
def policy
debug "[get policy] #{@resource[:name]} =#{@property_hash[:policy].to_s.downcase}"
return @property_hash[:policy].to_s.downcase
end
def self.prefetch(resources)
debug("[prefetch(resources)]")
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end
def flush
debug("[flush]")
persist_iptables(@resource[:name].match(Nameformat)[3])
# Clear the property hash so we re-initialize with updated values
@property_hash.clear
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}
end
@property_hash.dup
end
# Pull the current state of the list from the full list.
def query
self.class.instances.each do |instance|
if instance.name == self.name
debug "query found #{self.name}" % instance.properties.inspect
return instance.properties
end
end
nil
end
def self.instances
debug "[instances]"
table = nil
chains = []
Mapping.each { |p, c|
begin
c[:save].call.each_line do |line|
if line =~ c[:re] then
name = $1 + ':' + (table == 'filter' ? 'filter' : table) + ':' + p.to_s
policy = $2 == '-' ? nil : $2.downcase.to_sym
chains << new({
:name => name,
:policy => policy,
:ensure => :present,
})
debug "[instance] '#{name}' #{policy}"
elsif line =~ /^\*(\S+)/
table = $1
else
next
end
end
rescue Puppet::Error
# ignore command not found for ebtables or anything that doesn't exist
end
}
chains
end
def allvalidchains
@resource[:name].match(Nameformat)
chain = $1
table = $2
protocol = $3
yield Mapping[protocol.to_sym][:tables],chain,table,protocol.to_sym
end
end