Class: DNSTraverse::Referral

Inherits:
Object
  • Object
show all
Includes:
MessageUtility
Defined in:
lib/dnstraverse/referral.rb

Constant Summary collapse

EMPTY_ARRAY =
[].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageUtility

msg_additional?, msg_additional_ips?, msg_answers?, msg_authority, msg_cacheable, msg_comment, msg_follow_cnames, msg_nodata?, msg_validate

Constructor Details

#initialize(args) ⇒ Referral

Referral object represents a particular referral to a specified server with given qname, qclass and qtype.

roots can be passed in, which will be used to populate root hints in to the infocache, which if not passed in will be automatically created

server can be nil which is a special case and causes all the roots to be added as child referrals (uses infocache to lookup roots)

if the server’s IP address(es) are known, they are passed in as serverips otherwise, we will resolve the serverips

referral_resolution should be set to false. children that are a result of a resolution of a referral that didn’t have glue records will have this set to true so that you can distringuish this detail



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/dnstraverse/referral.rb', line 89

def initialize(args)
  @status = args[:status] || :normal
  @resolver = args[:resolver] # Dnsruby::Resolver object
  @qname = args[:qname]
  @qclass = args[:qclass] || :IN
  @qtype = args[:qtype] || :A
  @nsatype = args[:nsatype] || :A
  @infocache = args[:infocache] || DNSTraverse::InfoCache.new
  @roots = args[:roots]
  @resolves = nil # Array of referral objects for resolving phase
  @refid = args[:refid] || '' # node identifier, e.g. 1.2.1
  @refkey = args[:refkey] || '' # node key, e.g. 3.4.3 (maximums)
  @server = args[:server] || nil # nil for the root-root server
  @serverips = args[:serverips] || nil
  @responses = Hash.new # responses/exception for each IP in @serverips
  @children = Hash.new # Array of child Referral objects keyed by IP
  @bailiwick = args[:bailiwick] || nil
  @secure = args[:secure] || true # ensure bailiwick checks
  @parent = args[:parent] || nil # Parent Referral
  @parent_ip = args[:parent_ip] || nil # Parent Referral IP if applicable
  @maxdepth = args[:maxdepth] || 10 # maximum depth before error
  @decoded_query_cache = args[:decoded_query_cache]
  @referral_resolution = args[:referral_resolution] || false # flag
  @stats = nil # will contain statistics for answers
  @stats_resolve = nil # will contain statistics for our resolve (if applic)
  @serverweights = Hash.new # key is IP
  @warnings = Array.new # warnings will be placed here
  @processed = false # flag for processed? method
  @calculated = false # flag for calculated? method
  raise "Must pass Resolver" unless @resolver
  @infocache.add_hints('', args[:roots]) if args[:roots] # add root hints
  unless @decoded_query_cache then
    dcq_args = { :resolver => @resolver}
    @decoded_query_cache = DNSTraverse::DecodedQueryCache.new(dcq_args)
  end
  if serverips then # we know the server weights - we're not resolving
    for ip in serverips do
      @serverweights[ip] = 1.0 / @serverips.length
    end
  end
  Log.debug { "New Referral object created: " + self.to_s }
end

Instance Attribute Details

#bailiwickObject (readonly)

Returns the value of attribute bailiwick.



31
32
33
# File 'lib/dnstraverse/referral.rb', line 31

def bailiwick
  @bailiwick
end

#childrenObject (readonly)

Returns the value of attribute children.



32
33
34
# File 'lib/dnstraverse/referral.rb', line 32

def children
  @children
end

#decoded_query_cacheObject (readonly)

Returns the value of attribute decoded_query_cache.



33
34
35
# File 'lib/dnstraverse/referral.rb', line 33

def decoded_query_cache
  @decoded_query_cache
end

#infocacheObject (readonly)

Returns the value of attribute infocache.



31
32
33
# File 'lib/dnstraverse/referral.rb', line 31

def infocache
  @infocache
end

#nsatypeObject (readonly)

Returns the value of attribute nsatype.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def nsatype
  @nsatype
end

#parentObject (readonly)

Returns the value of attribute parent.



31
32
33
# File 'lib/dnstraverse/referral.rb', line 31

def parent
  @parent
end

#parent_ipObject (readonly)

Returns the value of attribute parent_ip.



32
33
34
# File 'lib/dnstraverse/referral.rb', line 32

def parent_ip
  @parent_ip
end

#qclassObject (readonly)

Returns the value of attribute qclass.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def qclass
  @qclass
end

#qnameObject (readonly)

Returns the value of attribute qname.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def qname
  @qname
end

#qtypeObject (readonly)

Returns the value of attribute qtype.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def qtype
  @qtype
end

#refidObject (readonly)

Returns the value of attribute refid.



31
32
33
# File 'lib/dnstraverse/referral.rb', line 31

def refid
  @refid
end

#refkeyObject (readonly)

Returns the value of attribute refkey.



31
32
33
# File 'lib/dnstraverse/referral.rb', line 31

def refkey
  @refkey
end

#replaced_byObject

Returns the value of attribute replaced_by.



36
37
38
# File 'lib/dnstraverse/referral.rb', line 36

def replaced_by
  @replaced_by
end

#responsesObject (readonly)

Returns the value of attribute responses.



34
35
36
# File 'lib/dnstraverse/referral.rb', line 34

def responses
  @responses
end

#serverObject (readonly)

Returns the value of attribute server.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def server
  @server
end

#serveripsObject (readonly)

Returns the value of attribute serverips.



30
31
32
# File 'lib/dnstraverse/referral.rb', line 30

def serverips
  @serverips
end

#statsObject (readonly)

Returns the value of attribute stats.



35
36
37
# File 'lib/dnstraverse/referral.rb', line 35

def stats
  @stats
end

#stats_resolveObject (readonly)

Returns the value of attribute stats_resolve.



35
36
37
# File 'lib/dnstraverse/referral.rb', line 35

def stats_resolve
  @stats_resolve
end

#statusObject (readonly)

:normal, :loop, :noglue, :maxdepth



29
30
31
# File 'lib/dnstraverse/referral.rb', line 29

def status
  @status
end

#warningsObject (readonly)

Returns the value of attribute warnings.



32
33
34
# File 'lib/dnstraverse/referral.rb', line 32

def warnings
  @warnings
end

Instance Method Details

#answer_calculateObject



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/dnstraverse/referral.rb', line 303

def answer_calculate
  Log.debug { "Calculating answer: #{self}" }
  @stats = Hash.new
  
  if not @server then
    # special case - rootroot, no actual IPs, just root referrals
    stats_calculate_children(@stats, @children[:rootroot], 1.0)
    @stats.each_pair do |key, data|
      Log.debug { sprintf "Answer: %.2f%% %s\n", data[:prob] * 100, key }
    end
    @calculated = true
    return
  end
  for ip in @serverips do
    serverweight = @serverweights[ip] # set at initialize or at resolve
    if ip =~ /^key:/ then # resolve failed for some reason
      # pull out the statistics on the resolution and copy over
      if @stats_resolve[ip][:prob] != serverweight then # assertion
        $stderr.puts "#{@stats_resolve[ip][:prob]} vs #{serverweight}"
        @stats_resolve[ip].each_pair do |a,b|
          $stderr.puts a
        end
        raise "unexpected probability" 
      end
      if @stats[ip] then
        # the same condition was found on another IP of this referral
        # and we've already added this key before
        # most likely this is an exception
        @stats[ip][:prob]+= @stats_resolve[ip][:prob]
      else
        # copy over the resolve statistics to the final stats
        @stats[ip] = @stats_resolve[ip].dup
      end
      next
    end
    if @children[ip] then
      stats_calculate_children(@stats, @children[ip], serverweight)
    else
      response = @responses[ip]
      prob = serverweight
      if @stats[response.stats_key] then
        # the same condition was found as a result of resolve stage and
        # when we asked the server. most likely this is an exception.
        prob+= @stats[response.stats_key][:prob]
      end
      @stats[response.stats_key] = { :prob => serverweight,
        :response => response, :referral => self }
    end
  end
  @stats.each_pair do |key, data|
    Log.debug { sprintf "Answer: %.2f%% %s\n", data[:prob] * 100, key }
  end
  @calculated = true
end

#calculated?Boolean

Returns:

  • (Boolean)


362
363
364
# File 'lib/dnstraverse/referral.rb', line 362

def calculated?
  return @calculated
end

#cleanup(args = nil) ⇒ Object

clean up the workings



144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/dnstraverse/referral.rb', line 144

def cleanup(args = nil)
  Log.debug { "cleaning: #{self}" }
  @infocache = nil unless args and args[:infocache]
  @cacheable_good = @cacheable_bad = nil unless args and args[:cacheable]
  @starters = @starters_bailiwick = nil unless args and args[:starters]
  @auth_ns = @auth_soa = @auth_other = nil unless args and args[:auth]
  @children = nil unless args and args[:children]
  @resolves = nil unless args and args[:resolves]
  @responses = nil unless args and args[:responses]
  @decoded_query_cache = nil unless args and args[:decoded_query_cache]
  @resolver = nil unless args and args[:resolver]
end

#inside_bailiwick?(name) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
160
161
162
163
164
# File 'lib/dnstraverse/referral.rb', line 157

def inside_bailiwick?(name)
  return true if @bailiwick.nil?
  bwend = ".#{@bailiwick}"
  namestr = name.to_s
  return true if namestr.casecmp(@bailiwick) == 0
  return true if namestr =~ /#{bwend}$/i
  return false
end

#ips_as_arrayObject

ips_as_array will return any IP addresses we know for this referral server



56
57
58
59
60
61
62
63
# File 'lib/dnstraverse/referral.rb', line 56

def ips_as_array
  return EMPTY_ARRAY unless @serverips
  my_ips = []
  for ip in @serverips do
    my_ips << ip unless ip =~ /^key:/
  end
  return my_ips
end

#is_rootroot?Boolean

Returns:

  • (Boolean)


373
374
375
376
377
# File 'lib/dnstraverse/referral.rb', line 373

def is_rootroot?
  # rootroot is the topmost object representing an automatic referral
  # to all the root servers
  @server.nil? ? true : false
end

#loop?Boolean

look out for endless loops e.g. while looking for a.b we get b NS c.d and while looking for c.d we get d NS a.b which would take us back to b NS c.d

Returns:

  • (Boolean)


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/dnstraverse/referral.rb', line 176

def loop?
  return false if @serverips
  parent = @parent
  until parent.nil? do
    if parent.qname.to_s == @qname.to_s and
      parent.qclass.to_s == @qclass.to_s and
      parent.qtype.to_s == @qtype.to_s and
      parent.server == @server and
      parent.serverips.nil?
        return true
    end
    parent = parent.parent
  end
  return false
end

#make_referral(args) ⇒ Object



485
486
487
488
489
490
491
492
493
494
# File 'lib/dnstraverse/referral.rb', line 485

def make_referral(args)
  raise "Must pass new refid" unless args[:refid]
  raise "Must pass new refkey" unless args[:refkey]
  refargs = { :qname => @qname, :qclass => @qclass,
    :qtype => @qtype, :nsatype => @nsatype, :infocache => @infocache,
    :referral_resolution => @referral_resolution,
    :resolver => @resolver, :maxdepth => @maxdepth, :parent => self,
    :decoded_query_cache => @decoded_query_cache }.merge(args)
  return Referral.new(refargs)
end

#make_referrals(args) ⇒ Object

:starters can be @root or our own list



468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/dnstraverse/referral.rb', line 468

def make_referrals(args) # :starters can be @root or our own list
  starters = args[:starters]
  children = Array.new
  child_refid = 1
  for starter in starters do
    refargs = args.merge({
      :server => starter[:name],
      :serverips => starter[:ips],
      :refid => "#{args[:refid]}.#{child_refid}",
      :refkey => "#{args[:refkey]}.#{starters.count}"
    })
    children.push make_referral(refargs)
    child_refid+= 1
  end
  return children
end

#noglue?Boolean

Returns:

  • (Boolean)


166
167
168
169
170
# File 'lib/dnstraverse/referral.rb', line 166

def noglue?
  return false if @serverips
  return false unless inside_bailiwick?(@server)
  return true
end

#process(args) ⇒ Object

process this Referral object:

query each IP in @serverips and create a Response object
return an array of sets of children


382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/dnstraverse/referral.rb', line 382

def process(args)
  raise "This Referral object has already been processed" if processed?
  raise "You need to resolve this Referral object" unless resolved?
  @processed = true
  unless (server) then
    # special case - no server means start from the top with the roots
    process_add_roots(args)
    #return @children.values.flatten
    return [ @children.values.flatten ] # one set
  end
  process_normal(args)
  # return a set of Referral objects that need to be processed
  # this is just using @serverips for ordering the children properly
  # because we numbered them all already
  #return @serverips.map {|ip| @children[ip] }.flatten.select {|x| x.is_a? Referral }
  # use serverips to keep ordering, skip key: entries
  return @serverips.select {|ip| @children[ip] }.map {|ip| @children[ip] } # array of sets of children
end

#process_add_roots(args) ⇒ Object



401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/dnstraverse/referral.rb', line 401

def process_add_roots(args)
  Log.debug { "Special case processing, addding roots as referrals" }
  dot = @refid == '' ? '' : "."
  child_refid = 1
  starters = (@infocache.get_startservers('', @nsatype))[0]
  @children[:rootroot] = Array.new # use 'rootroot' instead of IP address
  for root in starters do
    r = make_referral(:server => root[:name], :serverips => root[:ips],
                      :refid => "#{@refid}#{dot}#{child_refid}",
 :refkey => "#{@refkey}#{dot}#{starters.count}")
    @children[:rootroot].push r
    child_refid+= 1
  end
end

#process_normal(args) ⇒ Object



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
# File 'lib/dnstraverse/referral.rb', line 416

def process_normal(args)
  Log.debug { "process " + self.to_s }
  # two phases in order to calculate number of childsets
  childsets = 0
  for ip in @serverips do
    Log.debug { "Process normal #{ip}" }
    next if ip =~ /^key:/ # resolve failed on something
    m = nil
    # resolves get an extra .0. so strip those out before counting
    current_depth = @refid.split('.').select {|x| x != '0' }.length
    if current_depth >= @maxdepth.to_i then
      Log.debug { "Process normal #{ip} - Maxdepth #{@maxdepth} exceeded" }
      r = DNSTraverse::Response::Maxdepth.new(:qname => @qname,
                                              :qclass => @qclass,
                                              :qtype => @qtype,
                                              :server => @server,
                                              :ip => ip,
                                              :bailiwick => @bailiwick)
    else
      Log.debug { "Process normal #{ip} - making response" }
      r = DNSTraverse::Response.new(:message => m, :qname => @qname,
                                    :qclass => @qclass, :qtype => @qtype,
                                    :bailiwick => @bailiwick,
                                    :infocache => @infocache, :ip => ip,
                                    :server => @server,
                                    :parent_ip => @parent_ip,
                                    :decoded_query_cache => @decoded_query_cache)
      Log.debug { "Process normal #{ip} - done making response" }
    end
    @responses[ip] = r
    if r.status == :restart or r.status == :referral then
      childsets+= 1
    end
  end
  childset = 0
  @responses.each_pair do |ip, r|
    if r.status == :restart or r.status == :referral then
      childset+= 1
      Log.debug { "Process normal #{ip} - making referrals (childset #{childset})" }
      refid =  childsets == 1 ? @refid :  "#{@refid}.#{childset}"
      refkey = childsets == 1 ? @refkey : "#{@refkey}.#{childsets}"
      @children[ip] = make_referrals(:qname => r.endname,
                                     :starters => r.starters,
                                     :bailiwick => r.starters_bailiwick,
                                     :infocache => r.infocache,
                                     :refid => refid, :refkey => refkey,
                                     :parent_ip => ip)
      Log.debug { "Process normal #{ip} - done making referrals" }
    end
  end
end

#processed?Boolean

Returns:

  • (Boolean)


358
359
360
# File 'lib/dnstraverse/referral.rb', line 358

def processed?
  return @processed
end

#referral_resolution?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/dnstraverse/referral.rb', line 70

def referral_resolution?
  return @referral_resolution ? true : false
end

#replace_child(before, after) ⇒ Object



496
497
498
499
500
501
502
503
504
# File 'lib/dnstraverse/referral.rb', line 496

def replace_child(before, after)
  before.replaced_by = after
  @children.each_key do | ip |
    @children[ip].map! { |c| c.equal?(before) ? after : c }
  end
  if @resolves then
    @resolves.map! { |c| c.equal?(before) ? after : c }
  end
end

#resolve(*args) ⇒ Object

resolve server to serverips, return list of Referral objects to process



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/dnstraverse/referral.rb', line 193

def resolve(*args)
  raise "This Referral object has already been resolved" if resolved?
  if noglue? then
    # foo.net IN NS ns.foo.net - no IP cached & no glue = failure
    Log.debug { "Resolve: #{@server} with a bailiwick referral " +
                " of #{bailiwick} - no glue record provided" }
    @status = :noglue
    return EMPTY_ARRAY
  end
  if loop? then
    # b IN NS c.d, d IN NS a.b
    Log.debug { "Resolve: Loop reached at server #{server}" }
    @status = :loop
    return EMPTY_ARRAY
  end
  # resolves get an extra .0. so strip those out before counting
  current_depth = @refid.split('.').select {|x| x != '0' }.length
  if current_depth >= @maxdepth.to_i then
    Log.debug { "Resolve: Maxdepth #{@maxdepth} exceeded" }
    @status = :maxdepth
    return EMPTY_ARRAY
  end
  child_refid = 1
  starters, newbailiwick = @infocache.get_startservers(@server)
  Log.debug { "Resolving #{@server} type #{@nsatype} " }
  for starter in starters do
    r = make_referral(:server => starter[:name],
                      :serverips => starter[:ips],
                      :referral_resolution => true,
                      :qname => @server, :qclass => 'IN',
                      :qtype => @nsatype,
                      :bailiwick => newbailiwick,
                      :refid => "#{@refid}.0.#{child_refid}",
 :refkey => "#{@refkey}.0.#{starters.count}")
     (@resolves||= []) << r
    child_refid+= 1
  end
  # return a set of Referral objects that need to be processed
  return @resolves
end

#resolve_calculateObject



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/dnstraverse/referral.rb', line 234

def resolve_calculate
  Log.debug { "Calculating resolution: #{self}" }
  # create stats_resolve containing all the statistics of the resolution
  @stats_resolve = Hash.new
  case @status
  when :noglue # in-bailiwick referral without glue
    r = DNSTraverse::Response::NoGlue.new(:qname => @qname,
                                          :qclass => @qclass,
                                          :qtype => @qtype,
                                          :server => @server,
                                          :ip => @parent_ip,
                                          :bailiwick => @bailiwick)
    @stats_resolve[r.stats_key] = { :prob => 1.0, :response => r,
      :referral => self }
  when :loop # endless loop, e.g. b. NS c.d, d NS a.b
    r = DNSTraverse::Response::Loop.new(:qname => @qname,
                                        :qclass => @qclass,
                                        :qtype => @qtype,
                                        :server => @server,
                                        :ip => @parent_ip,
                                        :bailiwick => @bailiwick)
    @stats_resolve[r.stats_key] = { :prob => 1.0, :response => r,
      :referral => self }
  when :maxdepth # max depth exceeded whilst resolving
    r = DNSTraverse::Response::Maxdepth.new(:qname => @qname,
                                            :qclass => @qclass,
                                            :qtype => @qtype)
    @stats_resolve[r.stats_key] = { :prob => 1.0, :response => r,
      :referral => self }
  else
    # normal resolve - combine children's statistics in to @stats_resolve
    stats_calculate_children(@stats_resolve, @resolves, 1.0)
  end
  # now use this data to work out %age of each IP address returned
  @serverweights = Hash.new
  @stats_resolve.each_pair do |key, data|
    # key = IP or key:blah, data is hash containing :prob, etc.
    if data[:response].status == :answered then # RR records
      # there were some answers - so add the probabilities in
      answers = data[:response].answers # weight RRs evenly
      for rr in answers do
        @serverweights[rr.address.to_s]||= 0
        @serverweights[rr.address.to_s]+= data[:prob] / answers.length
      end
    else
      # there were no answers - use the special key and record probabilities
      @serverweights[key]||= 0
      @serverweights[key]+= data[:prob]
    end
  end
  @serverips = @serverweights.keys
  Log.debug { "Calculating resolution (answer): #{@serverips.join(',')}" }
end

#resolved?Boolean

Returns:

  • (Boolean)


366
367
368
369
370
371
# File 'lib/dnstraverse/referral.rb', line 366

def resolved?
  # root-root is always resolved, otherwise check we have IP addresses
  return true if is_rootroot?
  return false if @serverips.nil?
  return true
end

#showstatsObject



132
133
134
135
136
137
138
139
140
141
# File 'lib/dnstraverse/referral.rb', line 132

def showstats
  s = Hash.new
  ObjectSpace.each_object do |o|
    s[o.class]||= 0
    s[o.class]= s[o.class] + 1
  end
  s.sort {|a,b| a[1] <=> b[1]}.each do | c |
    puts "#{c[1]} #{c[0]}"
  end
end

#stats_calculate_children(stats, children, weight) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/dnstraverse/referral.rb', line 288

def stats_calculate_children(stats, children, weight)
  percent = (1.0 / children.length) * weight
  for child in children do
    child.stats.each_pair do |key, data|
      if not stats[key] then
        # just copy the child's statistics for this key
        stats[key] = data.dup
        stats[key][:prob]*= percent
      else
        stats[key][:prob]+= data[:prob] * percent
      end
    end
  end
end

#stats_display(args) ⇒ Object



506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
# File 'lib/dnstraverse/referral.rb', line 506

def stats_display(args)
  spacing = args[:spacing] || false
  results = args[:results] || true
  prefix = args[:prefix] || ''
  indent = args[:indent] || "#{prefix}            "
  first = true
  @stats.keys.sort!.each do | key |
    data = @stats[key]
    puts if spacing and not first
    first = false
    printf "#{prefix}%5.1f%%: ", data[:prob] * 100
    response = data[:response]
    referral = data[:referral]
    where = "#{referral.server} (#{response.ip})"
    case response.status
    when :exception
      puts "#{response.exception_message} at #{where}"
    when :maxdepth
      puts "Maximum depth exceeded"
    when :noglue
      puts "No glue at #{referral.parent.server} " + 
        "(#{response.ip}) for #{referral.server}"
    when :referral_lame
      puts "Lame referral from #{referral.parent.server} " + 
        "(#{referral.parent_ip}) to #{where}"
    when :loop
      puts "Loop encountered at #{response.server}"
    when :cname_loop
      puts "CNAME loop encountered at #{response.server}"
    when :error
      puts "#{response.error_message} at #{where}"
    when :nodata
      puts "NODATA (for this type) at #{where}"
    when :answered
      puts "Answer from #{where}"
      if results then
        for rr in data[:response].answers do
          puts "#{indent}#{rr}"
        end
      end
    else
      puts "Stopped at #{where})"
      puts "#{indent}#{key}"
    end
    # downcase for symbols doesn't work with ruby 1.8 :-( remove for 1.9
    if response.status != :answered and
     ((response.qname.downcase != @qname.downcase) or
      (response.qclass.to_s.downcase != @qclass.to_s.downcase) or
      (response.qtype.to_s.downcase != @qtype.to_s.downcase)) then
      puts "#{indent}While querying #{response.qname}/" +
      "#{response.qclass}/#{response.qtype}"
    end
  end
end

#summary_statsObject

Returns a SummaryStats object



562
563
564
565
# File 'lib/dnstraverse/referral.rb', line 562

def summary_stats
  return nil unless calculated?
  @summary_stats_object||= DNSTraverse::SummaryStats.new(self)
end

#to_sObject



65
66
67
68
# File 'lib/dnstraverse/referral.rb', line 65

def to_s
  return "#{@refid} [#{@qname}/#{@qclass}/#{@qtype}] server=#{@server} " +
  "server_ips=#{txt_ips()} bailiwick=#{@bailiwick}"
end

#txt_ipsObject



48
49
50
51
52
53
# File 'lib/dnstraverse/referral.rb', line 48

def txt_ips
  return '' unless @serverips
  @serverips.map { |ip|
    ip =~ /^key:/ ? @stats_resolve[ip][:response].to_s : ip
  }.sort.join(',')
end

#txt_ips_verboseObject



40
41
42
43
44
45
46
# File 'lib/dnstraverse/referral.rb', line 40

def txt_ips_verbose
  return '' unless @serverips
  a = @serverips.map do |ip|
    sprintf("%.1f%%=", 100 * @serverweights[ip]).concat(ip =~ /^key:([^:]+(:[^:]*)?)/ ? $1 : ip)
  end
  a.sort.join(',')
end