passivedns-client 2.1.6 → 2.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -5,7 +5,7 @@ module PassiveDNS #:nodoc: don't document this
5
5
  module Provider
6
6
 
7
7
  # Queries BFK.de's passive DNS database
8
- class BFK < PassiveDB
8
+ class BFK < PassiveDB
9
9
  # Sets the modules self-reported name to "BFK.de"
10
10
  def self.name
11
11
  "BFK.de"
@@ -34,72 +34,76 @@ module PassiveDNS #:nodoc: don't document this
34
34
  #
35
35
  # PassiveDNS::Provider::BFK.new(options)
36
36
  #
37
-
38
- def initialize(options={})
39
- @debug = options[:debug] || false
37
+ def initialize(options={})
38
+ @debug = options[:debug] || false
39
+ @timeout = options[:timeout] || 20
40
40
  @base = options["URL"] || "http://www.bfk.de/bfk_dnslogger.html?query="
41
- end
41
+ raise "Due to the EU GDPR policy, this service has been shut down until further notice."
42
+ end
42
43
 
43
44
  # Takes a label (either a domain or an IP address) and returns
44
45
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
45
- def lookup(label, limit=nil)
46
- $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
47
- Timeout::timeout(240) {
48
- t1 = Time.now
49
- open(
50
- @base+label,
51
- "User-Agent" => "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}"
52
- ) do |f|
53
- t2 = Time.now
54
- recs = parse(f.read,t2-t1)
46
+ def lookup(label, limit=nil)
47
+ $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
48
+ Timeout::timeout(@timeout) {
49
+ t1 = Time.now
50
+ open(
51
+ @base+label,
52
+ "User-Agent" => "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}"
53
+ ) do |f|
54
+ t2 = Time.now
55
+ recs = parse(f.read,t2-t1)
55
56
  if limit
56
57
  recs[0,limit]
57
58
  else
58
59
  recs
59
60
  end
60
- end
61
- }
62
- rescue Timeout::Error => e
63
- $stderr.puts "#{self.class.name} lookup timed out: #{label}"
64
- end
61
+ end
62
+ }
63
+ rescue Timeout::Error
64
+ $stderr.puts "#{self.class.name} lookup timed out: #{label}"
65
+ end
65
66
 
66
67
  private
67
68
 
68
69
  # parses the webpage returned by BFK to generate an array of PDNSResult
69
- def parse(page,response_time)
70
- line = page.unpack('C*').pack('U*').split(/<table/).grep(/ id=\"logger\"/)
71
- return [] unless line.length > 0
72
- line = line[0].gsub(/[\t\n]/,'').gsub(/<\/table.*/,'')
73
- rows = line.split(/<tr.*?>/)
74
- res = []
75
- rows.collect do |row|
76
- r = row.split(/<td>/).map{|x| x.gsub(/<.*?>/,'').gsub(/\&.*?;/,'')}[1,1000]
77
- if r and r[0] =~ /\w/
78
- # BFK includes the MX weight in the answer response. First, find the MX records, then dump the weight to present a consistent record name to the collecting array. Otherwise the other repositories will present the same answer and your results will become cluttered with duplicates.
79
- if r[1] == "MX" then
80
- # MX lines look like "5 mx.domain.tld", so split on the space and assign r[2] (:answer) to the latter part.
81
- #s = r[2].split(/\w/).map{|x| x}[1,1000]
82
- # r[2] = s[1]
83
- r[2] =~ /[0-9]+?\s(.+)/
84
- s=$1
85
- puts "DEBUG: == BFK: MX Parsing Strip: Answer: " + r[2] + " : mod: " + s if @debug
86
- r[2] = s
87
-
88
- ######### FIX BLANKS FOR MX
89
-
90
- end
70
+ def parse(page,response_time)
71
+ line = page.unpack('C*').pack('U*').split(/<table/).grep(/ id=\"logger\"/)
72
+ return [] unless line.length > 0
73
+ line = line[0].gsub(/[\t\n]/,'').gsub(/<\/table.*/,'')
74
+ rows = line.split(/<tr.*?>/)
75
+ res = []
76
+ rows.collect do |row|
77
+ r = row.split(/<td>/).map{|x| x.gsub(/<.*?>/,'').gsub(/\&.*?;/,'')}[1,1000]
78
+ if r and r[0] =~ /\w/
79
+ # BFK includes the MX weight in the answer response. First, find the MX records,
80
+ # then dump the weight to present a consistent record name to the collecting
81
+ # array. Otherwise the other repositories will present the same answer and
82
+ # your results will become cluttered with duplicates.
83
+ if r[1] == "MX" then
84
+ # MX lines look like "5 mx.domain.tld", so split on the space and assign r[2] (:answer) to the latter part.
85
+ #s = r[2].split(/\w/).map{|x| x}[1,1000]
86
+ # r[2] = s[1]
87
+ r[2] =~ /[0-9]+?\s(.+)/
88
+ s=$1
89
+ #puts "DEBUG: == BFK: MX Parsing Strip: Answer: " + r[2] + " : mod: " + s if @debug
90
+ r[2] = s
91
+
92
+ ######### FIX BLANKS FOR MX
93
+
94
+ end
91
95
  query = r[0]
92
96
  answer = r[2]
93
97
  rrtype = r[1]
94
- res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype)
95
- end
96
- end
97
- res
98
- rescue Exception => e
99
- $stderr.puts "#{self.class.name} Exception: #{e}"
100
- raise e
101
- end
98
+ res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype,'white')
99
+ end
100
+ end
101
+ res
102
+ rescue Exception => e
103
+ $stderr.puts "#{self.class.name} Exception: #{e}"
104
+ raise e
105
+ end
102
106
 
103
- end
107
+ end
104
108
  end
105
- end
109
+ end
@@ -9,7 +9,7 @@ module PassiveDNS #:nodoc: don't document this
9
9
  module Provider
10
10
  # Queries CIRCL.LU's passive DNS database
11
11
  # Circl is aliased by CIRCL
12
- class Circl < PassiveDB
12
+ class Circl < PassiveDB
13
13
  # Sets the modules self-reported name to "CIRCL"
14
14
  def self.name
15
15
  "CIRCL"
@@ -45,68 +45,84 @@ module PassiveDNS #:nodoc: don't document this
45
45
  #
46
46
  # PassiveDNS::Provider::CIRCL.new(options)
47
47
  #
48
- def initialize(options={})
48
+ def initialize(options={})
49
49
  @debug = options[:debug] || false
50
+ @timeout = options[:timeout] || 20
50
51
  @username = options["USERNAME"]
51
52
  @password = options["PASSWORD"]
52
53
  @auth_token = options["AUTH_TOKEN"]
53
54
  @url = options["URL"] || "https://www.circl.lu/pdns/query"
54
- end
55
+ end
55
56
 
56
57
  # Takes a label (either a domain or an IP address) and returns
57
58
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
58
- def lookup(label, limit=nil)
59
- $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
60
- Timeout::timeout(240) {
61
- url = @url+"/"+label
62
- $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
63
- url = URI.parse url
64
- http = Net::HTTP.new(url.host, url.port)
65
- http.use_ssl = (url.scheme == 'https')
66
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
67
- http.verify_depth = 5
68
- request = Net::HTTP::Get.new(url.request_uri)
69
- request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
59
+ def lookup(label, limit=nil)
60
+ $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
61
+ recs = []
62
+ Timeout::timeout(@timeout) {
63
+ url = @url+"/"+label
64
+ $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
65
+ begin
66
+ url = URI.parse url
67
+ rescue URI::InvalidURIError
68
+ $stderr.puts "ERROR: Invalid address: #{url}"
69
+ return recs
70
+ end
71
+ http = Net::HTTP.new(url.host, url.port)
72
+ http.use_ssl = (url.scheme == 'https')
73
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
74
+ http.verify_depth = 5
75
+ request = Net::HTTP::Get.new(url.request_uri)
76
+ request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
70
77
  if @username
71
78
  request.basic_auth(@username, @password)
72
79
  end
73
80
  if @auth_token
74
81
  request.add_field("Authorization", @auth_token)
75
82
  end
76
- t1 = Time.now
77
- response = http.request(request)
78
- t2 = Time.now
79
- recs = parse_json(response.body, label, t2-t1)
80
- if limit
81
- recs[0,limit]
82
- else
83
- recs
84
- end
85
- }
86
- rescue Timeout::Error => e
87
- $stderr.puts "#{self.class.name} lookup timed out: #{label}"
88
- end
83
+ t1 = Time.now
84
+ 0.upto(9) do
85
+ response = http.request(request)
86
+ body = response.body
87
+ if body == "Rate Limit Exceeded"
88
+ $stderr.puts "DEBUG: Rate Limit Exceeded. Retrying #{label}" if @debug
89
+ else
90
+ t2 = Time.now
91
+ recs = parse_json(response.body, label, t2-t1)
92
+ break
93
+ end
94
+ end
95
+ if limit
96
+ recs[0,limit]
97
+ else
98
+ recs
99
+ end
100
+ }
101
+ rescue Timeout::Error
102
+ $stderr.puts "#{self.class.name} lookup timed out: #{label}"
103
+ recs
104
+ end
89
105
 
90
106
  private
91
107
 
92
108
  # parses the response of circl's JSON reply to generate an array of PDNSResult
93
- def parse_json(page,query,response_time=0)
94
- res = []
109
+ def parse_json(page,query,response_time=0)
110
+ res = []
95
111
  page.split(/\n/).each do |line|
96
112
  row = JSON.parse(line)
97
113
  firstseen = Time.at(row['time_first'].to_i)
98
114
  lastseen = Time.at(row['time_last'].to_i)
99
- res << PDNSResult.new(self.class.name,response_time,
115
+ res << PDNSResult.new(self.class.name,response_time,
100
116
  row['rrname'], row['rdata'], row['rrtype'], 0,
101
- firstseen, lastseen, row['count'])
117
+ firstseen, lastseen, row['count'], 'yellow')
102
118
  end
103
- res
104
- rescue Exception => e
105
- $stderr.puts "#{self.class.name} Exception: #{e}"
106
- raise e
107
- end
119
+ res
120
+ rescue Exception => e
121
+ $stderr.puts "#{self.class.name} Exception: #{e}"
122
+ raise e
123
+ end
108
124
 
109
- end
125
+ end
110
126
  CIRCL = PassiveDNS::Provider::Circl
111
127
  end
112
- end
128
+ end
@@ -3,6 +3,7 @@ require 'net/https'
3
3
  require 'openssl'
4
4
  require 'json'
5
5
  require 'digest/md5'
6
+ require 'pp'
6
7
 
7
8
  module PassiveDNS #:nodoc: don't document this
8
9
  # The Provider module contains all the Passive DNS provider client code
@@ -43,6 +44,7 @@ module PassiveDNS #:nodoc: don't document this
43
44
  #
44
45
  def initialize(options={})
45
46
  @debug = options[:debug] || false
47
+ @timeout = options[:timeout] || 20
46
48
  ["API", "API_ID", "API_KEY"].each do |opt|
47
49
  if not options[opt]
48
50
  raise "Field #{opt} is required. See README.md"
@@ -60,52 +62,61 @@ module PassiveDNS #:nodoc: don't document this
60
62
  end
61
63
  limit ||= 10000
62
64
  path = "/api/#{table}/keyword/#{label}/count/#{limit}/"
63
- url = @cp["API"]+path
64
- url = URI.parse url
65
- http = Net::HTTP.new(url.host, url.port)
66
- http.use_ssl = (url.scheme == 'https')
67
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE # I hate doing this
68
- http.verify_depth = 5
69
- request = Net::HTTP::Get.new(url.path)
70
- request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
71
- request.add_field('Accept', 'application/json')
72
- request.add_field("X-BashTokid", @cp["API_ID"])
73
- token = Digest::MD5.hexdigest(path+@cp["API_KEY"])
74
- $stderr.puts "DEBUG: cn360 url = #{url} token = #{token}" if @debug
75
- request.add_field("X-BashToken", token)
76
- t1 = Time.now
77
- response = http.request(request)
78
- t2 = Time.now
79
- recs = parse_json(response.body, label, t2-t1)
80
- if limit
81
- recs[0,limit]
82
- else
83
- recs
84
- end
65
+ Timeout::timeout(@timeout) {
66
+ url = @cp["API"]+path
67
+ url = URI.parse url
68
+ http = Net::HTTP.new(url.host, url.port)
69
+ http.use_ssl = (url.scheme == 'https')
70
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE # I hate doing this
71
+ http.verify_depth = 5
72
+ request = Net::HTTP::Get.new(url.path)
73
+ request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
74
+ request.add_field('Accept', 'application/json')
75
+ request.add_field("X-BashTokid", @cp["API_ID"])
76
+ token = Digest::MD5.hexdigest(path+@cp["API_KEY"])
77
+ $stderr.puts "DEBUG: cn360 url = #{url} token = #{token}" if @debug
78
+ request.add_field("X-BashToken", token)
79
+ t1 = Time.now
80
+ response = http.request(request)
81
+ t2 = Time.now
82
+ recs = parse_json(response.body, label, t2-t1)
83
+ if limit
84
+ recs[0,limit]
85
+ else
86
+ recs
87
+ end
88
+ }
89
+ rescue Timeout::Error
90
+ $stderr.puts "#{self.class.name} lookup timed out: #{label}"
91
+ recs
85
92
  end
86
93
 
87
94
  private
88
95
 
89
96
  # parses the response of 360.cn's JSON reply to generate an array of PDNSResult
90
97
  def parse_json(page,query,response_time=0)
91
- res = []
92
- data = JSON.parse(page)
98
+ res = []
99
+ data = JSON.parse(page)
100
+ if data.class == Hash and data['err']
101
+ raise "#{self.class.name} Error: #{data['err']}"
102
+ end
93
103
  data.each do |row|
94
- time_first = (row["time_first"]) ? Time.at(row["time_first"].to_i) : nil
95
- time_last = (row["time_last"]) ? Time.at(row["time_last"].to_i) : nil
104
+ time_first = (row["time_first"]) ? Time.at(row["time_first"]) : nil
105
+ time_last = (row["time_last"]) ? Time.at(row["time_last"]) : nil
96
106
  count = row["count"] || 0
97
107
  query = row["rrname"]
98
108
  answers = row["rdata"].gsub(/;$/,'').split(/;/)
99
109
  rrtype = row["rrtype"]
100
110
  answers.each do |answer|
101
- res << PDNSResult.new(self.class.name, response_time, query, answer, rrtype, time_first, time_last, count)
111
+ res << PDNSResult.new(self.class.name, response_time, query, answer, rrtype, nil, time_first, time_last, count, TLPSecurityControl.new('yellow'))
102
112
  end
103
- end
104
- res
105
- rescue Exception => e
106
- $stderr.puts "#{self.class.name} Exception: #{e}"
107
- raise e
113
+ end
114
+ res
115
+ rescue Exception => e
116
+ $stderr.puts "#{self.class.name} Exception: #{e}"
117
+ puts e.backtrace
118
+ raise e
108
119
  end
109
120
  end
110
121
  end
111
- end
122
+ end
@@ -8,7 +8,7 @@ module PassiveDNS #:nodoc: don't document this
8
8
  # The Provider module contains all the Passive DNS provider client code
9
9
  module Provider
10
10
  # Queries FarSight's passive DNS database
11
- class DNSDB < PassiveDB
11
+ class DNSDB < PassiveDB
12
12
  # Sets the modules self-reported name to "DNSDB"
13
13
  def self.name
14
14
  "DNSDB"
@@ -39,80 +39,81 @@ module PassiveDNS #:nodoc: don't document this
39
39
  #
40
40
  # PassiveDNS::Provider::DNSDB.new(options)
41
41
  #
42
- def initialize(options={})
43
- @debug = options[:debug] || false
42
+ def initialize(options={})
43
+ @debug = options[:debug] || false
44
+ @timeout = options[:timeout] || 20
44
45
  @key = options["APIKEY"] || raise("APIKEY option required for #{self.class}")
45
46
  @base = options["URL"] || "https://api.dnsdb.info/lookup"
46
- end
47
+ end
47
48
 
48
49
  # Takes a label (either a domain or an IP address) and returns
49
50
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
50
- def lookup(label, limit=nil)
51
- $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
52
- Timeout::timeout(240) {
53
- url = nil
54
- if label =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/
55
- label = label.gsub(/\//,',')
56
- url = "#{@base}/rdata/ip/#{label}"
57
- else
58
- url = "#{@base}/rrset/name/#{label}"
59
- end
60
- url = URI.parse url
61
- http = Net::HTTP.new(url.host, url.port)
62
- http.use_ssl = (url.scheme == 'https')
63
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
64
- http.verify_depth = 5
51
+ def lookup(label, limit=nil)
52
+ $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
53
+ Timeout::timeout(@timeout) {
54
+ url = nil
55
+ if label =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/
56
+ label = label.gsub(/\//,',')
57
+ url = "#{@base}/rdata/ip/#{label}"
58
+ else
59
+ url = "#{@base}/rrset/name/#{label}"
60
+ end
61
+ url = URI.parse url
62
+ http = Net::HTTP.new(url.host, url.port)
63
+ http.use_ssl = (url.scheme == 'https')
64
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
+ http.verify_depth = 5
65
66
  path = url.path
66
67
  if limit
67
68
  path << "?limit=#{limit}"
68
69
  end
69
- request = Net::HTTP::Get.new(path)
70
- request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
71
- request.add_field("X-API-Key", @key)
72
- request.add_field("Accept", "application/json")
73
- t1 = Time.now
74
- response = http.request(request)
75
- t2 = Time.now
76
- $stderr.puts response.body if @debug
77
- parse_json(response.body,t2-t1)
78
- }
79
- rescue Timeout::Error => e
80
- $stderr.puts "#{self.class.name} lookup timed out: #{label}"
81
- end
70
+ request = Net::HTTP::Get.new(path)
71
+ request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
72
+ request.add_field("X-API-Key", @key)
73
+ request.add_field("Accept", "application/json")
74
+ t1 = Time.now
75
+ response = http.request(request)
76
+ t2 = Time.now
77
+ $stderr.puts response.body if @debug
78
+ parse_json(response.body,t2-t1)
79
+ }
80
+ rescue Timeout::Error
81
+ $stderr.puts "#{self.class.name} lookup timed out: #{label}"
82
+ end
82
83
 
83
84
  private
84
85
 
85
86
  # parses the response of DNSDB's JSON reply to generate an array of PDNSResult
86
- def parse_json(page,response_time)
87
- res = []
88
- raise "Error: unable to parse request" if page =~ /Error: unable to parse request/
89
- rows = page.split(/\n/)
90
- rows.each do |row|
91
- record = JSON.parse(row)
87
+ def parse_json(page,response_time)
88
+ res = []
89
+ raise "Error: unable to parse request" if page =~ /Error: unable to parse request/
90
+ rows = page.split(/\n/)
91
+ rows.each do |row|
92
+ record = JSON.parse(row)
92
93
  answers = record['rdata']
93
- answers = [record['rdata']] if record['rdata'].class == String
94
+ answers = [record['rdata']] if record['rdata'].class == String
94
95
  query = record['rrname'].gsub!(/\.$/,'')
95
96
  rrtype = record['rrtype']
96
97
  firstseen = Time.at(record['time_first'].to_i)
97
98
  lastseen = Time.at(record['time_last'].to_i)
98
99
  count = record['count']
99
100
 
100
- answers.each do |answer|
101
+ answers.each do |answer|
101
102
  answer.gsub!(/\.$/,'')
102
- if record['time_first']
103
- res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype,
104
- 0,firstseen,lastseen,count)
105
- else
106
- res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype)
107
- end
108
- end
109
- end
110
- res
111
- rescue Exception => e
112
- $stderr.puts "#{self.class.name} Exception: #{e}"
113
- $stderr.puts page
114
- raise e
115
- end
116
- end
103
+ if record['time_first']
104
+ res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype,
105
+ 0,firstseen,lastseen,count, 'yellow')
106
+ else
107
+ res << PDNSResult.new(self.class.name,response_time,query,answer,rrtype)
108
+ end
109
+ end
110
+ end
111
+ res
112
+ rescue Exception => e
113
+ $stderr.puts "#{self.class.name} Exception: #{e}"
114
+ $stderr.puts page
115
+ raise e
116
+ end
117
+ end
117
118
  end
118
- end
119
+ end