Class: DNSTraverse::DecodedQuery

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

Constant Summary collapse

NOERROR =
Dnsruby::RCode.NOERROR

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) ⇒ DecodedQuery

Returns a new instance of DecodedQuery.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/dnstraverse/decoded_query.rb', line 36

def initialize(args)
  @message = args[:message] || nil # skip query - use this message/exception
  @qname = args[:qname] # the query name
  @qclass = args[:qclass] # the query class
  @qtype = args[:qtype] # the query type
  @ip = args[:ip] # the nameserver to query (was queried if :message passed)
  @resolver = args[:resolver] # Dnsruby::Resolver / CachingResolver object
  @bailiwick = args[:bailiwick] # the bailiwick in force
  @cacheable_good = Hash.new # in-bailiwick records
  @cacheable_bad = Hash.new # out-of-bailiwick records
  @auth_ns = nil # NS RR records in authority section
  @auth_soa = nil # SOA RR records in authority section
  @auth_other = nil # Other RR records in authority section
  @answers = nil # Answers, if :answered
  @warnings = nil # Warnings if there are any (array)
  query unless @message
  process
  Log.debug { "Query to #{@ip} for #{@qname}/#{@qclass}/#{@qtype} decoded status=#{@status}" }
  return self
end

Instance Attribute Details

#answersObject (readonly)

:answered only



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

def answers
  @answers
end

#auth_nsObject (readonly)

authority info



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

def auth_ns
  @auth_ns
end

#auth_otherObject (readonly)

authority info



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

def auth_other
  @auth_other
end

#auth_soaObject (readonly)

authority info



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

def auth_soa
  @auth_soa
end

#authoritynamesObject (readonly)

auth_ns converted to array of strings



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

def authoritynames
  @authoritynames
end

#bailiwickObject (readonly)

Returns the value of attribute bailiwick.



25
26
27
# File 'lib/dnstraverse/decoded_query.rb', line 25

def bailiwick
  @bailiwick
end

#cacheable_badObject (readonly)

Returns the value of attribute cacheable_bad.



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

def cacheable_bad
  @cacheable_bad
end

#cacheable_goodObject (readonly)

Returns the value of attribute cacheable_good.



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

def cacheable_good
  @cacheable_good
end

#endnameObject (readonly)

Returns the value of attribute endname.



27
28
29
# File 'lib/dnstraverse/decoded_query.rb', line 27

def endname
  @endname
end

#error_messageObject (readonly)

:exception/:error only



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

def error_message
  @error_message
end

#exception_messageObject (readonly)

:exception/:error only



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

def exception_message
  @exception_message
end

#infocacheObject (readonly)

Returns the value of attribute infocache.



25
26
27
# File 'lib/dnstraverse/decoded_query.rb', line 25

def infocache
  @infocache
end

#ipObject (readonly)

Returns the value of attribute ip.



26
27
28
# File 'lib/dnstraverse/decoded_query.rb', line 26

def ip
  @ip
end

#messageObject (readonly)

Returns the value of attribute message.



25
26
27
# File 'lib/dnstraverse/decoded_query.rb', line 25

def message
  @message
end

#qclassObject (readonly)

Returns the value of attribute qclass.



26
27
28
# File 'lib/dnstraverse/decoded_query.rb', line 26

def qclass
  @qclass
end

#qnameObject (readonly)

Returns the value of attribute qname.



26
27
28
# File 'lib/dnstraverse/decoded_query.rb', line 26

def qname
  @qname
end

#qtypeObject (readonly)

Returns the value of attribute qtype.



26
27
28
# File 'lib/dnstraverse/decoded_query.rb', line 26

def qtype
  @qtype
end

#statusObject (readonly)

Returns the value of attribute status.



28
29
30
# File 'lib/dnstraverse/decoded_query.rb', line 28

def status
  @status
end

#warningsObject (readonly)

warnings about this query



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

def warnings
  @warnings
end

Instance Method Details

#inside_bailiwick?(name) ⇒ Boolean

# clean up the workings

def cleanup
  @cacheable_good = @cacheable_bad = nil
  @starters = @starters_bailiwick = nil
  @auth_ns = @auth_soa = @auth_other = nil
end

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
120
# File 'lib/dnstraverse/decoded_query.rb', line 112

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
  Log.debug { "#{namestr} is not inside bailiwick #{@bailiwick}" }
  return false
end

#makequery_messageObject

make a query start with whatever UDP size is configured in resolver fall-back to UDP size 512 if appropriate



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/dnstraverse/decoded_query.rb', line 74

def makequery_message
  my_udp_size = @resolver.udp_size
  message = makequery_with_udpsize(my_udp_size)
  return message if message.is_a? Exception
  return message if my_udp_size == 512
  return message if (message.rcode != Dnsruby::RCode.FORMERR and
                     message.rcode != Dnsruby::RCode.NOTIMP and
                     message.rcode != Dnsruby::RCode.SERVFAIL)
  Log.debug { "Possible failure by nameserver to understand EDNS0 - retry" }
  message_retry = makequery_with_udpsize(512)
  @resolver.udp_size = my_udp_size
  return message if message_retry.is_a? Exception
  return message if (message_retry.rcode == Dnsruby::RCode.FORMERR or
                     message_retry.rcode == Dnsruby::RCode.NOTIMP or
                     message_retry.rcode == Dnsruby::RCode.SERVFAIL)
  warnings_add "#{message.answerfrom} doesn't seem to support EDNS0"
  return message_retry
end

#makequery_with_udpsize(udpsize) ⇒ Object



66
67
68
69
# File 'lib/dnstraverse/decoded_query.rb', line 66

def makequery_with_udpsize(udpsize)
  @resolver.udp_size = udpsize
  return @resolver.query(@qname, @qtype)
end

#processObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/dnstraverse/decoded_query.rb', line 124

def process
  return process_exception if @message.is_a? Exception
  @auth_ns, @auth_soa, @auth_other = msg_authority(@message)
  @cacheable_good, @cacheable_bad = msg_cacheable(@message, @bailiwick)
  return process_error if @message.rcode != NOERROR
  @endname = msg_follow_cnames(@message, :qname => @qname, :qtype => @qtype,
                               :bailiwick => @bailiwick)
  return process_cname_loop if @endname.nil?
  return process_restart unless inside_bailiwick?(@endname)
  @answers = msg_answers?(@message, :qname => @endname, :qtype => qtype)
  return process_answered if @answers
  if @endname != @qname then
    if @auth_soa.size > 0 or @auth_ns.size == 0 then
      warnings_add "#{message.answerfrom} returned NODATA type 3 with a CNAME which we restarted"
    end
    return process_restart
  end
  return process_nodata if @auth_soa.size > 0 or @auth_ns.size == 0
  return process_referral unless @auth_ns.empty?
  return process_restart
end

#process_answeredObject



177
178
179
180
# File 'lib/dnstraverse/decoded_query.rb', line 177

def process_answered
  @status = :answered
  return self
end

#process_cname_loopObject



151
152
153
# File 'lib/dnstraverse/decoded_query.rb', line 151

def process_cname_loop
  @status = :cname_loop
end

#process_errorObject



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/dnstraverse/decoded_query.rb', line 159

def process_error
  @status = :error
  case @message.rcode
    when Dnsruby::RCode::FORMERR
    @error_message = "Formate error (FORMERR)"
    when Dnsruby::RCode::SERVFAIL
    @error_message = "Server failure (SERVFAIL)"
    when Dnsruby::RCode::NXDOMAIN
    @error_message = "No such domain (NXDOMAIN)"
    when Dnsruby::RCode::NOTIMP
    @error_message = "Not implemented (NOTIMP)"
    when Dnsruby::RCode::REFUSED
    @error_message = "Refused"
  else
    @error_message = @message.rcode.to_s
  end
end

#process_exceptionObject



146
147
148
149
# File 'lib/dnstraverse/decoded_query.rb', line 146

def process_exception
  @status = :exception
  @exception_message = @message.to_s
end

#process_nodataObject



182
183
184
185
# File 'lib/dnstraverse/decoded_query.rb', line 182

def process_nodata
  @status = :nodata
  return self
end

#process_referralObject



187
188
189
190
191
# File 'lib/dnstraverse/decoded_query.rb', line 187

def process_referral
  @status = :referral
  @authoritynames = @auth_ns.map { |rr| rr.domainname.to_s.downcase }
  return self
end

#process_restartObject



155
156
157
# File 'lib/dnstraverse/decoded_query.rb', line 155

def process_restart
  @status = :restart
end

#queryObject



93
94
95
96
97
98
99
100
101
102
103
# File 'lib/dnstraverse/decoded_query.rb', line 93

def query
  Log.debug { "Querying #{@ip} for #{@qname}/#{@qclass}/#{@qtype}" }
  @resolver.nameserver = ip
  @message = makequery_message
  unless @message.is_a? Exception then
    msg_validate(message, :qname => @qname, :qclass => @qclass, 
                 :qtype => @qtype)
    warnings_add msg_comment(message, :want_recursion => false)
  end
  return @message
end

#to_sObject



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/dnstraverse/decoded_query.rb', line 193

def to_s
  case @status
  when :error
    return "Error: #{@error_message}"
  when :exception
    return "Exception: #{@exception_message}"
  when :cname_loop
    return "CNANE loop"
  when :nodata
    return "No data"
  when :answered
    return "Answered (#{@answers.size} entries)"
  when :referral
    return "Referral to #{@authoritynames.join(',')}"
  when :restart
    return "Query re-start with #{@endname}"
  end
end

#warnings_add(warning) ⇒ Object



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

def warnings_add(warning)
  @warnings = [] unless @warnings
  if warning.is_a? Array then
    @warnings.concat warning
  else
    @warnings.push warning
  end
end