Commit 4805607d authored by Patrick J Cherry's avatar Patrick J Cherry
Browse files

Fixed up symbiosis-firewall-{white,black}list to work properly.

parent c737c1e0
...@@ -27,7 +27,12 @@ module Symbiosis ...@@ -27,7 +27,12 @@ module Symbiosis
def generate def generate
results = do_read results = do_read
do_parse_results(results) do_parse(results)
end
def attempts=(a)
raise ArgumentError, "#{a.inspect} must be an integer" unless a.is_a?(Integer)
@attempts = a
end end
private private
......
...@@ -90,11 +90,7 @@ module Symbiosis ...@@ -90,11 +90,7 @@ module Symbiosis
# resolve addresses # resolve addresses
# #
hostnames.each do |hostname| hostnames.each do |hostname|
if hostname.is_a?(String) addresses += do_resolve_name(hostname)
addresses += do_resolve_name(hostname)
else
addresses << hostname
end
end end
# #
...@@ -131,7 +127,16 @@ module Symbiosis ...@@ -131,7 +127,16 @@ module Symbiosis
ips = [] ips = []
begin begin
ips << IPAddr.new(name) case name
when IPAddr
ips << name
when String
ips << IPAddr.new(name)
when Nilclass
ips << name
else
warn "#{name.inspect} could not be resolved because it is a #{name.class}." if $VERBOSE
end
rescue ArgumentError rescue ArgumentError
%w(A AAAA).each do |type| %w(A AAAA).each do |type|
begin begin
...@@ -252,6 +257,10 @@ module Symbiosis ...@@ -252,6 +257,10 @@ module Symbiosis
# #
class IPListDirectory < Directory class IPListDirectory < Directory
def include?(template, address)
end
private private
# #
......
...@@ -69,11 +69,15 @@ class IPAddr < ::IPAddr ...@@ -69,11 +69,15 @@ class IPAddr < ::IPAddr
end end
end end
#
# Append the CIDR mask if there is more than on IP in the range.
#
def to_s def to_s
[super, cidr_mask].join('/') s = [super]
s << cidr_mask if max.to_i - min.to_i > 0
s.join("/")
end end
end end
end end
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
# -e, --expire-after <n> Number of days after which blacklisted IPs should be # -e, --expire-after <n> Number of days after which blacklisted IPs should be
# expired. Defaults to 2. # expired. Defaults to 2.
# #
# -p, --prefix <dir> Directory where action.d, incoming.d, outgoing.d etc # -p, --prefix <dir> Directory where incoming.d, outgoing.d etc are
# are located. Defaults to /etc/symbiosis/firewall. # located. Defaults to /etc/symbiosis/firewall.
# #
# -t, --template-d <dir> Additional directory to search for templates. # -t, --template-d <dir> Additional directory to search for templates.
# #
...@@ -85,7 +85,7 @@ base_dir = "/etc/symbiosis/firewall/" ...@@ -85,7 +85,7 @@ base_dir = "/etc/symbiosis/firewall/"
delete = false delete = false
execute = false execute = false
template_dir = nil template_dir = nil
force = true force = false
attempts = 20 attempts = 20
expire_after = 2 expire_after = 2
...@@ -117,7 +117,7 @@ opts.each do |opt,arg| ...@@ -117,7 +117,7 @@ opts.each do |opt,arg|
when '--no-delete' when '--no-delete'
delete = false delete = false
when '--force' when '--force'
force = false force = true
when '--prefix' when '--prefix'
base_dir = File.expand_path(arg) base_dir = File.expand_path(arg)
when '--template-d' when '--template-d'
...@@ -167,7 +167,9 @@ blacklist_d = File.join(base_dir, "blacklist.d") ...@@ -167,7 +167,9 @@ blacklist_d = File.join(base_dir, "blacklist.d")
# ensure the directory exists. # ensure the directory exists.
if ( ! File.directory?( "#{blacklist_d}" ) ) if ( ! File.directory?( "#{blacklist_d}" ) )
system( "mkdir -p #{blacklist_d}" ) system( "mkdir -p #{blacklist_d}" )
end end
if ( File.directory?( blacklist_d ) ) if ( File.directory?( blacklist_d ) )
...@@ -189,40 +191,99 @@ puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE ) ...@@ -189,40 +191,99 @@ puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE )
# #
# Fetch the IP addresses # Fetch the IP addresses
# #
blacklist = Symbiosis::Blacklist.new blacklist = Symbiosis::Firewall::Blacklist.new
blacklist.attempts = attempts blacklist.attempts = attempts
blacklist.base_dir = base_dir blacklist.base_dir = base_dir
whitelist = Symbiosis::IPListDirectory.new(File.join(base_dir, "whitelist.d"))
# #
# Did we update? # Did we update?
# #
updated=false updated=false
# #
# Iterate over each IP # Iterate over each IP
# #
blacklist.generate.each do |ip, ports| blacklist.generate.each do |ip, ports|
#
# Make sure we can parse stuff
#
begin
ip = IPAddr.new(ip)
rescue ArgumentError => err
warn "Ignoring #{ip.inspect} because of #{err.to_s}"
next
end
#
# Mask IPv6 to /64s.
#
ip = ip.mask(64) if ip.ipv6?
#
# Mask IPv4 to /32s.
#
ip = ip.mask(32) if ip.ipv4?
#
# Only include globally routable IPs.
#
# FIXME: Need better IPv6 conditions.
#
next if ip.ipv4? and (IPAddr.new("127.0.0.1/8").include?(ip) or IPAddr.new("0.0.0.0") == ip )
next if ip.ipv6? and !IPAddr.new("2000::/3").include?(ip)
puts "Found IP address: #{ip}" if ( $VERBOSE ) puts "Found IP address: #{ip}" if ( $VERBOSE )
fn = File.join(blacklist_d,ip.to_s.gsub("/","-")+".auto" ) #
# Check filename without .auto first.
#
fn = File.join(blacklist_d,ip.to_s.gsub("/","-"))
if ( File.exists?(fn) ) if ( File.exists?(fn) )
puts "\tAlready blacklisted" if ( $VERBOSE ) puts "\tAlready manually blacklisted" if ( $VERBOSE )
else else
# create the file #
system( "touch #{fn}" ) # Automatically blacklist.
#
fn += ".auto"
if ! File.exists?(fn)
updated=true
puts "\tAdding to blacklist" if ( $VERBOSE )
#
# Write the list of ports
#
File.open(fn,"w"){|fh| fh.print ports.join("\n") }
#
# Create a new file.
#
FileUtils.touch(fn, :mtime => at)
else
updated=true
#
# Update the mtime, if this entry is newer.
#
puts "\tUpdating blacklist entry" if ( $VERBOSE )
old_ports = File.readlines(fn).collect{|pt| pt.chomp.strip }
new_ports = (ports + old_ports).collect{|pt| pt.nil? ? "all" : pt.to_s }.uniq
new_ports = %w(all) if new_ports.any{|pt| "all" == pt}
#
# overwrite file.
#
File.open(fn,"w"){|fh| fh.print ports.join("\n") }
end
updated=true
puts "\tAdding to blacklist" if ( $VERBOSE )
end end
end end
#
# Re-generate the blacklist chain # Re-generate the blacklist chain
# #
if ( updated || expired > 0 || force ) if ( updated || expired > 0 || force )
...@@ -233,6 +294,6 @@ if ( updated || expired > 0 || force ) ...@@ -233,6 +294,6 @@ if ( updated || expired > 0 || force )
cmd += ["--prefix", base_dir] cmd += ["--prefix", base_dir]
cmd += ["--template-d", template_dir] unless template_dir.nil? cmd += ["--template-d", template_dir] unless template_dir.nil?
cmd << "reload-blacklist" cmd << "reload-blacklist"
exec(cmd) exec(*cmd)
end end
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
require 'getoptlong' require 'getoptlong'
require 'tempfile' require 'tempfile'
require 'fileutils'
require 'symbiosis/utmp' require 'symbiosis/utmp'
require 'symbiosis/firewall/directory' require 'symbiosis/firewall/directory'
require 'symbiosis/firewall/template' require 'symbiosis/firewall/template'
...@@ -77,7 +78,7 @@ wtmp_file = "/var/log/wtmp" ...@@ -77,7 +78,7 @@ wtmp_file = "/var/log/wtmp"
delete = false delete = false
execute = false execute = false
template_dir = nil template_dir = nil
force = true force = false
expire_after = 8 expire_after = 8
opts = GetoptLong.new( opts = GetoptLong.new(
...@@ -108,7 +109,7 @@ opts.each do |opt,arg| ...@@ -108,7 +109,7 @@ opts.each do |opt,arg|
when '--no-delete' when '--no-delete'
delete = false delete = false
when '--force' when '--force'
force = false force = true
when '--prefix' when '--prefix'
base_dir = File.expand_path(arg) base_dir = File.expand_path(arg)
when '--template-d' when '--template-d'
...@@ -153,31 +154,33 @@ end ...@@ -153,31 +154,33 @@ end
puts "Expiring old whitelist entries" if ( $VERBOSE ) puts "Expiring old whitelist entries" if ( $VERBOSE )
expired = 0 expired = 0
whitelist_d = File.join($PREFIX, "whitelist.d") whitelist_d = File.join(base_dir, "whitelist.d")
# ensure the directory exists. # ensure the directory exists.
if ( ! File.directory?( "#{whitelist_d}" ) ) unless File.directory?(whitelist_d)
system( "mkdir -p #{whitelist_d}" ) FileUtils.mkdir_p(whitelist_d)
end end
if ( File.directory?( whitelist_d ) ) expire_before = Time.now - ( expire_after * 24 * 60 * 60 )
Dir.foreach( whitelist_d ) do |entry|
if ( ( entry =~ /\.auto$/i ) && if File.directory?( whitelist_d )
(File.mtime( "#{whitelist_d}/#{entry}" ) < ( Time.now - 8 * 24 * 60 * 60 ) ) )
then
puts "Removing #{whitelist_d}/#{entry}" if ( $VERBOSE ) Dir.glob( File.join(whitelist_d,"*.auto" ) ).each do |entry|
File.unlink("#{whitelist_d}/#{entry}")
if File.mtime(entry) < expire_before
puts "Removing #{entry}" if ( $VERBOSE )
File.unlink(entry)
expired += 1 expired += 1
end end
end end
end
puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE )
end
# puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE )
# Fetch the IP addresses
#
ip_addresses = Symbiosis::Utmp.read(wtmp_file).collect{|entry| entry["ip"]}
# #
# Did we update? # Did we update?
...@@ -185,46 +188,80 @@ ip_addresses = Symbiosis::Utmp.read(wtmp_file).collect{|entry| entry["ip"]} ...@@ -185,46 +188,80 @@ ip_addresses = Symbiosis::Utmp.read(wtmp_file).collect{|entry| entry["ip"]}
updated=false updated=false
# #
# Iterate over each IP
# #
ip_addresses.each do |ip| # Fetch the IP addresses
#
Symbiosis::Utmp.read(wtmp_file).each do |entry|
begin
ip = Symbiosis::Firewall::IPAddr.new(entry['ip'].to_s)
rescue ArgumentError
#
# Oops. Can't interpret the IP.
#
next
end
at = entry['time']
# #
# We only want IP addresses. # Make sure the record isn't already expired.
# #
next unless ip.is_a?(IPAddr) next unless at > expire_before
#
# Mask IPv6 to /64s.
#
ip = ip.mask(64) if ip.ipv6?
#
# Mask IPv4 to /32s.
#
ip = ip.mask(32) if ip.ipv4?
#
# Only include globally routable IPs.
# #
# FIXME: Need better IPv6 conditions. # FIXME: Need better IPv6 conditions.
# #
if ( ( ip.ipv4? and next if ip.ipv4? and (IPAddr.new("127.0.0.1/8").include?(ip) or IPAddr.new("0.0.0.0") == ip )
!( IPAddr.new("127.0.0.1/8").include?(ip) or IPAddr.new("0.0.0.0") == ip ) next if ip.ipv6? and !IPAddr.new("2000::/3").include?(ip)
) or (
ip.ipv6? and IPAddr.new("2000::/3").include?(ip)
)
)
# puts "Found IP address: #{ip}" if ( $VERBOSE )
# Mask IPv6 to /64s.
#
ip = ip.mask(64) if ip.ipv6?
puts "Found IP address: #{ip}" if ( $VERBOSE ) #
# Check filename without .auto first.
#
fn = File.join(whitelist_d,ip.to_s.gsub("/","-"))
fn = File.join(whitelist_d,ip.to_s.gsub("/","-")+".auto" ) if ( File.exists?(fn) )
puts "\tAlready manually whitelisted" if ( $VERBOSE )
if ( File.exists?(fn) ) else
puts "\tAlready whitelisted" if ( $VERBOSE ) #
else # Automatically whitelist.
# create the file #
system( "touch #{fn}" ) fn += ".auto"
updated=true if ! File.exists?(fn)
updated=true
puts "\tAdding to whitelist" if ( $VERBOSE ) puts "\tAdding to whitelist" if ( $VERBOSE )
#
# Create a new file.
#
FileUtils.touch(fn, :mtime => at)
elsif File.mtime(fn) < at
#
# Update the mtime, if this entry is newer.
#
puts "\tUpdating whitelist entry" if ( $VERBOSE )
FileUtils.touch(fn, :mtime => at)
end end
end
end
end
end
# #
# Re-generate the whitelist chain # Re-generate the whitelist chain
...@@ -237,7 +274,6 @@ if ( updated || expired > 0 || force ) ...@@ -237,7 +274,6 @@ if ( updated || expired > 0 || force )
cmd += ["--prefix", base_dir] cmd += ["--prefix", base_dir]
cmd += ["--template-d", template_dir] unless template_dir.nil? cmd += ["--template-d", template_dir] unless template_dir.nil?
cmd << "reload-whitelist" cmd << "reload-whitelist"
exec(cmd) puts "Executing #{cmd.join(" ")}" if $VERBOSE
exec(*cmd)
end end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment