passivedns-client 2.1.6 → 2.1.7

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.
@@ -7,7 +7,7 @@ module PassiveDNS #:nodoc: don't document this
7
7
  # The Provider module contains all the Passive DNS provider client code
8
8
  module Provider
9
9
  # Queries VirusTotal's passive DNS database
10
- class VirusTotal < PassiveDB
10
+ class VirusTotal < PassiveDB
11
11
  # Sets the modules self-reported name to "VirusTotal"
12
12
  def self.name
13
13
  "VirusTotal"
@@ -39,7 +39,7 @@ module PassiveDNS #:nodoc: don't document this
39
39
  #
40
40
  # PassiveDNS::Provider::VirusTotal.new(options)
41
41
  #
42
- def initialize(options={})
42
+ def initialize(options={})
43
43
  @debug = options[:debug] || false
44
44
  @apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY. See README.md")
45
45
  @url = options["URL"] || "https://www.virustotal.com/vtapi/v2/"
@@ -47,59 +47,59 @@ module PassiveDNS #:nodoc: don't document this
47
47
 
48
48
  # Takes a label (either a domain or an IP address) and returns
49
49
  # 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\.]+$/
55
- url = "#{@url}ip-address/report?ip=#{label}&apikey=#{@apikey}"
56
- else
57
- url = "#{@url}domain/report?domain=#{label}&apikey=#{@apikey}"
58
- end
59
- $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
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
65
- request = Net::HTTP::Get.new(url.path+"?"+url.query)
66
- request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
67
- t1 = Time.now
68
- response = http.request(request)
69
- t2 = Time.now
70
- recs = parse_json(response.body, label, t2-t1)
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\.]+$/
55
+ url = "#{@url}ip-address/report?ip=#{label}&apikey=#{@apikey}"
56
+ else
57
+ url = "#{@url}domain/report?domain=#{label}&apikey=#{@apikey}"
58
+ end
59
+ $stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
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
65
+ request = Net::HTTP::Get.new(url.path+"?"+url.query)
66
+ request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
67
+ t1 = Time.now
68
+ response = http.request(request)
69
+ t2 = Time.now
70
+ recs = parse_json(response.body, label, t2-t1)
71
71
  if limit
72
72
  recs[0,limit]
73
73
  else
74
74
  recs
75
75
  end
76
- }
77
- rescue Timeout::Error => e
78
- $stderr.puts "#{self.class.name} lookup timed out: #{label}"
79
- end
76
+ }
77
+ rescue Timeout::Error => e
78
+ $stderr.puts "#{self.class.name} lookup timed out: #{label}"
79
+ end
80
80
 
81
81
  private
82
82
 
83
83
  # parses the response of virustotal's JSON reply to generate an array of PDNSResult
84
- def parse_json(page,query,response_time=0)
85
- res = []
86
- data = JSON.parse(page)
87
- if data['resolutions']
88
- data['resolutions'].each do |row|
84
+ def parse_json(page,query,response_time=0)
85
+ res = []
86
+ data = JSON.parse(page)
87
+ if data['resolutions']
88
+ data['resolutions'].each do |row|
89
89
  lastseen = Time.parse(row['last_resolved']+" +0000")
90
- if row['ip_address']
91
- res << PDNSResult.new(self.class.name,response_time,query,row['ip_address'],'A',nil,nil,lastseen)
92
- elsif row['hostname']
93
- res << PDNSResult.new(self.class.name,response_time,row['hostname'],query,'A',nil,nil,lastseen)
94
- end
95
- end
96
- end
97
- res
98
- rescue Exception => e
99
- $stderr.puts "VirusTotal Exception: #{e}"
100
- raise e
101
- end
90
+ if row['ip_address']
91
+ res << PDNSResult.new(self.class.name,response_time,query,row['ip_address'],'A',nil,nil,lastseen, 'yellow')
92
+ elsif row['hostname']
93
+ res << PDNSResult.new(self.class.name,response_time,row['hostname'],query,'A',nil,nil,lastseen, 'yellow')
94
+ end
95
+ end
96
+ end
97
+ res
98
+ rescue Exception => e
99
+ $stderr.puts "VirusTotal Exception: #{e}"
100
+ raise e
101
+ end
102
102
 
103
- end
103
+ end
104
104
  end
105
- end
105
+ end
@@ -4,297 +4,297 @@ require 'structformatter'
4
4
 
5
5
  module PassiveDNS # :nodoc:
6
6
  # struct to hold pending entries for query
7
- class PDNSQueueEntry < Struct.new(:query, :state, :level); end
7
+ class PDNSQueueEntry < Struct.new(:query, :state, :level); end
8
8
 
9
9
  # holds state in memory of the queue to be queried, records returned, and the level of recursion
10
- class PDNSToolState
10
+ class PDNSToolState
11
11
  # :debug enables verbose logging to standard output
12
- attr_accessor :debug
12
+ attr_accessor :debug
13
13
  # :level is the recursion depth
14
- attr_reader :level
14
+ attr_reader :level
15
15
 
16
16
  # creates a new, blank PDNSToolState instance
17
- def initialize
18
- @queue = []
19
- @recs = []
20
- @level = 0
21
- end
17
+ def initialize
18
+ @queue = []
19
+ @recs = []
20
+ @level = 0
21
+ end
22
22
 
23
23
  # returns the next record
24
- def next_result
25
- @recs.each do |rec|
26
- yield rec
27
- end
28
- end
24
+ def next_result
25
+ @recs.each do |rec|
26
+ yield rec
27
+ end
28
+ end
29
29
 
30
30
  # adds the record to the list of records received and tries to add the answer and query back to the queue for future query
31
- def add_result(res)
32
- @recs << res
33
- add_query(res.answer,'pending')
34
- add_query(res.query,'pending')
35
- end
31
+ def add_result(res)
32
+ @recs << res
33
+ add_query(res.answer,'pending')
34
+ add_query(res.query,'pending')
35
+ end
36
36
 
37
37
  # sets the state of a given query
38
- def update_query(query,state)
39
- @queue.each do |q|
40
- if q.query == query
41
- puts "update_query: #{query} (#{q.state}) -> (#{state})" if @debug
42
- q.state = state
43
- break
44
- end
45
- end
46
- end
38
+ def update_query(query,state)
39
+ @queue.each do |q|
40
+ if q.query == query
41
+ puts "update_query: #{query} (#{q.state}) -> (#{state})" if @debug
42
+ q.state = state
43
+ break
44
+ end
45
+ end
46
+ end
47
47
 
48
48
  # returns the state of a provided query
49
- def get_state(query)
50
- @queue.each do |q|
51
- if q.query == query
52
- return q.state
53
- end
54
- end
55
- false
56
- end
49
+ def get_state(query)
50
+ @queue.each do |q|
51
+ if q.query == query
52
+ return q.state
53
+ end
54
+ end
55
+ false
56
+ end
57
57
 
58
58
  # adding a query to the queue of things to be queried, but only if the query isn't already queued or answered
59
- def add_query(query,state,level=@level+1)
60
- if query =~ /^\d+ \w+\./
61
- query = query.split(/ /,2)[1]
62
- end
63
- return if get_state(query)
64
- puts "Adding query: #{query}, #{state}, #{level}" if @debug
65
- @queue << PDNSQueueEntry.new(query,state,level)
66
- end
59
+ def add_query(query,state,level=@level+1)
60
+ if query =~ /^\d+ \w+\./
61
+ query = query.split(/ /,2)[1]
62
+ end
63
+ return if get_state(query)
64
+ puts "Adding query: #{query}, #{state}, #{level}" if @debug
65
+ @queue << PDNSQueueEntry.new(query,state,level)
66
+ end
67
67
 
68
68
  # returns each query waiting on the queue
69
- def each_query(max_level=20)
70
- @queue.each do |q|
71
- if q.state == 'pending' or q.state == 'failed'
72
- @level = q.level
73
- q.state = 'queried'
74
- if q.level < max_level
75
- yield q.query
76
- end
77
- end
78
- end
79
- end
69
+ def each_query(max_level=20)
70
+ @queue.each do |q|
71
+ if q.state == 'pending' or q.state == 'failed'
72
+ @level = q.level
73
+ q.state = 'queried'
74
+ if q.level < max_level
75
+ yield q.query
76
+ end
77
+ end
78
+ end
79
+ end
80
80
 
81
81
  # transforms a set of results into GDF syntax
82
- def to_gdf
83
- output = "nodedef> name,description VARCHAR(12),color,style\n"
84
- # IP "$node2,,white,1"
85
- # domain "$node2,,gray,2"
86
- # Struct.new(:query, :answer, :rrtype, :ttl, :firstseen, :lastseen)
87
- colors = {"MX" => "green", "A" => "blue", "CNAME" => "pink", "NS" => "red", "SOA" => "white", "PTR" => "purple", "TXT" => "brown"}
88
- nodes = {}
89
- edges = {}
90
- next_result do |i|
91
- if i
92
- nodes[i.query + ",,gray,2"] = true
93
- if i.answer =~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ then
94
- nodes[i.answer + ",,white,1"] = true
95
- else
96
- nodes[i.answer + ",,gray,2"] = true
97
- end
98
- color = colors[i.rrtype]
99
- color ||= "blue"
100
- edges[i.query + "," + i.answer + "," + color] = true
101
- end
102
- end
103
- nodes.each do |i,j|
104
- output += i+"\n"
105
- end
106
- output += "edgedef> node1,node2,color\n"
107
- edges.each do |i,j|
108
- output += i+"\n"
109
- end
110
- output
111
- end
82
+ def to_gdf
83
+ output = "nodedef> name,description VARCHAR(12),color,style\n"
84
+ # IP "$node2,,white,1"
85
+ # domain "$node2,,gray,2"
86
+ # Struct.new(:query, :answer, :rrtype, :ttl, :firstseen, :lastseen)
87
+ colors = {"MX" => "green", "A" => "blue", "CNAME" => "pink", "NS" => "red", "SOA" => "white", "PTR" => "purple", "TXT" => "brown"}
88
+ nodes = {}
89
+ edges = {}
90
+ next_result do |i|
91
+ if i
92
+ nodes[i.query + ",,gray,2"] = true
93
+ if i.answer =~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ then
94
+ nodes[i.answer + ",,white,1"] = true
95
+ else
96
+ nodes[i.answer + ",,gray,2"] = true
97
+ end
98
+ color = colors[i.rrtype]
99
+ color ||= "blue"
100
+ edges[i.query + "," + i.answer + "," + color] = true
101
+ end
102
+ end
103
+ nodes.each do |i,j|
104
+ output += i+"\n"
105
+ end
106
+ output += "edgedef> node1,node2,color\n"
107
+ edges.each do |i,j|
108
+ output += i+"\n"
109
+ end
110
+ output
111
+ end
112
112
 
113
113
  # transforms a set of results into graphviz syntax
114
- def to_graphviz
115
- colors = {"MX" => "green", "A" => "blue", "CNAME" => "pink", "NS" => "red", "SOA" => "white", "PTR" => "purple", "TXT" => "brown"}
116
- output = "graph pdns {\n"
117
- nodes = {}
118
- next_result do |l|
119
- if l
120
- unless nodes[l.query]
121
- output += " \"#{l.query}\" [shape=ellipse, style=filled, color=gray];\n"
122
- if l.answer =~ /^\d{3}\.\d{3}\.\d{3}\.\d{3}$/
123
- output += " \"#{l.answer}\" [shape=box, style=filled, color=white];\n"
124
- else
125
- output += " \"#{l.answer}\" [shape=ellipse, style=filled, color=gray];\n"
126
- end
127
- nodes[l.query] = true
128
- end
129
- output += " \"#{l.query}\" -- \"#{l.answer}\" [color=#{colors[l.rrtype]}];\n"
130
- end
131
- end
132
- output += "}\n"
133
- end
114
+ def to_graphviz
115
+ colors = {"MX" => "green", "A" => "blue", "CNAME" => "pink", "NS" => "red", "SOA" => "white", "PTR" => "purple", "TXT" => "brown"}
116
+ output = "graph pdns {\n"
117
+ nodes = {}
118
+ next_result do |l|
119
+ if l
120
+ unless nodes[l.query]
121
+ output += " \"#{l.query}\" [shape=ellipse, style=filled, color=gray];\n"
122
+ if l.answer =~ /^\d{3}\.\d{3}\.\d{3}\.\d{3}$/
123
+ output += " \"#{l.answer}\" [shape=box, style=filled, color=white];\n"
124
+ else
125
+ output += " \"#{l.answer}\" [shape=ellipse, style=filled, color=gray];\n"
126
+ end
127
+ nodes[l.query] = true
128
+ end
129
+ output += " \"#{l.query}\" -- \"#{l.answer}\" [color=#{colors[l.rrtype]}];\n"
130
+ end
131
+ end
132
+ output += "}\n"
133
+ end
134
134
 
135
135
  # transforms a set of results into graphml syntax
136
- def to_graphml
137
- output = '<?xml version="1.0" encoding="UTF-8"?>
136
+ def to_graphml
137
+ output = '<?xml version="1.0" encoding="UTF-8"?>
138
138
  <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
139
139
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
140
140
  xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
141
141
  http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
142
142
  <graph id="G" edgedefault="directed">
143
143
  '
144
- nodes = {}
145
- edges = {}
146
- next_result do |r|
147
- if r
148
- output += " <node id='#{r.query}'/>\n" unless nodes["#{r.query}"]
149
- nodes[r.query] = true
150
- output += " <node id='#{r.answer}'/>\n" unless nodes["#{r.answer}"]
151
- nodes[r.answer] = true
152
- output += " <edge source='#{r.query}' target='#{r.answer}'/>\n" unless edges["#{r.query}|#{r.answer}"]
153
- end
154
- end
155
- output += '</graph></graphml>'+"\n"
156
- end
144
+ nodes = {}
145
+ edges = {}
146
+ next_result do |r|
147
+ if r
148
+ output += " <node id='#{r.query}'/>\n" unless nodes["#{r.query}"]
149
+ nodes[r.query] = true
150
+ output += " <node id='#{r.answer}'/>\n" unless nodes["#{r.answer}"]
151
+ nodes[r.answer] = true
152
+ output += " <edge source='#{r.query}' target='#{r.answer}'/>\n" unless edges["#{r.query}|#{r.answer}"]
153
+ end
154
+ end
155
+ output += '</graph></graphml>'+"\n"
156
+ end
157
157
 
158
158
  # transforms a set of results into XML
159
- def to_xml
160
- output = '<?xml version="1.0" encoding="UTF-8" ?>'+"\n"
161
- output += "<report>\n"
162
- output += " <results>\n"
163
- next_result do |rec|
164
- output += " "+rec.to_xml+"\n"
165
- end
166
- output += " </results>\n"
167
- output += "</report>\n"
168
- end
159
+ def to_xml
160
+ output = '<?xml version="1.0" encoding="UTF-8" ?>'+"\n"
161
+ output += "<report>\n"
162
+ output += " <results>\n"
163
+ next_result do |rec|
164
+ output += " "+rec.to_xml+"\n"
165
+ end
166
+ output += " </results>\n"
167
+ output += "</report>\n"
168
+ end
169
169
 
170
170
  # transforms a set of results into YAML
171
- def to_yaml
172
- output = ""
173
- next_result do |rec|
174
- output += rec.to_yaml+"\n"
175
- end
176
- output
177
- end
171
+ def to_yaml
172
+ output = ""
173
+ next_result do |rec|
174
+ output += rec.to_yaml+"\n"
175
+ end
176
+ output
177
+ end
178
178
 
179
179
  # transforms a set of results into JSON
180
- def to_json
181
- output = "[\n"
182
- sep = ""
183
- next_result do |rec|
184
- output += sep
185
- output += rec.to_json
186
- sep = ",\n"
187
- end
188
- output += "\n]\n"
189
- end
180
+ def to_json
181
+ output = "[\n"
182
+ sep = ""
183
+ next_result do |rec|
184
+ output += sep
185
+ output += rec.to_json
186
+ sep = ",\n"
187
+ end
188
+ output += "\n]\n"
189
+ end
190
190
 
191
191
  # transforms a set of results into a text string
192
- def to_s(sep="\t")
193
- output = ""
194
- next_result do |rec|
195
- output += rec.to_s(sep)+"\n"
196
- end
197
- output
198
- end
199
- end # class PDNSToolState
192
+ def to_s(sep="\t")
193
+ output = ""
194
+ next_result do |rec|
195
+ output += rec.to_s(sep)+"\n"
196
+ end
197
+ output
198
+ end
199
+ end # class PDNSToolState
200
200
 
201
201
 
202
202
  # creates persistence to the tool state by leveraging SQLite3
203
- class PDNSToolStateDB < PDNSToolState
204
- attr_reader :level
203
+ class PDNSToolStateDB < PDNSToolState
204
+ attr_reader :level
205
205
  # creates an SQLite3-based Passive DNS Client state
206
206
  # only argument is the filename of the sqlite3 database
207
- def initialize(sqlitedb=nil)
208
- puts "PDNSToolState initialize #{sqlitedb}" if @debug
209
- @level = 0
210
- @sqlitedb = sqlitedb
211
- raise "Cannot use this class without a database file" unless @sqlitedb
212
- unless File.exists?(@sqlitedb)
213
- newdb = true
214
- end
215
- @sqlitedbh = SQLite3::Database.new(@sqlitedb)
216
- if newdb
217
- create_tables
218
- end
219
- res = @sqlitedbh.execute("select min(level) from queue where state = 'pending'")
220
- if res
221
- res.each do |row|
222
- @level = row[0].to_i
223
- puts "changed @level = #{@level}" if @debug
224
- end
225
- end
226
- end
207
+ def initialize(sqlitedb=nil)
208
+ puts "PDNSToolState initialize #{sqlitedb}" if @debug
209
+ @level = 0
210
+ @sqlitedb = sqlitedb
211
+ raise "Cannot use this class without a database file" unless @sqlitedb
212
+ unless File.exists?(@sqlitedb)
213
+ newdb = true
214
+ end
215
+ @sqlitedbh = SQLite3::Database.new(@sqlitedb)
216
+ if newdb
217
+ create_tables
218
+ end
219
+ res = @sqlitedbh.execute("select min(level) from queue where state = 'pending'")
220
+ if res
221
+ res.each do |row|
222
+ @level = row[0].to_i
223
+ puts "changed @level = #{@level}" if @debug
224
+ end
225
+ end
226
+ end
227
227
 
228
228
  # creates the sqlite3 tables needed to track the state of this tool as itqueries and recurses
229
- def create_tables
230
- puts "creating tables" if @debug
231
- @sqlitedbh.execute("create table results (query, answer, rrtype, ttl, firstseen, lastseen, ts REAL)")
232
- @sqlitedbh.execute("create table queue (query, state, level INTEGER, ts REAL)")
233
- @sqlitedbh.execute("create index residx on results (ts)")
234
- @sqlitedbh.execute("create unique index queue_unique on queue (query)")
235
- @sqlitedbh.execute("create index queue_level_idx on queue (level)")
236
- @sqlitedbh.execute("create index queue_state_idx on queue (state)")
237
- end
229
+ def create_tables
230
+ puts "creating tables" if @debug
231
+ @sqlitedbh.execute("create table results (query, answer, rrtype, ttl, firstseen, lastseen, ts REAL)")
232
+ @sqlitedbh.execute("create table queue (query, state, level INTEGER, ts REAL)")
233
+ @sqlitedbh.execute("create index residx on results (ts)")
234
+ @sqlitedbh.execute("create unique index queue_unique on queue (query)")
235
+ @sqlitedbh.execute("create index queue_level_idx on queue (level)")
236
+ @sqlitedbh.execute("create index queue_state_idx on queue (state)")
237
+ end
238
238
 
239
239
  # returns the next record
240
- def next_result
241
- rows = @sqlitedbh.execute("select query, answer, rrtype, ttl, firstseen, lastseen from results order by ts")
242
- rows.each do |row|
243
- yield PDNSResult.new(*row)
244
- end
245
- end
240
+ def next_result
241
+ rows = @sqlitedbh.execute("select query, answer, rrtype, ttl, firstseen, lastseen from results order by ts")
242
+ rows.each do |row|
243
+ yield PDNSResult.new(*row)
244
+ end
245
+ end
246
246
 
247
247
  # adds the record to the list of records received and tries to add the answer and query back to the queue for future query
248
- def add_result(res)
249
- puts "adding result: #{res.to_s}" if @debug
250
- curtime = Time.now().to_f
251
- @sqlitedbh.execute("insert into results values ('#{res.query}','#{res.answer}','#{res.rrtype}','#{res.ttl}','#{res.firstseen}','#{res.lastseen}',#{curtime})")
248
+ def add_result(res)
249
+ puts "adding result: #{res.to_s}" if @debug
250
+ curtime = Time.now().to_f
251
+ @sqlitedbh.execute("insert into results values ('#{res.query}','#{res.answer}','#{res.rrtype}','#{res.ttl}','#{res.firstseen}','#{res.lastseen}',#{curtime})")
252
252
 
253
- add_query(res.answer,'pending')
254
- add_query(res.query,'pending')
255
- end
253
+ add_query(res.answer,'pending')
254
+ add_query(res.query,'pending')
255
+ end
256
256
 
257
257
  # adding a query to the queue of things to be queried, but only if the query isn't already queued or answered
258
- def add_query(query,state,level=@level+1)
259
- return if get_state(query)
260
- curtime = Time.now().to_f
261
- begin
262
- puts "add_query(#{query},#{state},level=#{level})" if @debug
263
- @sqlitedbh.execute("insert into queue values ('#{query}','#{state}',#{level},#{curtime})")
264
- rescue
265
- end
266
- end
258
+ def add_query(query,state,level=@level+1)
259
+ return if get_state(query)
260
+ curtime = Time.now().to_f
261
+ begin
262
+ puts "add_query(#{query},#{state},level=#{level})" if @debug
263
+ @sqlitedbh.execute("insert into queue values ('#{query}','#{state}',#{level},#{curtime})")
264
+ rescue
265
+ end
266
+ end
267
267
 
268
268
  # sets the state of a given query
269
- def update_query(query,state)
270
- @sqlitedbh.execute("update queue set state = '#{state}' where query = '#{query}'")
271
- end
269
+ def update_query(query,state)
270
+ @sqlitedbh.execute("update queue set state = '#{state}' where query = '#{query}'")
271
+ end
272
272
 
273
273
  # returns each query waiting on the queue
274
- def get_state(query)
275
- rows = @sqlitedbh.execute("select state from queue where query = '#{query}'")
276
- if rows
277
- rows.each do |row|
278
- return row[0]
279
- end
280
- end
281
- false
282
- end
274
+ def get_state(query)
275
+ rows = @sqlitedbh.execute("select state from queue where query = '#{query}'")
276
+ if rows
277
+ rows.each do |row|
278
+ return row[0]
279
+ end
280
+ end
281
+ false
282
+ end
283
283
 
284
284
  # returns each query waiting on the queue
285
- def each_query(max_level=20)
286
- puts "each_query max_level=#{max_level} curlevel=#{@level}" if @debug
287
- rows = @sqlitedbh.execute("select query, state, level from queue where state = 'failed' or state = 'pending' order by level limit 1")
288
- if rows
289
- rows.each do |row|
290
- query,state,level = row
291
- puts " #{query},#{state},#{level}" if @debug
292
- if level < max_level
293
- update_query(query,'queried')
294
- yield query
295
- end
296
- end
297
- end
298
- end
299
- end # class PDNSToolStateDB
300
- end
285
+ def each_query(max_level=20)
286
+ puts "each_query max_level=#{max_level} curlevel=#{@level}" if @debug
287
+ rows = @sqlitedbh.execute("select query, state, level from queue where state = 'failed' or state = 'pending' order by level limit 1")
288
+ if rows
289
+ rows.each do |row|
290
+ query,state,level = row
291
+ puts " #{query},#{state},#{level}" if @debug
292
+ if level < max_level
293
+ update_query(query,'queried')
294
+ yield query
295
+ end
296
+ end
297
+ end
298
+ end
299
+ end # class PDNSToolStateDB
300
+ end