bin/fault_tolerant_router
#!/usr/bin/env ruby
require 'optparse'
require 'net/smtp'
require 'mail'
require 'logger'
require 'socket'
require 'yaml'
require 'fault_tolerant_router/version'
require 'fault_tolerant_router/generate_config'
require 'fault_tolerant_router/generate_iptables'
require 'fault_tolerant_router/monitor'
require 'fault_tolerant_router/uplink'
require 'fault_tolerant_router/uplinks'
CONFIG_TEMPLATE = {
'uplinks' => {
'interface' => {},
'type' => {},
'ip' => {},
'gateway' => {},
'description' => {},
'weight' => {},
'priority_group' => {}
},
'downlinks' => {
'lan' => {},
'dmz' => {}
},
'tests' => {
'ips' => {},
'required_successful' => {},
'ping_retries' => {},
'interval' => {}
},
'log' => {
'file' => {},
'max_size' => {},
'old_files' => {}
},
'email' => {
'send' => {},
'sender' => {},
'recipients' => {},
'smtp_parameters' => {
'address' => {},
'port' => {},
'authentication' => {},
'enable_starttls_auto' => {},
'user_name' => {},
'password' => {}
}
},
'base_table' => {},
'base_priority' => {},
'base_fwmark' => {}
}
def check_config(config, template, path = [])
config.each do |k, v|
unless template.keys.include?(k)
puts "Error: unknown configuration parameter '#{(path + [k]).join('/')}'"
exit 1
end
case v
when Hash
check_config(v, template[k], path + [k])
when Array
v.each { |v2| check_config(v2, template[k], path + [k]) if v2.is_a?(Hash) }
end
end
end
options = {
configuration_file: '/etc/fault_tolerant_router.conf',
debug: false,
demo: false
}
parser = OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename($0)} [OPTION]... ACTION"
opts.separator ''
opts.separator 'ACTION = generate_config|generate_iptables|email_test|monitor'
opts.separator ''
opts.separator ' generate_config: save an example configuration'
opts.separator ' generate_iptables: generate an "iptables-save" configuration'
opts.separator ' email_test: send a test email to verify the correctness of SMTP parameters'
opts.separator ' monitor: monitor uplinks and change routing accordingly'
opts.separator ''
opts.separator 'OPTIONS:'
opts.on('--config=FILE', 'Configuration file (default /etc/fault_tolerant_router.conf)') do |configuration_file|
options[:configuration_file] = configuration_file
end
opts.separator ' "monitor" specific options:'
opts.on('--debug', 'Print debug output') do |debug|
options[:debug] = debug
end
opts.on('--demo', 'Demo the program by faking random uplink failures') do |demo|
options[:demo] = demo
end
opts.separator ''
opts.separator "Version #{FaultTolerantRouter::VERSION}"
opts.separator 'Alessandro Zarrilli <alessandro@zarrilli.net>'
opts.separator 'https://github.com/drsound/fault_tolerant_router'
end
begin
parser.parse!
rescue OptionParser::ParseError
puts parser.help
exit 1
end
DEMO = options[:demo]
#activate debug if in demo mode
DEBUG = options[:debug] || DEMO
unless ARGV.size == 1 && %w(generate_config generate_iptables email_test monitor).include?(ARGV[0])
puts parser.help
exit 1
end
if ARGV[0] == 'generate_config'
generate_config(options[:configuration_file])
exit 0
end
unless File.exists?(options[:configuration_file])
puts "Configuration file #{options[:configuration_file]} does not exists!"
exit 1
end
config = YAML.load_file(options[:configuration_file])
check_config(config, CONFIG_TEMPLATE)
LAN_INTERFACE = config['downlinks']['lan']
DMZ_INTERFACE = config['downlinks']['dmz']
TEST_IPS = config['tests']['ips']
REQUIRED_SUCCESSFUL_TESTS = config['tests']['required_successful']
PING_RETRIES = config['tests']['ping_retries']
TEST_INTERVAL = config['tests']['interval']
LOG_FILE = config['log']['file']
LOG_MAX_SIZE = config['log']['max_size']
LOG_OLD_FILES = config['log']['old_files']
SEND_EMAIL = config['email']['send']
EMAIL_SENDER = config['email']['sender']
EMAIL_RECIPIENTS = config['email']['recipients']
SMTP_PARAMETERS = Hash[config['email']['smtp_parameters'].map { |k, v| [k.to_sym, v] }]
BASE_TABLE = config['base_table']
BASE_PRIORITY = config['base_priority']
BASE_FWMARK = config['base_fwmark']
UPLINKS = Uplinks.new(config['uplinks'])
case ARGV[0]
when 'generate_iptables'
generate_iptables
when 'email_test'
begin
send_email('fault_tolerant_router test')
puts "Test email sent to #{EMAIL_RECIPIENTS.join(', ')}"
rescue Exception => e
puts "Error sending email: #{e}"
end
else
monitor
end