File: //var/lib/puppet/lib/puppet/provider/csf/parsed.rb
require 'puppet/util/logging'
require 'facter'
#Provider is very important to have
Puppet::Type.type(:csf).provide(:csf, :parent => Puppet::Provider) do
desc "Setup allowed IPs, TCP/UDP ports, CSF state, and ICMP settings"
attr_accessor :tcp_out #Array of TCP_OUT ports
attr_accessor :tcp_in #Array of TCP_IN ports
attr_accessor :udp_out #Array of UDP_OUT ports
attr_accessor :udp_in #Array of UDP_IN ports
attr_accessor :closed_ports #Array of blocked ports
attr_accessor :allowed_ips #Array of ips for csf.allow
attr_accessor :blocked_ips #Array of ips for csf.deny
attr_accessor :allow_icmp #Boolean whether or not to use ICMP
attr_accessor :icmp_rate #ICMP rate in the form '\d+/s'
attr_accessor :purge #This will enforce that the given settings, and only the given settings are present. Make sure all ports and IPs are present!
attr_accessor :enabled #Whether to force CSF to be enabled or disabled
attr_accessor :skip_enable_check #If the file /etc/.csf_disabled is present, and has been touched less than 24 hours ago, skip the 'enable' check
def initialize(resource)
super(resource)
@tcp_out = []
@tcp_in = []
@udp_out = []
@udp_in = []
@allowed_ips = []
@blocked_ips = []
@allow_icmp = true
@icmp_rate = '10/s'
@enabled = Facter.value('csf_enabled')
@skip_enable_check = false
end
def self.prefetch(resources = nil)
if not File.exists?('/usr/sbin/csf')
raise Puppet::Error "Could not find csf binary"
end
if not File.exists?('/etc/csf/csf.conf')
raise Puppet::Error "Could not find csf configuration"
end
#Resources are the individual instances of type... I think
if resources != nil
begin
f = File.new('/etc/csf/csf.conf','r')
while( line = f.gets ) do
if line =~ /^\s*#/
next
elsif line =~ /^TCP_OUT\s*=\s*"(\d+(:\d+)?(,\d+(:\d+)?)*)?"\s*$/
resources.each do |hash, instance|
instance.provider.tcp_out= $1.split(',')
end
elsif line =~ /^TCP_IN\s*=\s*"(\d+(:\d+)?(,\d+(:\d+)?)*)?"\s*$/
resources.each do |hash, instance|
instance.provider.tcp_in= $1.split(',')
end
elsif line =~ /^UDP_OUT\s*=\s*"(\d+(:\d+)?(,\d+(:\d+)?)*)?"\s*$/
resources.each do |hash, instance|
instance.provider.udp_out= $1.split(',')
end
elsif line =~ /^UDP_IN\s*=\s*"(\d+(:\d+)?(,\d+(:\d+)?)*)?"\s*$/
resources.each do |hash, instance|
instance.provider.udp_in= $1.split(',')
end
elsif line =~ /^ICMP_IN\s*=\s*"(0|1)"\s*$/
resources.each do |hash, instance|
instance.provider.allow_icmp= ( $1 == "1" ? true : false )
end
elsif line =~ /^ICMP_IN_RATE\s*=\s*"(\d+\/s)"\s*$/
resources.each do |hash, instance|
instance.provider.icmp_rate= $1.chomp
end
end
end
f.close
rescue IOError => e
raise Puppet::Error "Could not read csf configuration file (#{e})"
end
skip_check = false
if File.exists?('/etc/.csf_disabled')
if Time.now.to_i - File.mtime("/etc/.csf_disabled").to_i > 86400
begin
File.unlink("/etc/.csf_disabled")
rescue
end
else
skip_check = true
end
end
resources.each do |hash, instance|
instance.provider.skip_enable_check= skip_check
end
begin
f = File.new('/etc/csf/csf.allow','r')
while( line = f.gets ) do
if line =~ /^\s*#/
next
elsif line =~ /^(\d+\.\d+\.\d+\.\d+)/
resources.each do |hash, instance|
instance.provider.allowed_ips.push $1.chomp
end
end
end
f.close
rescue IOError => e
raise Puppet::Error "Could not read csf allowed ips file (#{e})"
end
begin
f = File.new('/etc/csf/csf.deny','r')
while( line = f.gets ) do
if line =~ /^\s*#/
next
elsif line =~ /^(\d+\.\d+\.\d+\.\d+)/
resources.each do |hash, instance|
instance.provider.blocked_ips.push $1.chomp
end
end
end
f.close
rescue IOError => e
raise Puppet::Error "Could not read csf denied ips file (#{e})"
end
end
end
def flush
if ! @skip_enable_check
if @resource.should(:enabled) == :true and Facter.value(:csf_enabled) == "false"
Puppet.info "Enabling CSF"
output = %x{/usr/sbin/csf -e}
ret = $?.success?
elsif @resource.should(:enabled) == :false and Facter.value(:csf_enabled) == "true"
Puppet.info "Disabling CSF"
output = %x{/usr/sbin/csf -x}
ret = $?.success?
end
end
begin
fin = File.new('/etc/csf/csf.conf','r')
fout = File.new('/etc/csf/csf.conf.puppetnew','w')
while( line = fin.gets ) do
if line =~ /^\s*#/
fout.write(line)
#elsif line =~ /^((?:TCP|UDP)_(?:IN|OUT))\s*=\s*"(\d+(?:,\d+)*)?"\s*$/
elsif line =~ /^((?:TCP|UDP)_(?:IN|OUT))\s*=\s*"(\d+(?::\d+)?(?:,\d+(?::\d+)?)*)?"\s*$/
type = $1
case $1
when 'TCP_OUT':
desired_ports = @resource.value(:tcp_out)
when 'TCP_IN':
desired_ports = @resource.value(:tcp_in)
when 'UDP_OUT':
desired_ports = @resource.value(:udp_out)
when 'UDP_IN':
desired_ports = @resource.value(:udp_in)
end
real_ports = $2.split(',')
if @resource.value(:closed_ports) != [:absent] and @resource.value(:closed_ports) != :absent
@resource.value(:closed_ports).each do |p|
if (loc = real_ports.index(p) ) != nil
real_ports.delete_at(loc)
end
end
end
if desired_ports != [:absent] and desired_ports != :absent
if @resource.value(:purge) == :true
ports = desired_ports
else
ports = real_ports
desired_ports.each do |p|
if ! real_ports.include?(p)
ports.push(p)
end
end
end
fout.write("#{type} = \"#{ports.join(',')}\"\n")
else
fout.write(line)
end
elsif line =~ /^ICMP_IN\s*=\s*"(0|1)"\s*$/
if @resource.value(:allow_icmp) == true
fout.write("ICMP_IN = \"1\"\n")
elsif @resource.value(:allow_icmp) == false
fout.write("ICMP_IN = \"0\"\n")
else
fout.write(line)
end
elsif line =~ /^ICMP_IN_RATE\s*=\s*"(\d+\/s)"\s*$/
if @resource.value(:icmp_rate) != [:absent] and @resource.value(:icmp_rate) != :absent
fout.write("ICMP_IN_RATE = \"#{@resource.value(:icmp_rate)}\"\n")
else
fout.write(line)
end
else
fout.write(line)
end
end
fin.close
fout.close
File.rename('/etc/csf/csf.conf.puppetnew','/etc/csf/csf.conf')
rescue IOError => e
raise Puppet::Error "Could not read csf configuration file (#{e})"
end
#Denied ips
if @resource.should(:blocked_ips) != [:absent] and @resource.should(:blocked_ips) != :absent
begin
fin = File.new('/etc/csf/csf.deny','r')
fout = File.new('/etc/csf/csf.deny.puppetnew','w')
desired_ips = @resource.value(:blocked_ips)
if @resource.value(:purge) != :true
while( line = fin.gets ) do
fout.write(line)
if line =~ /^\s*((\d{1,3}\.){3}(\d{1,3}))/
#Requested IP already exists
if (loc = desired_ips.index($1)) != nil
desired_ips.delete_at(loc)
end
end
end
end
desired_ips.each do |ip|
fout.write("#{ip}\n")
end
fin.close
fout.close
File.rename('/etc/csf/csf.deny.puppetnew','/etc/csf/csf.deny')
rescue IOError => e
raise Puppet::Error "Could not write denied ips file (#{e})"
end
end
#Allowed ips
if @resource.value(:allowed_ips) != [:absent] and @resource.value(:allowed_ips) != :absent
begin
fin = File.new('/etc/csf/csf.allow','r')
fout = File.new('/etc/csf/csf.allow.puppetnew','w')
desired_ips = @resource.value(:allowed_ips)
if @resource.value(:purge) != :true
while( line = fin.gets ) do
fout.write(line)
if line =~ /^\s*((\d{1,3}\.){3}(\d{1,3}))/
#Requested IP already exists
if (loc = desired_ips.index($1)) != nil
desired_ips.delete_at(loc)
end
end
end
end
desired_ips.each do |ip|
fout.write("#{ip}\n")
end
fin.close
fout.close
File.rename('/etc/csf/csf.allow.puppetnew','/etc/csf/csf.allow')
rescue IOError => e
raise Puppet::Error "Could not write allowed ips file (#{e})"
end
end
end
end