passivedns-client 2.1.7 → 2.1.13

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 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}"