summaryrefslogtreecommitdiff
path: root/lib/dnsxl_check.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dnsxl_check.rb')
-rw-r--r--lib/dnsxl_check.rb105
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/dnsxl_check.rb b/lib/dnsxl_check.rb
new file mode 100644
index 00000000000..1e506b2d9cb
--- /dev/null
+++ b/lib/dnsxl_check.rb
@@ -0,0 +1,105 @@
+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