@ -1,52 +1,76 @@
# vim: set noet sw=2 ts=2 sts=2:
require 'prometheus/client'
require 'prometheus/client/formats/text'
require 'net/dns'
require 'yaml'
class DnsblCollector
attr_reader :lists , :prometheus , :configfile , :resolver , :metrics
def initialize prometheus : nil , configfile : nil
@configfile = configfile || 'config.yml'
@prometheus = prometheus || Prometheus :: Client . registry
% i [ dnsbl_listed dnsbl_query_error ] . each { | m | @prometheus . unregister m }
@metrics = {
dnsbl_listed : @prometheus . gauge ( :dnsbl_listed , 'IP listed currently on Blacklist' ) ,
dnsbl_query_error : @prometheus . counter ( :dnsbl_query_error , 'Errors while query for blacklist' ) ,
}
load_config
end
require 'ostruct'
class DnsblCollector
class << self
attr_reader :blacklists , :resolver , :registry
def load_config file = nil
config = YAML . load_file file || './config.yml'
self . blacklists = config [ 'blacklists' ]
self . resolver = config [ 'resolver' ]
end
def load_config
config = YAML . load_file @configfile
@resolver = config [ 'resolver' ]
@lists =
config [ 'blacklists' ] . map do | bl |
case bl
when String then { blacklist : bl }
when Hash then bl
else raise ConfigError , " Unexpected Element in blacklists: #{ bl } "
def blacklists = lists
@blacklists =
lists . map do | bl |
case bl
when String then { blacklist : bl }
when Hash then bl
else raise ConfigError , " Unexpected Element in blacklists: #{ bl } "
end
end
end
end
def resolver = resolver_cnf
@resolver =
case resolver_cnf
when Net :: DNS :: Resolver then resolver_cnf
when Hash then Net :: DNS :: Resolver . new resolver_cnf
else
raise ConfigError , " DnsblCollector.resolver= expects a Net::DNS::Resolver or a resolver-config as Hash "
end
end
def registry = registry
@registry = registry
@registry . counter :dnsbl_query_error_count , docstring : 'Errors while query for blacklist' , labels : % i [ blacklist target ]
@registry . counter :dnsbl_query_blacklist_duration_sum , docstring : 'Total duration for querieng this blacklist' , labels : % i [ blacklist ]
@registry . counter :dnsbl_query_blacklist_count , docstring : 'Total count of queries this blacklist' , labels : % i [ blacklist ]
end
end
self . registry = Prometheus :: Client :: Registry . new
attr_reader :lists , :registry , :configfile , :resolver , :metrics
def initialize registry : nil
@registry = registry || Prometheus :: Client :: Registry . new
@registry . gauge :dnsbl_listed , docstring : 'IP listed currently on Blacklist' , labels : % i [ blacklist target ]
@metrics = OpenStruct . new @registry . instance_variable_get ( :@metrics ) . merge ( self . class . registry . instance_variable_get ( :@metrics ) )
end
def collect ip
prefix = ip . send :_reverse
ip = ip . to_s
dns = Net :: DNS :: Resolver . new @resolver
todo = @lists . sort { | _ | rand }
durs = { }
todo = self . class . blacklists . sort { | _ | rand }
resolver = self . class . resolver
10 . times . map do
Thread . new do
while bl = @lists . pop
b = Time . now
while bl = todo . pop
name , b = bl [ :blacklist ] , Time . now
begin
r = dns . search ( " #{ prefix } . #{ bl [ :blacklist ] } " , Net :: DNS :: A ) . answer . empty?
@metrics [ :dnsbl_listed ] . set ( { blacklist : bl [ :blacklist ] , target : ip } , r ? 0 : 1 )
r = resolver . search ( " #{ prefix } . #{ name } " , Net :: DNS :: A ) . answer . empty?
@metrics . dnsbl_listed . set r ? 0 : 1 , labels : { blacklist : name , target : ip }
rescue Net :: DNS :: Resolver :: NoResponseError
@metrics [ :dnsbl_query_error ] . increment ( { blacklist : bl [ :blacklist ] , target : ip } )
@metrics . dnsbl_query_error_count . increment labels : { blacklist : name , target : ip }
end
durs [ bl [ :blacklist ] ] = Time . now - b
dur = Time . now - b
@metrics . dnsbl_query_blacklist_duration_sum . increment by : dur , labels : { blacklist : name }
@metrics . dnsbl_query_blacklist_count . increment labels : { blacklist : name }
end
end
end . each & :join