241 lines
5.8 KiB
Ruby
241 lines
5.8 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
|
||
|
require 'inifile'
|
||
|
require 'pp'
|
||
|
|
||
|
require "resolv"
|
||
|
require "mysql2"
|
||
|
|
||
|
require "socket"
|
||
|
require "thread"
|
||
|
require "syslog"
|
||
|
require "rubygems"
|
||
|
require "open-uri"
|
||
|
require "ipaddress"
|
||
|
|
||
|
STDOUT.sync = true
|
||
|
Syslog.open("#{$PROGRAM_NAME}", Syslog::LOG_PID)
|
||
|
|
||
|
def log(msg)
|
||
|
Syslog.log(Syslog::LOG_ERR, "%s", msg)
|
||
|
STDERR.puts("STDERR: [ #{msg} ]") if $debug
|
||
|
end
|
||
|
|
||
|
|
||
|
$my_dir = __dir__
|
||
|
|
||
|
config_filename = ARGV[0]
|
||
|
|
||
|
if config_filename.nil? or !File.exists?(config_filename)
|
||
|
$debug = true
|
||
|
log("The config file: [\"#{config_filename}\"] doesn't exist")
|
||
|
exit 1
|
||
|
end
|
||
|
|
||
|
config_file = IniFile.load(config_filename)
|
||
|
|
||
|
$domain_location = config_file["main"]["domain_pos"].to_i
|
||
|
$login_location = config_file["main"]["login_pos"].to_i
|
||
|
|
||
|
$list_table = config_file["tables"]["list"]
|
||
|
|
||
|
$users_table = config_file["tables"]["users"]
|
||
|
|
||
|
$debug = false
|
||
|
|
||
|
if config_file["main"]["debug"].to_s == "1"
|
||
|
$debug = true
|
||
|
end
|
||
|
|
||
|
log("Started with DEBUG => #{$debug}")
|
||
|
|
||
|
socket_type = config_file["socket"]["type"]
|
||
|
socket_address = config_file["socket"]["address"]
|
||
|
port = config_file["socket"]["port"] if config_file["socket"]["port"]
|
||
|
|
||
|
$mysql_hostname = config_file["mysql"]["host"]
|
||
|
$mysql_username = config_file["mysql"]["username"]
|
||
|
$mysql_password = config_file["mysql"]["password"]
|
||
|
$mysql_db = config_file["mysql"]["database"]
|
||
|
|
||
|
trap "SIGINT" do
|
||
|
STDERR.puts "STDERR: Exiting"
|
||
|
exit 130
|
||
|
end
|
||
|
|
||
|
|
||
|
def cleanupUnixSocket(unix_socket_address)
|
||
|
if File.exist?(unix_socket_address)
|
||
|
File.delete(unix_socket_address)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def generate_domain_array(domain)
|
||
|
parts = domain.split(".")
|
||
|
l = parts.length
|
||
|
|
||
|
domains = []
|
||
|
domains << parts.join(".")
|
||
|
|
||
|
i = 0
|
||
|
while i < l do
|
||
|
domains << ".#{parts[i..-1].join(".")}"
|
||
|
i = i +1
|
||
|
end
|
||
|
domains
|
||
|
end
|
||
|
|
||
|
def check_domain_in_db(domain, login)
|
||
|
domains = generate_domain_array(domain)
|
||
|
begin
|
||
|
db_client = Mysql2::Client.new(:host => $mysql_hostname, :username => $mysql_username, :password => $mysql_password, :database => $mysql_db)
|
||
|
rescue => e
|
||
|
log(e)
|
||
|
log(e.inspect)
|
||
|
end
|
||
|
sql_query = "SELECT u.username , ubl.dstdom, ubl.updated_at
|
||
|
FROM usersBlackLists ubl
|
||
|
LEFT JOIN users u ON u.user_id=ubl.user_id
|
||
|
WHERE u.username = '#{login}' and ubl.dstdom IN ( #{domains.map { |d| "'#{d}'" }.join(" , ")} ) AND ubl.y=1;"
|
||
|
log("Running SQL query: [ \"#{sql_query}\" ]")
|
||
|
results = db_client.query(sql_query)
|
||
|
if results.nil?
|
||
|
db_client.close
|
||
|
return false
|
||
|
end
|
||
|
if results.size > 0
|
||
|
db_client.close
|
||
|
return true
|
||
|
end
|
||
|
db_client.close
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
def check_domain(domain, login)
|
||
|
log("checking domain #{domain}") if $debug
|
||
|
db_res = check_domain_in_db(domain, login)
|
||
|
log("DB RES #{db_res}") if $debug
|
||
|
|
||
|
if db_res
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
def requestTest(request)
|
||
|
return if request == nil
|
||
|
request = request.split
|
||
|
matched_to = []
|
||
|
ret = "0"
|
||
|
log("Request size: #{request.size} , domain_location #{$domain_location}, login_location #{$login_location}") if $debug
|
||
|
if request.size >= $login_location
|
||
|
begin
|
||
|
# check if the requst is a domain name or ip address and if it's valid
|
||
|
is_ip_address = IPAddress.valid?(request[$domain_location])
|
||
|
# Check if the login name is valid (no spaces etc...)
|
||
|
if !is_ip_address
|
||
|
if check_domain(request[$domain_location].downcase, request[$login_location])
|
||
|
ret = "1"
|
||
|
end
|
||
|
end
|
||
|
rescue => e
|
||
|
log(e)
|
||
|
log(e.inspect)
|
||
|
ret = "1"
|
||
|
end
|
||
|
end
|
||
|
return { "request_id" => request[0], "ret" => "#{ret}" }
|
||
|
end
|
||
|
|
||
|
|
||
|
def validr?(request)
|
||
|
if request.ascii_only? && request.valid_encoding?
|
||
|
return true
|
||
|
else
|
||
|
STDERR.puts("errorness line [ #{request} ]")
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
answers = { "0" => "ERR", "1" => "OK" }
|
||
|
|
||
|
|
||
|
log("Socket binding is starting")
|
||
|
case socket_type
|
||
|
when /^tcp/i
|
||
|
begin
|
||
|
log("Trying to bind: #{socket_address}:#{port}")
|
||
|
server_socket = TCPServer.new(socket_address, port)
|
||
|
|
||
|
loop do
|
||
|
Thread.start(server_socket.accept) do |s|
|
||
|
log("#{s} is accepted")
|
||
|
processingtQueue = Queue.new
|
||
|
|
||
|
proccessor = Thread.new do
|
||
|
loop do
|
||
|
incomming_request = processingtQueue.pop
|
||
|
return if incomming_request.nil?
|
||
|
Thread.new do
|
||
|
result = requestTest(incomming_request) if validr?(incomming_request)
|
||
|
s.puts("#{result["request_id"]} #{answers[result["ret"]]}")
|
||
|
log("result for request: #{s} => [ #{incomming_request} ] , res => #{result}") if $debug
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
while line = s.gets
|
||
|
processingtQueue << line.strip.chomp
|
||
|
log("original request: #{s} => [ #{line.chomp} ]") if $debug
|
||
|
end
|
||
|
proccessor.join
|
||
|
log("#{s} is gone")
|
||
|
s.close
|
||
|
end
|
||
|
end
|
||
|
rescue => e
|
||
|
log(e)
|
||
|
log(e.inspect)
|
||
|
exit 10
|
||
|
end
|
||
|
when /^unix/i
|
||
|
begin
|
||
|
log("starting to bind UNIX Socket")
|
||
|
if IPAddress.valid?(socket_address)
|
||
|
log("Cannot use IP address #{socket_address} for unix socket")
|
||
|
exit 1
|
||
|
end
|
||
|
address_url = URI.parse(socket_address)
|
||
|
unix_socket_address = address_url.path
|
||
|
|
||
|
cleanupUnixSocket(unix_socket_address)
|
||
|
log("Trying to bind unix socket")
|
||
|
server_socket = UNIXServer.new(unix_socket_address)
|
||
|
log("UNIX Socket was bounded")
|
||
|
|
||
|
loop do
|
||
|
Thread.start(server_socket.accept) do |s|
|
||
|
log("#{s} is accepted")
|
||
|
while line = s.gets
|
||
|
line = line.strip.chomp
|
||
|
log("original request: #{s} => [ #{line} ]") if $debug
|
||
|
result = requestTest(line) if validr?(line)
|
||
|
s.puts("#{result["request_id"]} #{answers[result["ret"]]}")
|
||
|
log("result for request: #{s} => [ #{line} ] , res => #{result}") if $debug
|
||
|
end
|
||
|
log("#{s} is gone")
|
||
|
s.close
|
||
|
end
|
||
|
end
|
||
|
rescue => e
|
||
|
File.delete(unix_socket_address) if File.exists?(unix_socket_address)
|
||
|
log(e)
|
||
|
log(e.inspect)
|
||
|
exit 11
|
||
|
end
|
||
|
else
|
||
|
log("Sokcet type: #{socket_type} is not supported")
|
||
|
exit 1
|
||
|
end
|