106 lines
1.9 KiB
Ruby
106 lines
1.9 KiB
Ruby
|
require 'resolv'
|
||
|
|
||
|
class DNSXLCheck
|
||
|
|
||
|
class Resolver
|
||
|
def self.search(query)
|
||
|
begin
|
||
|
Resolv.getaddress(query)
|
||
|
true
|
||
|
rescue Resolv::ResolvError
|
||
|
false
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
IP_REGEXP = /\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/
|
||
|
DEFAULT_THRESHOLD = 0.33
|
||
|
|
||
|
def self.create_from_list(list)
|
||
|
dnsxl_check = DNSXLCheck.new
|
||
|
|
||
|
list.each do |entry|
|
||
|
dnsxl_check.add_list(entry.domain, entry.weight)
|
||
|
end
|
||
|
|
||
|
dnsxl_check
|
||
|
end
|
||
|
|
||
|
def test(ip)
|
||
|
if use_threshold?
|
||
|
test_with_threshold(ip)
|
||
|
else
|
||
|
test_strict(ip)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def test_with_threshold(ip)
|
||
|
return false if lists.empty?
|
||
|
|
||
|
search(ip)
|
||
|
final_score >= threshold
|
||
|
end
|
||
|
|
||
|
def test_strict(ip)
|
||
|
return false if lists.empty?
|
||
|
|
||
|
search(ip)
|
||
|
@score > 0
|
||
|
end
|
||
|
|
||
|
def use_threshold=(value)
|
||
|
@use_threshold = value == true
|
||
|
end
|
||
|
|
||
|
def use_threshold?
|
||
|
@use_threshold &&= true
|
||
|
end
|
||
|
|
||
|
def threshold=(threshold)
|
||
|
raise ArgumentError, "'threshold' value must be grather than 0 and less than or equal to 1" unless threshold > 0 && threshold <= 1
|
||
|
@threshold = threshold
|
||
|
end
|
||
|
|
||
|
def threshold
|
||
|
@threshold ||= DEFAULT_THRESHOLD
|
||
|
end
|
||
|
|
||
|
def add_list(domain, weight)
|
||
|
@lists ||= []
|
||
|
@lists << { domain: domain, weight: weight }
|
||
|
end
|
||
|
|
||
|
def lists
|
||
|
@lists ||= []
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def search(ip)
|
||
|
raise ArgumentError, "'ip' value must be in #{IP_REGEXP} format" unless ip.match(IP_REGEXP)
|
||
|
|
||
|
@score = 0
|
||
|
|
||
|
reversed = reverse_ip(ip)
|
||
|
search_in_rbls(reversed)
|
||
|
end
|
||
|
|
||
|
def reverse_ip(ip)
|
||
|
ip.split('.').reverse.join('.')
|
||
|
end
|
||
|
|
||
|
def search_in_rbls(reversed_ip)
|
||
|
lists.each do |rbl|
|
||
|
query = "#{reversed_ip}.#{rbl[:domain]}"
|
||
|
@score += rbl[:weight] if Resolver.search(query)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def final_score
|
||
|
weights = lists.map{ |rbl| rbl[:weight] }.reduce(:+).to_i
|
||
|
return 0 if weights == 0
|
||
|
|
||
|
(@score.to_f / weights.to_f).round(2)
|
||
|
end
|
||
|
end
|