first working implementation

This commit is contained in:
Denis Knauf 2018-12-14 14:58:11 +01:00
commit e008df4527
5 changed files with 171 additions and 0 deletions

6
Gemfile Normal file
View file

@ -0,0 +1,6 @@
source 'https://rubygems.org'
gem 'net-dns'
gem 'prometheus-client'
gem 'rack'
gem 'puma'

21
Gemfile.lock Normal file
View file

@ -0,0 +1,21 @@
GEM
remote: https://rubygems.org/
specs:
net-dns (0.9.0)
prometheus-client (0.8.0)
quantile (~> 0.2.1)
puma (3.12.0)
quantile (0.2.1)
rack (2.0.6)
PLATFORMS
ruby
DEPENDENCIES
net-dns
prometheus-client
puma
rack
BUNDLED WITH
1.13.6

28
config.ru Normal file
View file

@ -0,0 +1,28 @@
require 'rack'
require './dnsbl_exporter'
run lambda {|env|
begin
req = Rack::Request.new env
case req.path
when '/metrics'
collector = DnsblCollector.new
target =
begin
target = IPAddr.new req.params['target']
rescue IPAddr::AddressFamilyError
return [400, {"Content-Type" => "text/plain"}, ["Valid target-IP-Address expected.\n"]]
end
collector.collect target
[200, {"Content-Type" => "text/plain"}, [
Prometheus::Client::Formats::Text.marshal( collector.prometheus)
]]
else
[404, {"Content-Type" => "text/plain"}, ["Not found.\nYou want to try /metrics?\n"]]
end
rescue
STDERR.puts "#$! (#{$!.class})", $!.backtrace
[500, {"Content-Type" => "text/plain"}, ["Server-error.\n"]]
end
}

62
config.yml Normal file
View file

@ -0,0 +1,62 @@
# vim: set et sw=2 ts=2 sts=2:
---
resolver:
nameservers: 8.8.8.8
blacklists:
- all.s5h.net
- b.barracudacentral.org
- bl.emailbasura.org
- bl.spamcannibal.org
- bl.spamcop.net
- blacklist.woody.ch
- bogons.cymru.com
- cbl.abuseat.org
- cdl.anti-spam.org.cn
- combined.abuse.ch
- db.wpbl.info
- dnsbl-1.uceprotect.net
- dnsbl-2.uceprotect.net
- dnsbl-3.uceprotect.net
- dnsbl.anticaptcha.net
- dnsbl.dronebl.org
- dnsbl.inps.de
- dnsbl.sorbs.net
- dnsbl.spfbl.net
- drone.abuse.ch
- duinv.aupads.org
- dul.dnsbl.sorbs.net
- dyna.spamrats.com
- dynip.rothen.com
- http.dnsbl.sorbs.net
- ips.backscatterer.org
- ix.dnsbl.manitu.net
- korea.services.net
- misc.dnsbl.sorbs.net
- noptr.spamrats.com
- orvedb.aupads.org
- pbl.spamhaus.org
- proxy.bl.gweep.ca
- psbl.surriel.com
- relays.bl.gweep.ca
- relays.nether.net
- sbl.spamhaus.org
- short.rbl.jp
- singular.ttk.pte.hu
- smtp.dnsbl.sorbs.net
- socks.dnsbl.sorbs.net
- spam.abuse.ch
- spam.dnsbl.anonmails.de
- spam.dnsbl.sorbs.net
- spam.spamrats.com
- spambot.bls.digibase.ca
- spamrbl.imp.ch
- spamsources.fabel.dk
- ubl.lashback.com
- ubl.unsubscore.com
- virus.rbl.jp
- web.dnsbl.sorbs.net
- wormrbl.imp.ch
- xbl.spamhaus.org
- z.mailspike.net
- zen.spamhaus.org
- zombie.dnsbl.sorbs.net

54
dnsbl_exporter.rb Normal file
View file

@ -0,0 +1,54 @@
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
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}"
end
end
end
def collect ip
prefix = ip.send :_reverse
ip = ip.to_s
dns = Net::DNS::Resolver.new @resolver
todo = @lists.sort{|_|rand}
durs = {}
10.times.map do
Thread.new do
while bl = @lists.pop
b = 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)
rescue Net::DNS::Resolver::NoResponseError
@metrics[:dnsbl_query_error].increment( {blacklist: bl[:blacklist], target: ip})
end
durs[bl[:blacklist]] = Time.now-b
end
end
end.each &:join
end
end