passivedns-client 2.1.7 → 2.1.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 893747659885f41d56357637504abe671f95f102
4
- data.tar.gz: 6f2a91db26389c0286439a6c5b82ca9dbc535a74
2
+ SHA256:
3
+ metadata.gz: 8c2b55f21b59fb20d9167e1893d86aa500e3d020932d7b6e3fe5f2eed7e3113b
4
+ data.tar.gz: 7a48256ee4739a8a432a4a5f7aff6c7a9d8fcd1e5922b07caaf6d3557ffa5ca5
5
5
  SHA512:
6
- metadata.gz: 825f792a8082db19cf426ca8d87c32245ab0e5a8d9d3ee7e6e1442030a2976549affccc2212e71a53339fdb974bd20b5c31b08df3c23423714168753bb126e6d
7
- data.tar.gz: b2be17572348b7166bd567009653e5023ee1c0a142f78cb37c355fbe0c6ec38c7c7a89d32015b5f7dd6061ef85a3e152b2b8c62182e9af53c185b8076fd38e10
6
+ metadata.gz: e75a301a616818187ba3ea036b2ae39b8b3b562c37115cf4b6d1ece009748838d76477ef58b353f654a81e890c1f5aaa2aeb151b45c23cb5bec692845f52f732
7
+ data.tar.gz: 6a549456ebbc19920f00129ee0371742790f288324ade26441349cd407d9e7f8f42e49ecaac49da3b59ed5ba36267fb925d77cfc33e996d58df4d8284a28f5d2
data/README.md CHANGED
@@ -2,14 +2,10 @@
2
2
 
3
3
  This rubygem queries the following Passive DNS databases:
4
4
 
5
- * BFK.de
6
5
  * CIRCL
7
6
  * DNSDB (FarSight)
8
- * Mnemonic
9
- * PassiveDNS.cn (Qihoo 360 Technology Co.,Ltd)
10
7
  * PassiveTotal
11
8
  * RiskIQ
12
- * TCPIPUtils
13
9
  * VirusTotal
14
10
 
15
11
  Passive DNS is a technique where IP to hostname mappings are made by recording the answers of other people's queries.
@@ -40,16 +36,8 @@ From version 2.0.0 on, all configuration keys for passive DNS providers are in o
40
36
 
41
37
  [dnsdb]
42
38
  APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
43
- [cn360]
44
- API = http://some.web.address.for.their.api
45
- API_ID = a username that is given when you register
46
- API_KEY = a long and random password of sorts that is used along with the page request to generate a per page API key
47
- [tcpiputils]
48
- APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
49
39
  [virustotal]
50
40
  APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
51
- [mnemonic]
52
- APIKEY = 01234567890abcdef01234567890abcdef012345
53
41
  [passivetotal]
54
42
  USERNAME = tom@example.com
55
43
  APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
@@ -66,58 +54,55 @@ CIRCL also can use and authorization token. In that case, you should drop the U
66
54
  AUTH_TOKEN = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
67
55
 
68
56
  ## Getting Access
69
- * 360.cn : http://www.passivedns.cn
70
- * BFK.de : No registration required, but please, please ready their usage policy at http://www.bfk.de/bfk_dnslogger.html
71
57
  * CIRCL : https://www.circl.lu/services/passive-dns/
72
58
  * DNSDB (Farsight Security) : https://api.dnsdb.info/
73
- * Mnemonic : mss .at. mnemonic.no
74
59
  * PassiveTotal : https://www.passivetotal.org
75
60
  * RiskIQ : https://github.com/RiskIQ/python_api/blob/master/LICENSE
76
- * TCPIPUtils : http://www.tcpiputils.com/premium-access
77
61
  * VirusTotal : https://www.virustotal.com
78
62
 
79
63
  ## Usage
80
64
 
81
65
  require 'passivedns/client'
82
66
 
83
- c = PassiveDNS::Client.new(['bfk','dnsdb']) # providers: bfk, tcpiputils, certee, dnsdb, virustotal, passivedns.cn, mnemonic
67
+ c = PassiveDNS::Client.new(['riskiq','dnsdb'])
84
68
  results = c.query("example.com")
85
69
 
86
70
 
87
71
  Or use the included tool...
88
72
 
89
- Usage: bin/pdnstool [-d [3bcdmptv]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] <ip|domain|cidr>
90
- Passive DNS Providers -d3bcdmptv uses all of the available passive dns database
91
- -d3 use 360.cn
92
- -db use BFK.de
93
- -dc use CIRCL
94
- -dd use DNSDB
95
- -dm use Mnemonic
96
- -dp use PassiveTotal
97
- -dr use RiskIQ
98
- -dt use TCPIPUtils
99
- -dv use VirusTotal
100
- -dvt uses VirusTotal and TCPIPUtils (for example)
101
-
102
- Output Formatting
103
- -g link-nodal GDF visualization definition
104
- -z link-nodal graphviz visualization definition
105
- -m link-nodal graphml visualization definition
106
- -c CSV
107
- -x XML
108
- -y YAML
109
- -j JSON
110
- -t ASCII text (default)
111
- -s <sep> specifies a field separator for text output, default is tab
112
-
113
- State and Recusion
114
- -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs.
115
- -r# specifies the levels of recursion to pull. **WARNING** This is quite taxing on the pDNS servers, so use judiciously (never more than 3 or so) or find yourself blocked!
116
- -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)
117
- -l <count> limits the number of records returned per passive dns database queried.
118
-
119
- Getting Help
120
- -v debugging information
73
+ Usage: bin/pdnstool [-d [cdprv]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] [--config <file>] <ip|domain|cidr>
74
+ Passive DNS Providers
75
+ -dcdprv uses all of the available passive dns database
76
+ -dc use CIRCL
77
+ -dd use DNSDB
78
+ -dp use PassiveTotal
79
+ -dr use RiskIQ
80
+ -dv use VirusTotal
81
+ -dvr uses VirusTotal and RiskIQ (for example)
82
+
83
+ Output Formatting
84
+ -g link-nodal GDF visualization definition
85
+ -z link-nodal graphviz visualization definition
86
+ -m link-nodal graphml visualization definition
87
+ -c CSV
88
+ -x XML
89
+ -y YAML
90
+ -j JSON
91
+ -t ASCII text (default)
92
+ -s <sep> specifies a field separator for text output, default is tab
93
+
94
+ State and Recursion
95
+ -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs.
96
+ -r# specifies the levels of recursion to pull. **WARNING** This is quite taxing on the pDNS servers, so use judiciously (never more than 3 or so) or find yourself blocked!
97
+ -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)
98
+ -l <count> limits the number of records returned per passive dns database queried.
99
+
100
+ Specifying a Configuration File
101
+ --config <file> specifies a config file. default: /home/chris/.passivedns-client
102
+
103
+ Getting Help
104
+ -h hello there. This option produces this helpful help information on how to access help.
105
+ -v debugging information
121
106
 
122
107
  ## Writing Your Own Database Adaptor
123
108
 
data/Rakefile CHANGED
File without changes
@@ -92,6 +92,12 @@ module PassiveDNS # :nodoc:
92
92
  end
93
93
  end
94
94
 
95
+ def timeout=(t)
96
+ @pdnsdbs.each do |pdnsdb|
97
+ pdnsdb.timeout = t
98
+ end
99
+ end
100
+
95
101
  # perform the query lookup accross all configured PassiveDNS providers
96
102
  def query(item, limit=nil)
97
103
  threads = []
@@ -58,7 +58,8 @@ module PassiveDNS # :nodoc:
58
58
  [ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
59
59
  [ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
60
60
  [ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ],
61
- [ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ]
61
+ [ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ],
62
+ [ '--config', GetoptLong::REQUIRED_ARGUMENT ]
62
63
  )
63
64
 
64
65
  letter_map = get_letter_map
@@ -74,7 +75,8 @@ module PassiveDNS # :nodoc:
74
75
  :debug => false,
75
76
  :sqlitedb => nil,
76
77
  :limit => nil,
77
- :help => false
78
+ :help => false,
79
+ :configfile => "#{ENV['HOME']}/.passivedns-client"
78
80
  }
79
81
 
80
82
  opts.each do |opt, arg|
@@ -121,6 +123,8 @@ module PassiveDNS # :nodoc:
121
123
  options[:sqlitedb] = arg
122
124
  when '--limit'
123
125
  options[:limit] = arg.to_i
126
+ when '--config'
127
+ options[:configfile] = arg
124
128
  else
125
129
  options[:help] = true
126
130
  end
@@ -129,12 +133,7 @@ module PassiveDNS # :nodoc:
129
133
  ARGV.replace(origARGV)
130
134
 
131
135
  if options[:pdnsdbs].length == 0
132
- options[:pdnsdbs] << "bfk"
133
- end
134
-
135
- if options[:pdnsdbs].index("bfk") and options[:recursedepth] > 1 and options[:wait] < 60
136
- options[:wait] = 60
137
- $stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling"
136
+ options[:pdnsdbs] << "virustotal"
138
137
  end
139
138
 
140
139
  if options[:debug]
@@ -158,13 +157,13 @@ module PassiveDNS # :nodoc:
158
157
  def self.usage(letter_map)
159
158
  databases = letter_map.keys.sort.join("")
160
159
  help_text = ""
161
- help_text << "Usage: #{$0} [-d [#{databases}]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] <ip|domain|cidr>\n"
160
+ help_text << "Usage: #{$0} [-d [#{databases}]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] [--config <file>] <ip|domain|cidr>\n"
162
161
  help_text << "Passive DNS Providers\n"
163
162
  help_text << " -d#{databases} uses all of the available passive dns database\n"
164
163
  letter_map.keys.sort.each do |l|
165
164
  help_text << " -d#{l} use #{letter_map[l][0]}\n"
166
165
  end
167
- help_text << " -dvt uses VirusTotal and TCPIPUtils (for example)\n"
166
+ help_text << " -dvr uses VirusTotal and RiskIQ (for example)\n"
168
167
  help_text << "\n"
169
168
  help_text << "Output Formatting\n"
170
169
  help_text << " -g link-nodal GDF visualization definition\n"
@@ -183,6 +182,9 @@ module PassiveDNS # :nodoc:
183
182
  help_text << " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)\n"
184
183
  help_text << " -l <count> limits the number of records returned per passive dns database queried.\n"
185
184
  help_text << "\n"
185
+ help_text << "Specifying a Configuration File\n"
186
+ help_text << " --config <file> specifies a config file. default: #{ENV['HOME']}/.passivedns-client\n"
187
+ help_text << "\n"
186
188
  help_text << "Getting Help\n"
187
189
  help_text << " -h hello there. This option produces this helpful help information on how to access help.\n"
188
190
  help_text << " -v debugging information\n"
@@ -249,6 +251,7 @@ module PassiveDNS # :nodoc:
249
251
  else
250
252
  state = PassiveDNS::PDNSToolState.new
251
253
  end
254
+ state
252
255
  end
253
256
 
254
257
  # main method, takes command-line arguments and performs the desired queries and outputs
@@ -264,7 +267,7 @@ module PassiveDNS # :nodoc:
264
267
  state = create_state(options[:sqlitedb])
265
268
  state.debug = options[:debug]
266
269
 
267
- pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs])
270
+ pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs], options[:configfile])
268
271
  pdnsclient.debug = options[:debug]
269
272
 
270
273
  if items.length > 0
@@ -47,6 +47,7 @@ module PassiveDNS #:nodoc: don't document this
47
47
  #
48
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"]
@@ -57,10 +58,16 @@ module PassiveDNS #:nodoc: don't document this
57
58
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
58
59
  def lookup(label, limit=nil)
59
60
  $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
60
- Timeout::timeout(240) {
61
+ recs = []
62
+ Timeout::timeout(@timeout) {
61
63
  url = @url+"/"+label
62
64
  $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
63
- url = URI.parse url
65
+ begin
66
+ url = URI.parse url
67
+ rescue URI::InvalidURIError
68
+ $stderr.puts "ERROR: Invalid address: #{url}"
69
+ return recs
70
+ end
64
71
  http = Net::HTTP.new(url.host, url.port)
65
72
  http.use_ssl = (url.scheme == 'https')
66
73
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -74,17 +81,26 @@ module PassiveDNS #:nodoc: don't document this
74
81
  request.add_field("Authorization", @auth_token)
75
82
  end
76
83
  t1 = Time.now
77
- response = http.request(request)
78
- t2 = Time.now
79
- recs = parse_json(response.body, label, t2-t1)
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
80
95
  if limit
81
96
  recs[0,limit]
82
97
  else
83
98
  recs
84
99
  end
85
100
  }
86
- rescue Timeout::Error => e
101
+ rescue Timeout::Error
87
102
  $stderr.puts "#{self.class.name} lookup timed out: #{label}"
103
+ recs
88
104
  end
89
105
 
90
106
  private
@@ -41,6 +41,7 @@ module PassiveDNS #:nodoc: don't document this
41
41
  #
42
42
  def initialize(options={})
43
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
47
  end
@@ -49,7 +50,7 @@ module PassiveDNS #:nodoc: don't document this
49
50
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
50
51
  def lookup(label, limit=nil)
51
52
  $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
52
- Timeout::timeout(240) {
53
+ Timeout::timeout(@timeout) {
53
54
  url = nil
54
55
  if label =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/
55
56
  label = label.gsub(/\//,',')
@@ -76,7 +77,7 @@ module PassiveDNS #:nodoc: don't document this
76
77
  $stderr.puts response.body if @debug
77
78
  parse_json(response.body,t2-t1)
78
79
  }
79
- rescue Timeout::Error => e
80
+ rescue Timeout::Error
80
81
  $stderr.puts "#{self.class.name} lookup timed out: #{label}"
81
82
  end
82
83
 
@@ -54,6 +54,7 @@ module PassiveDNS #:nodoc: don't document this
54
54
  #
55
55
  def initialize(options={})
56
56
  @debug = options[:debug] || false
57
+ @timeout = options[:timeout] || 20
57
58
  @username = options["USERNAME"] || raise("#{self.class.name} requires a USERNAME")
58
59
  @apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY")
59
60
  @url = options["URL"] || "https://api.passivetotal.org/v2/dns/passive"
@@ -63,7 +64,7 @@ module PassiveDNS #:nodoc: don't document this
63
64
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
64
65
  def lookup(label, limit=nil)
65
66
  $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
66
- Timeout::timeout(240) {
67
+ Timeout::timeout(@timeout) {
67
68
  url = @url+"?query=#{label}"
68
69
  $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
69
70
  url = URI.parse url
@@ -85,7 +86,7 @@ module PassiveDNS #:nodoc: don't document this
85
86
  recs
86
87
  end
87
88
  }
88
- rescue Timeout::Error => e
89
+ rescue Timeout::Error
89
90
  $stderr.puts "#{self.class.name} lookup timed out: #{label}"
90
91
  end
91
92
 
@@ -93,8 +94,12 @@ module PassiveDNS #:nodoc: don't document this
93
94
 
94
95
  # parses the response of passivetotals's JSON reply to generate an array of PDNSResult
95
96
  def parse_json(page,query,response_time=0)
96
- res = []
97
+ res = []
97
98
  data = JSON.parse(page)
99
+ pp data
100
+ if data['message']
101
+ raise "#{self.class.name} Error: #{data['message']}"
102
+ end
98
103
  query = data['queryValue']
99
104
  if data['results']
100
105
  data['results'].each do |row|
@@ -46,10 +46,11 @@ module PassiveDNS #:nodoc: don't document this
46
46
  #
47
47
  def initialize(options={})
48
48
  @debug = options[:debug] || false
49
+ @timeout = options[:timeout] || 20
49
50
  @token = options["API_TOKEN"] || raise("#{self.class.name} requires an API_TOKEN")
50
51
  @privkey = options["API_PRIVATE_KEY"] || raise("#{self.class.name} requires an API_PRIVATE_KEY")
51
- @server = options["API_SERVER"] || "ws.riskiq.net"
52
52
  @version = options["API_VERSION"] || "v1"
53
+ @server = options["API_SERVER"] || api_settings[@version][:server]
53
54
  @url = "https://#{@server}/#{@version}"
54
55
  end
55
56
 
@@ -57,7 +58,7 @@ module PassiveDNS #:nodoc: don't document this
57
58
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
58
59
  def lookup(label, limit=nil)
59
60
  $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
60
- Timeout::timeout(240) {
61
+ Timeout::timeout(@timeout) {
61
62
  url = nil
62
63
  params = {"rrType" => "", "maxResults" => limit || 1000}
63
64
 
@@ -65,8 +66,10 @@ module PassiveDNS #:nodoc: don't document this
65
66
  url = @url+"/dns/data"
66
67
  params["ip"] = label
67
68
  else
68
- url = @url+"/dns/name"
69
- params["name"] = label
69
+ resource = api_settings[@version][:resource]
70
+ param = api_settings[@version][:param]
71
+ url = @url+"/dns/#{resource}"
72
+ params[param] = label
70
73
  end
71
74
  url << "?"
72
75
  params.each do |k,v|
@@ -95,16 +98,29 @@ module PassiveDNS #:nodoc: don't document this
95
98
  recs
96
99
  end
97
100
  }
98
- rescue Timeout::Error => e
101
+ rescue Timeout::Error
99
102
  $stderr.puts "#{self.class.name} lookup timed out: #{label}"
100
103
  end
101
104
 
102
105
  private
103
106
 
107
+ def api_settings
108
+ @api_settings ||= {
109
+ 'v1' => { server: "ws.riskiq.net", resource: 'name', param: 'name' },
110
+ 'v2' => { server: "api.passivetotal.org", resource: 'passive', param: 'query' }
111
+ }
112
+ end
113
+
104
114
  # parses the response of riskiq's JSON reply to generate an array of PDNSResult
105
115
  def parse_json(page,query,response_time=0)
106
- res = []
116
+ res = []
107
117
  data = JSON.parse(page)
118
+ if data['message']
119
+ if data['message'] =~ /quota_exceeded/
120
+ $stderr.puts "ERROR: quota exceeded."
121
+ return res
122
+ end
123
+ end
108
124
  if data['records']
109
125
  data['records'].each do |record|
110
126
  name = record['name'].gsub!(/\.$/,'')
@@ -41,6 +41,7 @@ module PassiveDNS #:nodoc: don't document this
41
41
  #
42
42
  def initialize(options={})
43
43
  @debug = options[:debug] || false
44
+ @timeout = options[:timeout] || 20
44
45
  @apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY. See README.md")
45
46
  @url = options["URL"] || "https://www.virustotal.com/vtapi/v2/"
46
47
  end
@@ -49,7 +50,7 @@ module PassiveDNS #:nodoc: don't document this
49
50
  # an array of PassiveDNS::PDNSResult instances with the answers to the query
50
51
  def lookup(label, limit=nil)
51
52
  $stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
52
- Timeout::timeout(240) {
53
+ Timeout::timeout(@timeout) {
53
54
  url = nil
54
55
  if label =~ /^[\d\.]+$/
55
56
  url = "#{@url}ip-address/report?ip=#{label}&apikey=#{@apikey}"
@@ -57,7 +58,12 @@ module PassiveDNS #:nodoc: don't document this
57
58
  url = "#{@url}domain/report?domain=#{label}&apikey=#{@apikey}"
58
59
  end
59
60
  $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
60
- url = URI.parse url
61
+ begin
62
+ url = URI.parse url
63
+ rescue URI::InvalidURIError
64
+ $stderr.puts "ERROR: Invalid address: #{url}"
65
+ return
66
+ end
61
67
  http = Net::HTTP.new(url.host, url.port)
62
68
  http.use_ssl = (url.scheme == 'https')
63
69
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -66,6 +72,10 @@ module PassiveDNS #:nodoc: don't document this
66
72
  request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
67
73
  t1 = Time.now
68
74
  response = http.request(request)
75
+ if response.code.to_i == 204
76
+ $stderr.puts "DEBUG: empty response from server" if @debug
77
+ return
78
+ end
69
79
  t2 = Time.now
70
80
  recs = parse_json(response.body, label, t2-t1)
71
81
  if limit
@@ -74,7 +84,7 @@ module PassiveDNS #:nodoc: don't document this
74
84
  recs
75
85
  end
76
86
  }
77
- rescue Timeout::Error => e
87
+ rescue Timeout::Error
78
88
  $stderr.puts "#{self.class.name} lookup timed out: #{label}"
79
89
  end
80
90
 
@@ -83,6 +93,7 @@ module PassiveDNS #:nodoc: don't document this
83
93
  # parses the response of virustotal's JSON reply to generate an array of PDNSResult
84
94
  def parse_json(page,query,response_time=0)
85
95
  res = []
96
+ return res if !page
86
97
  data = JSON.parse(page)
87
98
  if data['resolutions']
88
99
  data['resolutions'].each do |row|
@@ -94,6 +105,9 @@ module PassiveDNS #:nodoc: don't document this
94
105
  end
95
106
  end
96
107
  end
108
+ if data['response_code'] == 0
109
+ $stderr.puts "DEBUG: server returned error: #{data['verbose_msg']}" if @debug
110
+ end
97
111
  res
98
112
  rescue Exception => e
99
113
  $stderr.puts "VirusTotal Exception: #{e}"