Commit 2e94e6bd authored by Patrick J Cherry's avatar Patrick J Cherry
Browse files

Implemented incrond support for the firewall to allow instant-iptables

updates.
parent 5013ca51
......@@ -8,7 +8,7 @@ Standards-Version: 3.9.1
Package: symbiosis-firewall
Architecture: any
Depends: iptables, ruby1.8, symbiosis-common (>= 2011:1214), libruby1.8, libsqlite3-ruby1.8, ${shlibs:Depends}, ${misc:Depends}
Depends: iptables, ruby1.8, symbiosis-common (>= 2011:1214), libruby1.8, libsqlite3-ruby1.8, incrond, ${shlibs:Depends}, ${misc:Depends}
Replaces: bytemark-vhost-firewall, symbiosis-test, symbiosis-monit (<< 2011:1206)
Breaks: symbiosis-monit (<< 2011:1206)
Provides: bytemark-vhost-firewall
......
......@@ -3,3 +3,4 @@ patterns.d/ etc/symbiosis/firewall
rule.d usr/share/symbiosis/firewall
action.d usr/share/symbiosis/firewall
test.d etc/symbiosis
incron.d/ etc/
###########################################
#
# incrond snippet for symbiosis-firewall
#
###########################################
#
# Monitor the incoming, outgoing directories for changes.
#
/etc/symbiosis/firewall/incoming.d IN_NO_LOOP,IN_CREATE,IN_DELETE,IN_MOVE,IN_CLOSE_WRITE /usr/sbin/symbiosis-firewall -s 5 load
/etc/symbiosis/firewall/outgoing.d IN_NO_LOOP,IN_CREATE,IN_DELETE,IN_MOVE,IN_CLOSE_WRITE /usr/sbin/symbiosis-firewall -s 5 load
#
# Monitor the whitelist and blacklist directories for changes.
#
/etc/symbiosis/firewall/whitelist.d IN_NO_LOOP,IN_CREATE,IN_DELETE,IN_MOVE,IN_CLOSE_WRITE /usr/sbin/symbiosis-firewall -s 5 reload-blacklist
/etc/symbiosis/firewall/blacklist.d IN_NO_LOOP,IN_CREATE,IN_DELETE,IN_MOVE,IN_CLOSE_WRITE /usr/sbin/symbiosis-firewall -s 5 reload-whitelist
#
# Need to monitor attribute changes here, since we need the executable bit to be set.
#
/etc/symbiosis/firewall/local.d IN_NO_LOOP,IN_CREATE,IN_DELETE,IN_MOVE,IN_CLOSE_WRITE,IN_ATTRIB /usr/sbin/symbiosis-firewall -s 5 load
......@@ -23,9 +23,11 @@
#
# -d, --no-delete Do not delete the generated script
#
# -f, --flush Set the action to "flush". This will overwrite any
# -f, --flush Set the action to "flush". This will overwrite any
# action specified.
#
# -s, --sleep <n> Sleep for <n> seconds before executing anything.
#
# <action> The action to run. This defaults to "load".
#
# USAGE
......@@ -79,6 +81,11 @@
# addresses, in the file instead of leaving it empty. This will restrict
# access to/from the named addresses.
#
# If scripts are placed in local.d, then they are executed by run-parts(8), so
# they must follow the naming conventions required by run-parts. Also the exit
# status of the scripts is important. If any script exits with a non-zero
# code, then the whole firewall will have deemed to have failed to load.
#
# ACTIONS AND TEMPLATES
#
# The "actions" are bash(1) scripts, that have been templated using eRuby.
......@@ -107,9 +114,16 @@
# The magic strings '$SRC' and '$DEST' will be replaced by any IP addresses the
# user has specified in their file - or removed if none are present.
#
# FAILURE
#
# If the firewall fails to load, an attempt is made to restore the firewall to
# its prior state, using iptables-save(8) and iptables-restore(8), and their
# ip6tables eqivalents. If these commands fail, then the firewall is left
# flushed.
#
# SEE ALSO
# symbiosis-firewall-whitelist(1), symbiosis-firewall-blacklist(1),
# iptables(8), ip6tables(8)
# iptables(8), ip6tables(8), run-parts(8)
#
# AUTHOR
# Steve Kemp <steve@bytemark.co.uk>
......@@ -145,6 +159,7 @@ base_dir = '/etc/symbiosis/firewall'
template_dir = '/usr/share/symbiosis/firewall/rule.d'
address_families = %w(inet inet6)
action = nil
sleep_for = 0
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
......@@ -156,6 +171,7 @@ opts = GetoptLong.new(
[ '--no-delete', '-d', GetoptLong::NO_ARGUMENT ],
[ '--flush', '-f', GetoptLong::NO_ARGUMENT ],
[ '--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--sleep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
[ '--template-d', '-t', GetoptLong::REQUIRED_ARGUMENT ]
)
......@@ -184,6 +200,8 @@ begin
template_dir = File.expand_path(arg)
when '--flush'
action = "flush"
when '--sleep'
sleep_for = arg.to_i
end
end
rescue
......@@ -308,6 +326,13 @@ if ENV.has_key?("IFACE") and ENV.has_key?("PHASE")
end
#
# Sleep a little, for inotify.
#
if sleep_for > 0
verbose "Sleeping for #{sleep_for} seconds"
Kernel.sleep sleep_for
end
begin
include Symbiosis::Firewall
......@@ -319,6 +344,21 @@ begin
iptables_cmds << "/sbin/iptables" if address_families.include?("inet")
iptables_cmds << "/sbin/ip6tables" if address_families.include?("inet6")
#
# Save a copy of iptables before we begin, in case of disaster.
#
if address_families.include?("inet")
iptables_restore = IO.popen('/sbin/iptables-save','r'){|io| io.read}
else
iptables_restore = []
end
if address_families.include?("inet6")
ip6tables_restore = IO.popen('/sbin/ip6tables-save','r'){|io| io.read}
else
ip6tables_restore = []
end
#
# Change the ownership of the firewall directory, if we're going to execute
# the firewall script
......@@ -382,10 +422,10 @@ begin
if ( execute and ::Process.uid == 0 )
unless system( tf.path )
warn "symbiosis-firewall: Firewall script failed. Flushing rules."
warn "symbiosis-firewall: Firewall script failed."
#
# FIXME: This is deliberatly hard-coded, although it probably needs to catch errors better.
# FIXME: This is deliberately hard-coded, although it probably needs to catch errors better.
#
iptables_cmds.each do |cmd|
#
......@@ -393,16 +433,19 @@ begin
#
next unless File.executable?(cmd)
warn "symbiosis-firewall: Flusing #{cmd} rules and chains."
%w(INPUT FORWARD OUTPUT).each do |chain|
#
# Fix policy, flush chain, and allow everything on loopback.
#
system(cmd, "-P #{chain} ACCEPT")
system(cmd, "-P", chain, "ACCEPT")
end
#
# Flush everything
#
system(cmd,"-F")
#
# Delete any old chains
#
......@@ -410,14 +453,23 @@ begin
end
#
# Leave the script for inspection.
# Now restore our old tables
#
delete = false
unless iptables_restore.empty?
warn "symbiosis-firewall: Restoring old iptables rules and chains."
IO.popen('/sbin/iptables-restore','w'){|io| io.write iptables_restore}
end
unless ip6tables_restore.empty?
warn "symbiosis-firewall: Restoring old ip6tables rules and chains."
IO.popen('/sbin/ip6tables-restore','w'){|io| io.write ip6tables_restore}
end
#
# Further warning.
# Leave the script for inspection.
#
warn "symbiosis-firewall: This machine is now running *without* a firewall in place."
delete = false
end
end
......@@ -428,7 +480,7 @@ begin
#
new_path = tf.path+"-saved"
FileUtils.cp tf.path, new_path
puts "Left firewall script in #{new_path} for inspection."
warn "symbiosis-firewall: Left firewall script in #{new_path} for inspection."
end
end
......
......@@ -7,7 +7,7 @@
# symbiosis-firewall-blacklist [ -h | --help ] [-m | --manual]
# [ -v | --verbose ] [ -x | --no-exec] [ -d | --no-delete ]
# [ -a | --attempts <n> ] [ -e | --expire-after <n> ]
# [ -p | --prefix <dir> ] [ -t | --template-d <dir> ]
# [ -p | --prefix <dir> ]
#
# OPTIONS
# -h, --help Show a help message, and exit.
......@@ -29,8 +29,6 @@
# -p, --prefix <dir> Directory where incoming.d, outgoing.d etc are
# located. Defaults to /etc/symbiosis/firewall.
#
# -t, --template-d <dir> Additional directory to search for templates.
#
# USAGE
#
# This script is designed to automatically blacklist IP addresses which
......@@ -79,7 +77,6 @@ $VERBOSE = false
base_dir = "/etc/symbiosis/firewall/"
delete = true
execute = true
template_dir = nil
force = false
attempts = 20
expire_after = 2
......@@ -92,7 +89,6 @@ opts = GetoptLong.new(
[ '--no-delete', '-d', GetoptLong::NO_ARGUMENT ],
[ '--force', '-f', GetoptLong::NO_ARGUMENT ],
[ '--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--template-d', '-t', GetoptLong::REQUIRED_ARGUMENT ],
[ '--attempts', '-a', GetoptLong::REQUIRED_ARGUMENT ],
[ '--expire-after', '-e', GetoptLong::REQUIRED_ARGUMENT ]
)
......@@ -116,8 +112,6 @@ begin
force = true
when '--prefix'
base_dir = File.expand_path(arg)
when '--template-d'
template_dir = File.expand_path(arg)
when '--expire-after'
expire_after = arg.to_i
when '--attempts'
......@@ -311,17 +305,5 @@ end
puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE )
#
# Re-generate the blacklist chain
# Updating the firewall is now done by the inotify cronjob
#
if ( updated || expired > 0 || force )
cmd = %w(/usr/sbin/symbiosis-firewall)
cmd << "--verbose" if $VERBOSE
cmd << "--no-execute" unless execute
cmd << "--no-delete" unless delete
cmd += ["--prefix", base_dir]
cmd += ["--template-d", template_dir] unless template_dir.nil?
cmd << "reload-blacklist"
puts "Running #{cmd.join(" ")}" if $VERBOSE
exec(*cmd)
end
......@@ -7,7 +7,7 @@
# symbiosis-firewall-whitelist [ -h | --help ] [-m | --manual]
# [ -v | --verbose ] [ -x | --no-exec] [ -d | --no-delete ]
# [ -e | --expire-after <n> ] [ -w | --wtmp-file <file> ]
# [ -p | --prefix <dir> ] [ -t | --template-d <dir> ]
# [ -p | --prefix <dir> ]
#
# OPTIONS
# -h, --help Show a help message, and exit.
......@@ -30,8 +30,6 @@
# -p, --prefix <dir> Directory where action.d, incoming.d, outgoing.d etc.
# are located. Defaults to /etc/symbiosis/firewall.
#
# -t, --template-d <dir> Additional directory to search for templates.
#
# USAGE
#
# This script is designed to automatically whitelist IP addresses which
......@@ -73,7 +71,6 @@ base_dir = "/etc/symbiosis/firewall/"
wtmp_file = "/var/log/wtmp"
delete = true
execute = true
template_dir = nil
force = false
expire_after = 8
......@@ -85,7 +82,6 @@ opts = GetoptLong.new(
[ '--no-delete', '-d', GetoptLong::NO_ARGUMENT ],
[ '--force', '-f', GetoptLong::NO_ARGUMENT ],
[ '--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--template-d', '-t', GetoptLong::REQUIRED_ARGUMENT ],
[ '--wtmp-file', '-w', GetoptLong::REQUIRED_ARGUMENT ],
[ '--expire-after', '-e', GetoptLong::REQUIRED_ARGUMENT ]
)
......@@ -109,8 +105,6 @@ begin
force = true
when '--prefix'
base_dir = File.expand_path(arg)
when '--template-d'
template_dir = File.expand_path(arg)
when '--expire-after'
expire_after = arg.to_i
when '--wtmp-file'
......@@ -298,16 +292,6 @@ end
puts "Expiring done - removed #{expired} file(s)" if ( $VERBOSE )
#
# Re-generate the whitelist chain
# Updating the firewall is now done by the inotify cronjob.
#
if ( updated || expired > 0 || force )
cmd = %w(/usr/sbin/symbiosis-firewall)
cmd << "--verbose" if $VERBOSE
cmd << "--no-execute" unless execute
cmd << "--no-delete" unless delete
cmd += ["--prefix", base_dir]
cmd += ["--template-d", template_dir] unless template_dir.nil?
cmd << "reload-whitelist"
puts "Executing #{cmd.join(" ")}" if $VERBOSE
exec(*cmd)
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