Class: Net::DNS::Resolver::Recurse
- Inherits:
-
Net::DNS::Resolver
- Object
- Net::DNS::Resolver
- Net::DNS::Resolver::Recurse
- Defined in:
- lib/Net/DNS/Resolver/Recurse.rb
Overview
NAME
Net::DNS::Resolver::Recurse - Perform recursive dns lookups
SYNOPSIS
require 'Net/DNS'
res = Net::DNS::Resolver::Recurse.new
DESCRIPTION
This module is a sub class of Net::DNS::Resolver. So the methods for Net::DNS::Resolver still work for this module as well. There are just a couple methods added
head1 AUTHOR
Rob Brown, [email protected]
head1 SEE ALSO
L<Net::DNS::Resolver>,
head1 COPYRIGHT
Copyright © 2002, Rob Brown. All rights reserved. Portions Copyright © 2005, Olaf M Kolkman. Ruby version Copyright © 2006, AlexD (Nominet UK)
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Example lookup process:
[root@box root]# dig +trace www.rob.com.au.
; <<>> DiG 9.2.0 <<>> +trace www.rob.com.au. ;; global options: printcmd . 507343 IN NS C.ROOT-SERVERS.NET. . 507343 IN NS D.ROOT-SERVERS.NET. . 507343 IN NS E.ROOT-SERVERS.NET. . 507343 IN NS F.ROOT-SERVERS.NET. . 507343 IN NS G.ROOT-SERVERS.NET. . 507343 IN NS H.ROOT-SERVERS.NET. . 507343 IN NS I.ROOT-SERVERS.NET. . 507343 IN NS J.ROOT-SERVERS.NET. . 507343 IN NS K.ROOT-SERVERS.NET. . 507343 IN NS L.ROOT-SERVERS.NET. . 507343 IN NS M.ROOT-SERVERS.NET. . 507343 IN NS A.ROOT-SERVERS.NET. . 507343 IN NS B.ROOT-SERVERS.NET. ;; Received 436 bytes from 127.0.0.1#53(127.0.0.1) in 9 ms
;;; But these should be hard coded as the hints
;;; Ask H.ROOT-SERVERS.NET gave:
au. 172800 IN NS NS2.BERKELEY.EDU. au. 172800 IN NS NS1.BERKELEY.EDU. au. 172800 IN NS NS.UU.NET. au. 172800 IN NS BOX2.AUNIC.NET. au. 172800 IN NS SEC1.APNIC.NET. au. 172800 IN NS SEC3.APNIC.NET. ;; Received 300 bytes from 128.63.2.53#53(H.ROOT-SERVERS.NET) in 322 ms
;;; A little closer than before
;;; Ask NS2.BERKELEY.EDU gave:
com.au. 259200 IN NS ns4.ausregistry.net. com.au. 259200 IN NS dns1.telstra.net. com.au. 259200 IN NS au2ld.CSIRO.au. com.au. 259200 IN NS audns01.syd.optus.net. com.au. 259200 IN NS ns.ripe.net. com.au. 259200 IN NS ns1.ausregistry.net. com.au. 259200 IN NS ns2.ausregistry.net. com.au. 259200 IN NS ns3.ausregistry.net. com.au. 259200 IN NS ns3.melbourneit.com. ;; Received 387 bytes from 128.32.206.12#53(NS2.BERKELEY.EDU) in 10312 ms
;;; A little closer than before
;;; Ask ns4.ausregistry.net gave:
com.au. 259200 IN NS ns1.ausregistry.net. com.au. 259200 IN NS ns2.ausregistry.net. com.au. 259200 IN NS ns3.ausregistry.net. com.au. 259200 IN NS ns4.ausregistry.net. com.au. 259200 IN NS ns3.melbourneit.com. com.au. 259200 IN NS dns1.telstra.net. com.au. 259200 IN NS au2ld.CSIRO.au. com.au. 259200 IN NS ns.ripe.net. com.au. 259200 IN NS audns01.syd.optus.net. ;; Received 259 bytes from 137.39.1.3#53(ns4.ausregistry.net) in 606 ms
;;; Uh... yeah... I already knew this
;;; from what NS2.BERKELEY.EDU told me.
;;; ns4.ausregistry.net must have brain damage
;;; Ask ns1.ausregistry.net gave:
rob.com.au. 86400 IN NS sy-dns02.tmns.net.au. rob.com.au. 86400 IN NS sy-dns01.tmns.net.au. ;; Received 87 bytes from 203.18.56.41#53(ns1.ausregistry.net) in 372 ms
;;; Ah, much better. Something more useful.
;;; Ask sy-dns02.tmns.net.au gave:
www.rob.com.au. 7200 IN A 139.134.5.123 rob.com.au. 7200 IN NS sy-dns01.tmns.net.au. rob.com.au. 7200 IN NS sy-dns02.tmns.net.au. ;; Received 135 bytes from 139.134.2.18#53(sy-dns02.tmns.net.au) in 525 ms
;;; FINALLY, THE ANSWER!
Constant Summary
Constants inherited from Net::DNS::Resolver
DEFAULT_ERROR_STRING, DOTFILE, RESOLV_CONF
Instance Attribute Summary collapse
-
#callback ⇒ Object
Returns the value of attribute callback.
-
#hints ⇒ Object
Returns the value of attribute hints.
-
#nameservers ⇒ Object
Returns the value of attribute nameservers.
-
#recurse ⇒ Object
Returns the value of attribute recurse.
Attributes inherited from Net::DNS::Resolver
#answerfrom, #answersize, #axfr_rr, #axfr_sel, #axfr_soa_count, #cdflag, #debug, #defnames, #dnsrch, #dnssec, #domain, #errorstring, #force_v4, #ignqrid, #igntc, #persistent_tcp, #persistent_udp, #port, #querytime, #retrans, #retry, #searchlist, #set, #sockets, #srcaddr, #srcport, #stayopen, #tcp_timeout, #tsig_rr, #udp_timeout, #udppacketsize, #usevc
Instance Method Summary collapse
- #_dorecursion(query_packet, known_zone, known_authorities, depth) ⇒ Object
-
#query_dorecursion(*args) ⇒ Object
This method is much like the normal query() method except it disables the recurse flag in the packet and explicitly performs the recursion.
- #recursion_callback ⇒ Object
-
#recursion_callback=(sub) ⇒ Object
This method is takes a code reference, which is then invoked each time a packet is received during the recursive lookup.
Methods inherited from Net::DNS::Resolver
#_create_tcp_socket, #_packetsz, #_reset_errorstring, #axfr, #axfr_next, #axfr_old, #axfr_start, #bgisready, #bgread, #bgsend, #cname_addr, #initialize, #inspect, #make_query_packet, #query, #read_config_file, #read_env, #read_tcp, #search, #send, #send_method, #send_tcp, #send_udp, #set_defaults, #tsig, #tsig=
Constructor Details
This class inherits a constructor from Net::DNS::Resolver
Instance Attribute Details
#callback ⇒ Object
Returns the value of attribute callback.
124 125 126 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 124 def callback @callback end |
#hints ⇒ Object
Returns the value of attribute hints.
125 126 127 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 125 def hints @hints end |
#nameservers ⇒ Object
Returns the value of attribute nameservers.
124 125 126 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 124 def nameservers @nameservers end |
#recurse ⇒ Object
Returns the value of attribute recurse.
124 125 126 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 124 def recurse @recurse end |
Instance Method Details
#_dorecursion(query_packet, known_zone, known_authorities, depth) ⇒ Object
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 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 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 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 467 468 469 470 471 472 473 474 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 272 def _dorecursion(query_packet, known_zone, , depth) cache = @authority_cache # die "Recursion too deep, aborting..." if $depth > 255; if ( depth > 255 ) print ";; _dorecursion() Recursion too deep, aborting...\n" if @debug @errorstring="Recursion too deep, aborted" return nil end known_zone.sub!(/\.*$/, ".") # Get IPs from authorities ns = [] # foreach my $ns (keys %{ $known_authorities }) { .keys.each do |ns_rec| if ([ns_rec] != nil && [ns_rec] != [] ) cache[ns_rec] = [ns_rec] ns.push(cache[ns_rec]) elsif (cache[ns_rec]!=nil && cache[ns_rec]!=[]) [ns_rec] = cache[ns_rec] ns.push(cache[ns_rec]) end end if (ns.length == 0) found_auth = 0 if (@debug) print ";; _dorecursion() Failed to extract nameserver IPs:\n"; print .inspect + cache.inspect + "\n" end # foreach my $ns (keys %{ $known_authorities }) { .keys.each do |ns_rec| if ([ns_rec]==nil || [ns_rec]==[]) print ";; _dorecursion() Manual lookup for authority [#{ns_rec}]\n" if @debug auth_packet=nil ans=[] # Don't query for V6 if its not there. if (! @force_v4) auth_packet = _dorecursion(make_query_packet([ns_rec,"AAAA"]), # packet ".", # known_zone @hints, # known_authorities depth+1); # depth ans = auth_packet.answer if auth_packet end auth_packet = _dorecursion(make_query_packet([ns_rec,"A"]), # packet ".", # known_zone @hints, # known_authorities depth+1); # depth ans.push(auth_packet.answer ) if auth_packet if ( ans.length > 0 ) print ";; _dorecursion() Answers found for [#{ns_rec}]\n" if @debug # foreach my $rr (@ans) { ans.each do |rr_arr| rr_arr.each do |rr| print ";; RR:" + rr.inspect + "\n" if @debug if (rr.type == "CNAME") # Follow CNAME server = rr.name.downcase if (server) server.sub!(/\.*$/, ".") if (server == ns_rec) cname = rr.rdatastr.downcase cname.sub!(/\.*$/, ".") print ";; _dorecursion() Following CNAME ns [#{ns_rec}] -> [#{cname}]\n" if @debug [cname] ||= [] .delete[ns_rec] next end end elsif (rr.type == "A" || rr.type == "AAAA" ) server = rr.name.downcase if (server) server.sub!(/\.*$/, ".") if ([server]!=nil) ip = rr.rdatastr print ";; _dorecursion() Found ns: #{server} IN A #{ip}\n" if @debug cache[server] = [server] cache[ns_rec].push(ip) found_auth+=1 next end end end print ";; _dorecursion() Ignoring useless answer: " + rr.inspect + "\n" if @debug end end else print ";; _dorecursion() Could not find A records for [#{ns_rec}]\n" if @debug end end end if (found_auth > 0) print ";; _dorecursion() Found #{found_auth} new NS authorities...\n" if @debug return _dorecursion( query_packet, known_zone, , depth+1) end print ";; _dorecursion() No authority information could be obtained.\n" if @debug return nil end # Cut the deck of IPs in a random place. print ";; _dorecursion() cutting deck of (" + ns.length.to_s + ") authorities...\n" if @debug splitpos = rand(ns.length) start = ns[0, splitpos] endarr = ns[splitpos, ns.length - splitpos] ns = endarr + start ns.each do |levelns| print ";; _dorecursion() Trying nameserver [#{levelns}]\n" if @debug @nameservers=(levelns) packet = send( query_packet ) if (packet) if (@callback) @callback.call(packet) end of = nil print ";; _dorecursion() Response received from [" + @answerfrom + "]\n" if @debug status = packet.header.rcode = packet. if (status) if (status == "NXDOMAIN") # I guess NXDOMAIN is the best we'll ever get print ";; _dorecursion() returning NXDOMAIN\n" if @debug return packet elsif (packet.answer.length > 0) print ";; _dorecursion() Answers were found.\n" if @debug return packet elsif (.length > 0) auth = Hash.new # foreach my $rr (@authority) { .each do |rr| if (rr.type =~ /^(NS|SOA)$/) server = (rr.type == "NS" ? rr.nsdname : rr.mname).downcase server.sub!(/\.*$/, ".") of = rr.name.downcase of.sub!(/\.*$/, ".") print ";; _dorecursion() Received authority [#{of}] [" + rr.type() + "] [#{server}]\n" if @debug if (of.length <= known_zone.length) print ";; _dorecursion() Deadbeat name server did not provide new information.\n" if @debug next elsif (of =~ /#{known_zone}/) print ";; _dorecursion() FOUND closer authority for [#{of}] at [#{server}].\n" if @debug auth[server] ||= [] else print ";; _dorecursion() Confused name server [" + @answerfrom + "] thinks [#{of}] is closer than [#{known_zone}]?\n" if @debug last end else print ";; _dorecursion() Ignoring NON NS entry found in authority section: " + rr.inspect + "\n" if @debug end end # foreach my $rr ($packet->additional) packet.additional.each do |rr| if (rr.type == "CNAME") # Store this CNAME into %auth too server = rr.name.downcase if (server) server.sub!(/\.*$/, ".") if (auth[server]!=nil && auth[server]!=[]) cname = rr.rdatastr.downcase cname.sub!(/\.*$/, ".") print ";; _dorecursion() FOUND CNAME authority: " + rr.string + "\n" if @debug auth[cname] ||= [] auth[server] = auth[cname] next end end elsif (rr.type == "A" || rr.type == "AAAA") server = rr.name.downcase if (server) server.sub!(/\.*$/, ".") if (auth[server]!=nil) print ";; _dorecursion() STORING: #{server} IN A " + rr.rdatastr + "\n" if @debug && rr.type == "A" print ";; _dorecursion() STORING: #{server} IN AAAA " + rr.rdatastr + "\n" if @debug && rr.type == "AAAA" auth[server].push(rr.rdatastr) next end end end print ";; _dorecursion() Ignoring useless: " + rr.inspect + "\n" if @debug end if (of =~ /#{known_zone}/) return _dorecursion( query_packet, of, auth, depth+1 ) else return _dorecursion( query_packet, known_zone, , depth+1 ) end end end end end return nil end |
#query_dorecursion(*args) ⇒ Object
This method is much like the normal query() method except it disables the recurse flag in the packet and explicitly performs the recursion.
packet = res.query_dorecursion( "www.netscape.com.", "A")
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 255 def query_dorecursion(*args) # Make sure the hint servers are initialized. @hints=Hash.new unless @hints @recurse=(0) # Make sure the authority cache is clean. # It is only used to store A and AAAA records of # the suposedly authoritative name servers. @authority_cache = Hash.new # Obtain real question Net::DNS::Packet query_packet = make_query_packet(args) # Seed name servers with hints return _dorecursion( query_packet, ".", @hints, 0) end |
#recursion_callback ⇒ Object
243 244 245 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 243 def recursion_callback return @callback end |
#recursion_callback=(sub) ⇒ Object
This method is takes a code reference, which is then invoked each time a packet is received during the recursive lookup. For example to emulate dig’s C<+trace> function:
res.recursion_callback(Proc.new { |packet|
print packet.additional.inspect
print";; Received %d bytes from %s\n\n",
packetanswersize,
packet.answerfrom);
})
237 238 239 240 241 |
# File 'lib/Net/DNS/Resolver/Recurse.rb', line 237 def recursion_callback=(sub) # if (sub && UNIVERSAL::isa(sub, 'CODE')) @callback = sub # end end |