Splitting Registry for action and process-statistics and clean up repositry.

config.yml was only an example, so name it as config.yml.example and
ignore any config.yml, that checkout could be used as local
project-directory without conflicts.

DnsblCollector will have singleton-behaviour like process configs and an
own Registry.  Config was loaded every request, yet.
There was one Registry, which was reused for every request.  Now every
request will use his own Registry.

Requests will get the content of both Registries.
master
Denis Knauf 2021-05-09 14:39:21 +02:00
parent a3e7b85a50
commit 392ac36312
4 changed files with 68 additions and 36 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.sw[pomnqrst]
*.gem
config.yml
Gemfile.lock

View File

@ -1,6 +1,9 @@
# vim: set noet sw=2 ts=2 sts=2:
require 'rack' require 'rack'
require './dnsbl_exporter' require_relative 'dnsbl_exporter'
require 'yaml'
DnsblCollector.load_config './config.yml'
run lambda {|env| run lambda {|env|
begin begin
@ -16,7 +19,8 @@ run lambda {|env|
end end
collector.collect target collector.collect target
[200, {"Content-Type" => "text/plain"}, [ [200, {"Content-Type" => "text/plain"}, [
Prometheus::Client::Formats::Text.marshal( collector.prometheus) Prometheus::Client::Formats::Text.marshal( collector.registry),
Prometheus::Client::Formats::Text.marshal( DnsblCollector.registry),
]] ]]
else else
[404, {"Content-Type" => "text/plain"}, ["Not found.\nYou want to try /metrics?\n"]] [404, {"Content-Type" => "text/plain"}, ["Not found.\nYou want to try /metrics?\n"]]

View File

@ -1,7 +1,7 @@
# vim: set et sw=2 ts=2 sts=2: # vim: set et sw=2 ts=2 sts=2:
--- ---
resolver: resolver:
nameservers: 8.8.8.8 nameservers: '::1'
blacklists: blacklists:
- all.s5h.net - all.s5h.net
- b.barracudacentral.org - b.barracudacentral.org
@ -17,7 +17,6 @@ blacklists:
- dnsbl-1.uceprotect.net - dnsbl-1.uceprotect.net
- dnsbl-2.uceprotect.net - dnsbl-2.uceprotect.net
- dnsbl-3.uceprotect.net - dnsbl-3.uceprotect.net
- dnsbl.anticaptcha.net
- dnsbl.dronebl.org - dnsbl.dronebl.org
- dnsbl.inps.de - dnsbl.inps.de
- dnsbl.sorbs.net - dnsbl.sorbs.net

View File

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