passivedns-client 2.0.6 → 2.1.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +6 -0
- data/Rakefile +8 -0
- data/lib/passivedns/client.rb +14 -7
- data/lib/passivedns/client/cli.rb +34 -6
- data/lib/passivedns/client/passivedb.rb +6 -1
- data/lib/passivedns/client/provider/bfk.rb +102 -0
- data/lib/passivedns/client/provider/circl.rb +111 -0
- data/lib/passivedns/client/provider/cn360.rb +108 -0
- data/lib/passivedns/client/provider/dnsdb.rb +110 -0
- data/lib/passivedns/client/provider/mnemonic.rb +98 -0
- data/lib/passivedns/client/provider/passivetotal.rb +103 -0
- data/lib/passivedns/client/provider/riskiq.rb +130 -0
- data/lib/passivedns/client/provider/tcpiputils.rb +118 -0
- data/lib/passivedns/client/provider/virustotal.rb +105 -0
- data/lib/passivedns/client/state.rb +30 -2
- data/lib/passivedns/client/version.rb +4 -2
- data/test/test_cli.rb +6 -5
- data/test/test_passivedns-client.rb +33 -8
- metadata +11 -10
- data/lib/passivedns/client/providers/bfk.rb +0 -77
- data/lib/passivedns/client/providers/circl.rb +0 -79
- data/lib/passivedns/client/providers/cn360.rb +0 -80
- data/lib/passivedns/client/providers/dnsdb.rb +0 -85
- data/lib/passivedns/client/providers/mnemonic.rb +0 -72
- data/lib/passivedns/client/providers/passivetotal.rb +0 -77
- data/lib/passivedns/client/providers/tcpiputils.rb +0 -92
- data/lib/passivedns/client/providers/virustotal.rb +0 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bc0b0ff155e1b9570c05b45f22368b0cfa79a83
|
4
|
+
data.tar.gz: 4b2d805d77a29ef052c0003a116c21224166254f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21dd2aefcc5074d626047c4cf4e798c33b9dc063199667b29a68614463b464e01f91fe72b285ecf2a3a752f8ef1f9a4082c1da797f6ed405950becefa32e5c55
|
7
|
+
data.tar.gz: 39c7c7ae6f931634c58c588a9ce7113bdcd776becc587036e6a51261ba7d67008619b9cdf9da478674ba34cc46d255a965a9dc6dbaec83c9092e59daa95a2b49
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,7 @@ This rubygem queries the following Passive DNS databases:
|
|
8
8
|
* Mnemonic
|
9
9
|
* PassiveDNS.cn (Qihoo 360 Technology Co.,Ltd)
|
10
10
|
* PassiveTotal
|
11
|
+
* RiskIQ
|
11
12
|
* TCPIPUtils
|
12
13
|
* VirusTotal
|
13
14
|
|
@@ -54,6 +55,9 @@ From version 2.0.0 on, all configuration keys for passive DNS providers are in o
|
|
54
55
|
[circl]
|
55
56
|
USERNAME = circl_user
|
56
57
|
PASSWORD = circl_pass
|
58
|
+
[riskiq]
|
59
|
+
API_TOKEN = 0123456789abcdef
|
60
|
+
API_PRIVATE_KEY = 01234567890abcdefghijklmnopqrstu
|
57
61
|
|
58
62
|
CIRCL also can use and authorization token. In that case, you should drop the USERNAME and PASSWORD options and change the section to something like the following:
|
59
63
|
|
@@ -67,6 +71,7 @@ CIRCL also can use and authorization token. In that case, you should drop the U
|
|
67
71
|
* DNSDB (Farsight Security) : https://api.dnsdb.info/
|
68
72
|
* Mnemonic : mss .at. mnemonic.no
|
69
73
|
* PassiveTotal : https://www.passivetotal.org
|
74
|
+
* RiskIQ : https://github.com/RiskIQ/python_api/blob/master/LICENSE
|
70
75
|
* TCPIPUtils : http://www.tcpiputils.com/premium-access
|
71
76
|
* VirusTotal : https://www.virustotal.com
|
72
77
|
|
@@ -88,6 +93,7 @@ Or use the included tool...
|
|
88
93
|
-dd use DNSDB
|
89
94
|
-dm use Mnemonic
|
90
95
|
-dp use PassiveTotal
|
96
|
+
-dr use RiskIQ
|
91
97
|
-dt use TCPIPUtils
|
92
98
|
-dv use VirusTotal
|
93
99
|
-dvt uses VirusTotal and TCPIPUtils (for example)
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
|
4
4
|
require 'rake/testtask'
|
5
|
+
require 'rdoc/task'
|
5
6
|
|
6
7
|
Rake::TestTask.new do |t|
|
7
8
|
t.libs << 'lib'
|
@@ -9,4 +10,11 @@ Rake::TestTask.new do |t|
|
|
9
10
|
t.verbose = true
|
10
11
|
end
|
11
12
|
|
13
|
+
RDoc::Task.new do |rd|
|
14
|
+
rd.main = "README.doc"
|
15
|
+
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
16
|
+
rd.options << "--all"
|
17
|
+
rd.options << "--verbose"
|
18
|
+
end
|
19
|
+
|
12
20
|
task :default => :test
|
data/lib/passivedns/client.rb
CHANGED
@@ -8,27 +8,32 @@ require 'passivedns/client/passivedb'
|
|
8
8
|
|
9
9
|
# load all the providers
|
10
10
|
$passivedns_providers = Array.new
|
11
|
-
provider_path = File.dirname(__FILE__)+"/client/
|
11
|
+
provider_path = File.dirname(__FILE__)+"/client/provider/*.rb"
|
12
12
|
Dir.glob(provider_path).each do |provider|
|
13
13
|
name = File.basename(provider, '.rb')
|
14
|
-
require "passivedns/client/
|
14
|
+
require "passivedns/client/provider/#{name}.rb"
|
15
15
|
$passivedns_providers << name
|
16
16
|
end
|
17
17
|
|
18
18
|
require 'configparser'
|
19
19
|
|
20
|
-
module PassiveDNS
|
21
|
-
|
20
|
+
module PassiveDNS # :nodoc:
|
21
|
+
# struct to contain the results from a PassiveDNS lookup
|
22
22
|
class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count); end
|
23
23
|
|
24
|
+
# coodinates the lookups accross all configured PassiveDNS providers
|
24
25
|
class Client
|
26
|
+
|
27
|
+
# instantiate and configure all specified PassiveDNS providers
|
28
|
+
# pdns array of passivedns provider names, e.g., ["dnsdb","virustotal"]
|
29
|
+
# configfile filename of the passivedns-client configuration (this should probably be abstracted)
|
25
30
|
def initialize(pdns=$passivedns_providers, configfile="#{ENV['HOME']}/.passivedns-client")
|
26
31
|
cp = ConfigParser.new(configfile)
|
27
32
|
# this creates a map of all the PassiveDNS provider names and their classes
|
28
33
|
class_map = {}
|
29
|
-
PassiveDNS.constants.each do |const|
|
30
|
-
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
31
|
-
class_map[PassiveDNS.const_get(const).config_section_name] = PassiveDNS.const_get(const)
|
34
|
+
PassiveDNS::Provider.constants.each do |const|
|
35
|
+
if PassiveDNS::Provider.const_get(const).is_a?(Class) and PassiveDNS::Provider.const_get(const).superclass == PassiveDNS::PassiveDB
|
36
|
+
class_map[PassiveDNS::Provider.const_get(const).config_section_name] = PassiveDNS::Provider.const_get(const)
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -43,12 +48,14 @@ module PassiveDNS
|
|
43
48
|
|
44
49
|
end #initialize
|
45
50
|
|
51
|
+
# set the debug flag
|
46
52
|
def debug=(d)
|
47
53
|
@pdnsdbs.each do |pdnsdb|
|
48
54
|
pdnsdb.debug = d
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
58
|
+
# perform the query lookup accross all configured PassiveDNS providers
|
52
59
|
def query(item, limit=nil)
|
53
60
|
threads = []
|
54
61
|
@pdnsdbs.each do |pdnsdb|
|
@@ -4,18 +4,39 @@ require 'getoptlong'
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'pp'
|
6
6
|
|
7
|
-
module PassiveDNS
|
7
|
+
module PassiveDNS # :nodoc:
|
8
|
+
# Handles all the command-line parsing, state tracking, and dispatching queries to the PassiveDNS::Client instance
|
9
|
+
# CLInterface is aliased by CLI
|
8
10
|
class CLInterface
|
11
|
+
# generates a mapping between the option letter for each PassiveDNS provider and the class
|
9
12
|
def self.get_letter_map
|
10
13
|
letter_map = {}
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
mod = PassiveDNS::Provider
|
15
|
+
mod.constants.each do |const|
|
16
|
+
if mod.const_get(const).is_a?(Class) and mod.const_get(const).superclass == PassiveDNS::PassiveDB
|
17
|
+
letter = mod.const_get(const).option_letter
|
18
|
+
name = mod.const_get(const).name
|
19
|
+
config_section_name = mod.const_get(const).config_section_name
|
20
|
+
letter_map[letter] = [name, config_section_name]
|
14
21
|
end
|
15
22
|
end
|
16
23
|
letter_map
|
17
24
|
end
|
18
25
|
|
26
|
+
# parses the command line and yields an options hash
|
27
|
+
# === Default Options
|
28
|
+
# options = {
|
29
|
+
# :pdnsdbs => [], # passive dns providers to query
|
30
|
+
# :format => "text", # output format
|
31
|
+
# :sep => "\t", # field separator for text format
|
32
|
+
# :recursedepth => 1, # recursion depth
|
33
|
+
# :wait => 0, # wait period between recursions
|
34
|
+
# :res => nil, # unused. I don't remember why this is here.
|
35
|
+
# :debug => false, # debug flag
|
36
|
+
# :sqlitedb => nil, # filename for maintaining state in an sqlite3 db
|
37
|
+
# :limit => nil, # number of results per provider per recursion
|
38
|
+
# :help => false # display the usage text
|
39
|
+
# }
|
19
40
|
def self.parse_command_line(args)
|
20
41
|
origARGV = ARGV.dup
|
21
42
|
ARGV.replace(args)
|
@@ -132,6 +153,8 @@ module PassiveDNS
|
|
132
153
|
[options, args]
|
133
154
|
end
|
134
155
|
|
156
|
+
# returns a string containing the usage information
|
157
|
+
# takes in a hash of letter to passive dns providers
|
135
158
|
def self.usage(letter_map)
|
136
159
|
databases = letter_map.keys.sort.join("")
|
137
160
|
help_text = ""
|
@@ -167,6 +190,7 @@ module PassiveDNS
|
|
167
190
|
help_text
|
168
191
|
end
|
169
192
|
|
193
|
+
# performs a stateful, recursive (if desired) passive DNS lookup against all specified providers
|
170
194
|
def self.pdnslookup(state, pdnsclient, options)
|
171
195
|
recursedepth = options[:recursedepth]
|
172
196
|
wait = options[:wait]
|
@@ -195,6 +219,7 @@ module PassiveDNS
|
|
195
219
|
state
|
196
220
|
end
|
197
221
|
|
222
|
+
# returns a string transforming all the PassiveDNS::PDNSResult stored in the state object into text/xml/json/etc.
|
198
223
|
def self.results_to_s(state,options)
|
199
224
|
format = options[:format]
|
200
225
|
sep = options[:sep]
|
@@ -216,6 +241,7 @@ module PassiveDNS
|
|
216
241
|
end
|
217
242
|
end
|
218
243
|
|
244
|
+
# create a state instance
|
219
245
|
def self.create_state(sqlitedb=nil)
|
220
246
|
state = nil
|
221
247
|
if sqlitedb
|
@@ -225,6 +251,7 @@ module PassiveDNS
|
|
225
251
|
end
|
226
252
|
end
|
227
253
|
|
254
|
+
# main method, takes command-line arguments and performs the desired queries and outputs
|
228
255
|
def self.run(args)
|
229
256
|
options, items = parse_command_line(args)
|
230
257
|
if options[:help]
|
@@ -240,8 +267,8 @@ module PassiveDNS
|
|
240
267
|
pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs])
|
241
268
|
pdnsclient.debug = options[:debug]
|
242
269
|
|
243
|
-
if
|
244
|
-
|
270
|
+
if items.length > 0
|
271
|
+
items.each do |arg|
|
245
272
|
state.add_query(arg,'pending',0)
|
246
273
|
end
|
247
274
|
else
|
@@ -253,6 +280,7 @@ module PassiveDNS
|
|
253
280
|
results_to_s(state,options)
|
254
281
|
end
|
255
282
|
end
|
283
|
+
# Alias for the CLInterface class
|
256
284
|
CLI = PassiveDNS::CLInterface
|
257
285
|
end
|
258
286
|
|
@@ -1,17 +1,22 @@
|
|
1
|
-
module PassiveDNS
|
1
|
+
module PassiveDNS #:nodoc: don't document this
|
2
|
+
# abstract class that all PassiveDNS::Provider should subclass
|
2
3
|
class PassiveDB
|
4
|
+
# raises an exception that this should be implemented by the subclass
|
3
5
|
def self.name
|
4
6
|
raise "You should implement your own version of .name"
|
5
7
|
end
|
6
8
|
|
9
|
+
# raises an exception that this should be implemented by the subclass
|
7
10
|
def self.config_section_name
|
8
11
|
name
|
9
12
|
end
|
10
13
|
|
14
|
+
# raises an exception that this should be implemented by the subclass
|
11
15
|
def self.option_letter
|
12
16
|
raise "You should pick a unique letter to serve as your database option letter for the command line option -d"
|
13
17
|
end
|
14
18
|
|
19
|
+
# raises an exception that this should be implemented by the subclass
|
15
20
|
def lookup(label, limit=nil)
|
16
21
|
raise "You must implement the lookup function"
|
17
22
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module PassiveDNS #:nodoc: don't document this
|
4
|
+
# The Provider module contains all the Passive DNS provider client code
|
5
|
+
module Provider
|
6
|
+
|
7
|
+
# Queries BFK.de's passive DNS database
|
8
|
+
class BFK < PassiveDB
|
9
|
+
# Sets the modules self-reported name to "BFK.de"
|
10
|
+
def self.name
|
11
|
+
"BFK.de"
|
12
|
+
end
|
13
|
+
# Sets the configuration section name to "bfk"
|
14
|
+
def self.config_section_name
|
15
|
+
"bfk"
|
16
|
+
end
|
17
|
+
# Sets the command line database argument to "b"
|
18
|
+
def self.option_letter
|
19
|
+
"b"
|
20
|
+
end
|
21
|
+
|
22
|
+
# :debug enables verbose logging to standard output
|
23
|
+
attr_accessor :debug
|
24
|
+
# === Options
|
25
|
+
# * :debug Sets the debug flag for the module
|
26
|
+
# * "URL" Alternate url for testing. Defaults to "http://www.bfk.de/bfk_dnslogger.html?query="
|
27
|
+
#
|
28
|
+
# === Example Instantiation
|
29
|
+
#
|
30
|
+
# options = {
|
31
|
+
# :debug => true,
|
32
|
+
# "URL" => "http://www.bfk.de/bfk_dnslogger.html?query="
|
33
|
+
# }
|
34
|
+
#
|
35
|
+
# PassiveDNS::Provider::BFK.new(options)
|
36
|
+
#
|
37
|
+
|
38
|
+
def initialize(options={})
|
39
|
+
@debug = options[:debug] || false
|
40
|
+
@base = options["URL"] || "http://www.bfk.de/bfk_dnslogger.html?query="
|
41
|
+
end
|
42
|
+
|
43
|
+
# Takes a label (either a domain or an IP address) and returns
|
44
|
+
# 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)
|
55
|
+
if limit
|
56
|
+
recs[0,limit]
|
57
|
+
else
|
58
|
+
recs
|
59
|
+
end
|
60
|
+
end
|
61
|
+
}
|
62
|
+
rescue Timeout::Error => e
|
63
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# 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
|
91
|
+
res << PDNSResult.new(self.class.name,response_time,r[0],r[2],r[1])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
res
|
95
|
+
rescue Exception => e
|
96
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
97
|
+
raise e
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# DESCRIPTION: Module to query PassiveTotal's passive DNS repository
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module PassiveDNS #:nodoc: don't document this
|
8
|
+
# The Provider module contains all the Passive DNS provider client code
|
9
|
+
module Provider
|
10
|
+
# Queries CIRCL.LU's passive DNS database
|
11
|
+
# Circl is aliased by CIRCL
|
12
|
+
class Circl < PassiveDB
|
13
|
+
# Sets the modules self-reported name to "CIRCL"
|
14
|
+
def self.name
|
15
|
+
"CIRCL"
|
16
|
+
end
|
17
|
+
# Sets the configuration section name to "circl"
|
18
|
+
def self.config_section_name
|
19
|
+
"circl"
|
20
|
+
end
|
21
|
+
# Sets the command line database argument to "c"
|
22
|
+
def self.option_letter
|
23
|
+
"c"
|
24
|
+
end
|
25
|
+
|
26
|
+
# :debug enables verbose logging to standard output
|
27
|
+
attr_accessor :debug
|
28
|
+
# === Options
|
29
|
+
# * :debug Sets the debug flag for the module
|
30
|
+
# * "USERNAME" User name associated with your CIRCL account
|
31
|
+
# * "PASSWORD" Password associated with your CIRCL account
|
32
|
+
# * "AUTH_TOKEN" Authorization token associated with your CIRCL account
|
33
|
+
# * "URL" Alternate url for testing. Defaults to "https://www.circl.lu/pdns/query"
|
34
|
+
|
35
|
+
# You should either have a username+password or an authorization token to use this service
|
36
|
+
#
|
37
|
+
# === Example Instantiation
|
38
|
+
#
|
39
|
+
# options = {
|
40
|
+
# :debug => true,
|
41
|
+
# "USERNAME" => "circl_user",
|
42
|
+
# "PASSWORD" => "circl_pass",
|
43
|
+
# "URL" => "https://www.circl.lu/pdns/query"
|
44
|
+
# }
|
45
|
+
#
|
46
|
+
# PassiveDNS::Provider::CIRCL.new(options)
|
47
|
+
#
|
48
|
+
def initialize(options={})
|
49
|
+
@debug = options[:debug] || false
|
50
|
+
@username = options["USERNAME"]
|
51
|
+
@password = options["PASSWORD"]
|
52
|
+
@auth_token = options["AUTH_TOKEN"]
|
53
|
+
@url = options["URL"] || "https://www.circl.lu/pdns/query"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Takes a label (either a domain or an IP address) and returns
|
57
|
+
# 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}")
|
70
|
+
if @username
|
71
|
+
request.basic_auth(@username, @password)
|
72
|
+
end
|
73
|
+
if @auth_token
|
74
|
+
request.add_field("Authorization", @auth_token)
|
75
|
+
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
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# 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 = []
|
95
|
+
# need to remove the json_class tag or the parser will crap itself trying to find a class to align it to
|
96
|
+
page.split(/\n/).each do |line|
|
97
|
+
row = JSON.parse(line)
|
98
|
+
res << PDNSResult.new(self.class.name,response_time,
|
99
|
+
row['rrname'], row['rdata'], row['rrtype'], 0,
|
100
|
+
row['time_first'], row['time_last'], row['count'])
|
101
|
+
end
|
102
|
+
res
|
103
|
+
rescue Exception => e
|
104
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
105
|
+
raise e
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
CIRCL = PassiveDNS::Provider::Circl
|
110
|
+
end
|
111
|
+
end
|