1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 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 233 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 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 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 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 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
|
#--
#Copyright 2007 Nominet UK
#
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.
#++
require 'Dnsruby/code_mapper'
require 'Dnsruby/ipv4'
require 'Dnsruby/ipv6'
require 'timeout'
require 'Dnsruby/TheLog'
#= Dnsruby library
#Dnsruby is a thread-aware DNS stub resolver library written in Ruby.
#
#It is based on resolv.rb, the standard Ruby DNS implementation,
#but gives a complete DNS implementation, including DNSSEC.
#
#The Resolv class can be used to resolve addresses using /etc/hosts and /etc/resolv.conf,
#or the DNS class can be used to make DNS queries. These interfaces will attempt to apply
#the default domain and searchlist when resolving names.
#
#The Resolver and SingleResolver interfaces allow finer control of individual messages.
#The Resolver class sends queries to multiple resolvers using various retry mechanisms.
#The SingleResolver class is used by Resolver to send individual Messages to individual
#resolvers.
#
#Resolver queries return Dnsruby::Message objects. Message objects have five
#sections:
#
#* The header section, a Dnsruby::Header object.
#
#* The question section, a list of Dnsruby::Question objects.
#
#* The answer section, a list of Dnsruby::Resource objects.
#
#* The authority section, a list of Dnsruby::Resource objects.
#
#* The additional section, a list of Dnsruby::Resource objects.
#
#
#== example
# res = Dnsruby::Resolver.new # System default
# ret = res.query("example.com")
# print "#{ret.anwer.length} answer records returned, #{ret.answer.rrsets.length} RRSets returned in aswer section\n"
#
# p Dnsruby::Resolv.getaddress("www.ruby-lang.org")
# p Dnsruby::Resolv.getname("210.251.121.214")
#
# Dnsruby::DNS.open {|dns|
# p dns.getresources("www.ruby-lang.org", Dnsruby::Types.A).collect {|r| r.address}
# p dns.getresources("ruby-lang.org", 'MX').collect {|r| [r.exchange.to_s, r.preference]}
# }
#
#== exceptions
#
#* ResolvError < StandardError
#
#* ResolvTimeout < TimeoutError
#
#* NXDomain < ResolvError
#
#* FormErr < ResolvError
#
#* ServFail < ResolvError
#
#* NotImp < ResolvError
#
#* Refused < ResolvError
#
#* NotZone < ResolvError
#
#* YXDomain < ResolvError
#
#* YXRRSet < ResolvError
#
#* NXRRSet < ResolvError
#
#* NotAuth < ResolvError
#
#* OtherResolvError < ResolvError
#
#== I/O
#Dnsruby implements a pure Ruby event loop to perform I/O.
#Support for EventMachine has been deprecated.
#
#== DNSSEC
#Dnsruby supports DNSSEC and NSEC(3).
#DNSSEC support is on by default - but no trust anchors are configured by default.
#See Dnsruby::Dnssec for more details.
#
#== Bugs
#* NIS is not supported.
#* /etc/nsswitch.conf is not supported.
#* NSEC3 validation still TBD
module Dnsruby
# @TODO@ Remember to update version in dnsruby.gemspec!
VERSION = 1.54
def Dnsruby.version
return VERSION
end
@@logger = Logger.new(STDOUT)
@@logger.level = Logger::FATAL
#Get the log for Dnsruby
#Use this to set the log level
#e.g. Dnsruby.log.level = Logger::INFO
def Dnsruby.log
@@logger
end
class OpCode < CodeMapper
Query = 0 # RFC 1035
IQuery = 1 # RFC 1035
Status = 2 # RFC 1035
Notify = 4 # RFC 1996
Update = 5 # RFC 2136
update()
end
class RCode < CodeMapper
NOERROR = 0 # RFC 1035
FORMERR = 1 # RFC 1035
SERVFAIL = 2 # RFC 1035
NXDOMAIN = 3 # RFC 1035
NOTIMP = 4 # RFC 1035
REFUSED = 5 # RFC 1035
YXDOMAIN = 6 # RFC 2136
YXRRSET = 7 # RFC 2136
NXRRSET = 8 # RFC 2136
NOTAUTH = 9 # RFC 2136
NOTZONE = 10 # RFC 2136
# BADVERS = 16 # an EDNS ExtendedRCode
BADSIG = 16
BADKEY = 17
BADTIME = 18
BADMODE = 19
BADNAME = 20
BADALG = 21
update()
end
class ExtendedRCode < CodeMapper
BADVERS = 16
update()
end
class Classes < CodeMapper
IN = 1 # RFC 1035
CH = 3 # RFC 1035
# CHAOS = 3 # RFC 1035
HS = 4 # RFC 1035
# HESIOD = 4 # RFC 1035
NONE = 254 # RFC 2136
ANY = 255 # RFC 1035
update()
def unknown_string(arg)
if (arg=~/^CLASS/i)
Classes.add_pair(arg, arg.gsub('CLASS', '').to_i)
set_string(arg)
else
raise ArgumentError.new("String #{arg} not a member of #{self.class}")
end
end
def unknown_code(arg)
Classes.add_pair('CLASS' + arg.to_s, arg)
set_code(arg)
end
# classesbyval and classesbyname functions are wrappers around the
# similarly named hashes. They are used for 'unknown' DNS RR classess
# (RFC3597)
# See typesbyval and typesbyname, these beasts have the same functionality
def Classes.classesbyname(name) #:nodoc: all
name.upcase!;
if to_code(name)
return to_code(name)
end
if ((name =~/^\s*CLASS(\d+)\s*$/o) == nil)
raise ArgumentError, "classesbyval() argument is not CLASS### (#{name})"
end
val = $1.to_i
if val > 0xffff
raise ArgumentError, 'classesbyval() argument larger than ' + 0xffff
end
return val;
end
def Classes.classesbyval(val) #:nodoc: all
if (val.class == String)
if ((val =~ /^\s*0*([0-9]+)\s*$/) == nil)
raise ArgumentError, "classesbybal() argument is not numeric (#{val})" # unless val.gsub!("^\s*0*([0-9]+)\s*$", "$1")
# val =~ s/^\s*0*([0-9]+)\s*$/$1/o;#
end
val = $1.to_i
end
return to_string(val) if to_string(val)
raise ArgumentError, 'classesbyval() argument larger than ' + 0xffff if val > 0xffff;
return "CLASS#{val}";
end
end
# The RR types explicitly supported by Dnsruby.
#
# New RR types should be added to this set
class Types < CodeMapper
SIGZERO = 0 # RFC2931 consider this a pseudo type
A = 1 # RFC 1035, Section 3.4.1
NS = 2 # RFC 1035, Section 3.3.11
MD = 3 # RFC 1035, Section 3.3.4 (obsolete)
MF = 4 # RFC 1035, Section 3.3.5 (obsolete)
CNAME = 5 # RFC 1035, Section 3.3.1
SOA = 6 # RFC 1035, Section 3.3.13
MB = 7 # RFC 1035, Section 3.3.3
MG = 8 # RFC 1035, Section 3.3.6
MR = 9 # RFC 1035, Section 3.3.8
NULL = 10 # RFC 1035, Section 3.3.10
WKS = 11 # RFC 1035, Section 3.4.2 (deprecated)
PTR = 12 # RFC 1035, Section 3.3.12
HINFO = 13 # RFC 1035, Section 3.3.2
MINFO = 14 # RFC 1035, Section 3.3.7
MX = 15 # RFC 1035, Section 3.3.9
TXT = 16 # RFC 1035, Section 3.3.14
RP = 17 # RFC 1183, Section 2.2
AFSDB = 18 # RFC 1183, Section 1
X25 = 19 # RFC 1183, Section 3.1
ISDN = 20 # RFC 1183, Section 3.2
RT = 21 # RFC 1183, Section 3.3
NSAP = 22 # RFC 1706, Section 5
NSAP_PTR = 23 # RFC 1348 (obsolete)
SIG = 24 # RFC 2535, Section 4.1
KEY = 25 # RFC 2535, Section 3.1
PX = 26 # RFC 2163,
GPOS = 27 # RFC 1712 (obsolete)
AAAA = 28 # RFC 1886, Section 2.1
LOC = 29 # RFC 1876
NXT = 30 # RFC 2535, Section 5.2 obsoleted by RFC3755
EID = 31 # draft-ietf-nimrod-dns-xx.txt
NIMLOC = 32 # draft-ietf-nimrod-dns-xx.txt
SRV = 33 # RFC 2052
ATMA = 34 # ???
NAPTR = 35 # RFC 2168
KX = 36 # RFC 2230
CERT = 37 # RFC 2538
DNAME = 39 # RFC 2672
OPT = 41 # RFC 2671
# APL = 42 # RFC 3123
DS = 43 # RFC 4034
SSHFP = 44 # RFC 4255
IPSECKEY = 45 # RFC 4025
RRSIG = 46 # RFC 4034
NSEC = 47 # RFC 4034
DNSKEY = 48 # RFC 4034
DHCID = 49 # RFC 4701
NSEC3 = 50 # RFC still pending at time of writing
NSEC3PARAM= 51 # RFC still pending at time of writing
HIP = 55 # RFC 5205
SPF = 99 # RFC 4408
UINFO = 100 # non-standard
UID = 101 # non-standard
GID = 102 # non-standard
UNSPEC = 103 # non-standard
TKEY = 249 # RFC 2930
TSIG = 250 # RFC 2931
IXFR = 251 # RFC 1995
AXFR = 252 # RFC 1035
MAILB = 253 # RFC 1035 (MB, MG, MR)
MAILA = 254 # RFC 1035 (obsolete - see MX)
ANY = 255 # RFC 1035
DLV = 32769 # RFC 4431 (informational)
update()
def unknown_string(arg) #:nodoc: all
if (arg=~/^TYPE/i)
Types.add_pair(arg, arg.gsub('TYPE', '').to_i)
set_string(arg)
else
raise ArgumentError.new("String #{arg} not a member of #{self.class}")
end
end
def unknown_code(arg) #:nodoc: all
Types.add_pair('TYPE' + arg.to_s, arg)
set_code(arg)
end
#--
# typesbyval and typesbyname functions are wrappers around the similarly named
# hashes. They are used for 'unknown' DNS RR types (RFC3597)
# typesbyname returns they TYPEcode as a function of the TYPE
# mnemonic. If the TYPE mapping is not specified the generic mnemonic
# TYPE### is returned.
def Types.typesbyname(name) #:nodoc: all
name.upcase!
if to_code(name)
return to_code(name)
end
if ((name =~/^\s*TYPE(\d+)\s*$/o)==nil)
raise ArgumentError, "Net::DNS::typesbyname() argument (#{name}) is not TYPE###"
end
val = $1.to_i
if val > 0xffff
raise ArgumentError, 'Net::DNS::typesbyname() argument larger than ' + 0xffff
end
return val;
end
# typesbyval returns they TYPE mnemonic as a function of the TYPE
# code. If the TYPE mapping is not specified the generic mnemonic
# TYPE### is returned.
def Types.typesbyval(val) #:nodoc: all
if (!defined?val)
raise ArgumentError, "Net::DNS::typesbyval() argument is not defined"
end
if val.class == String
# if val.gsub!("^\s*0*(\d+)\s*$", "$1")
if ((val =~ /^\s*0*(\d+)\s*$", "$1/o) == nil)
raise ArgumentError, "Net::DNS::typesbyval() argument (#{val}) is not numeric"
# val =~s/^\s*0*(\d+)\s*$/$1/o;
end
val = $1.to_i
end
if to_string(val)
return to_string(val)
end
raise ArgumentError, 'Net::DNS::typesbyval() argument larger than ' + 0xffff if
val > 0xffff;
return "TYPE#{val}";
end
end
class QTypes < CodeMapper
IXFR = 251 # incremental transfer [RFC1995]
AXFR = 252 # transfer of an entire zone [RFC1035]
MAILB = 253 # mailbox-related RRs (MB, MG or MR) [RFC1035]
MAILA = 254 # mail agent RRs (Obsolete - see MX) [RFC1035]
ANY = 255 # all records [RFC1035]
update()
end
class MetaTypes < CodeMapper
TKEY = 249 # Transaction Key [RFC2930]
TSIG = 250 # Transaction Signature [RFC2845]
OPT = 41 # RFC 2671
end
# http://www.iana.org/assignments/dns-sec-alg-numbers/
class Algorithms < CodeMapper
RESERVED = 0
RSAMD5 = 1
DH = 2
DSA = 3
ECC = 4
RSASHA1 = 5
RSASHA256 = 8
RSASHA512 = 10
INDIRECT = 252
PRIVATEDNS = 253
PRIVATEOID = 254
update()
# Referred to as Algorithms.DSA_NSEC3_SHA1
add_pair("DSA-NSEC3-SHA1", 6)
# Referred to as Algorithms.RSASHA1_NSEC3_SHA1
add_pair("RSASHA1-NSEC3-SHA1", 7)
end
# http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml
class Nsec3HashAlgorithms < CodeMapper
RESERVED = 0
update()
add_pair("SHA-1", 1)
end
#An error raised while querying for a resource
class ResolvError < StandardError
end
#A timeout error raised while querying for a resource
class ResolvTimeout < Timeout::Error
end
#The requested domain does not exist
class NXDomain < ResolvError
end
#A format error in a received DNS message
class FormErr < ResolvError
end
#Indicates a failure in the remote resolver
class ServFail < ResolvError
end
#The requested operation is not implemented in the remote resolver
class NotImp < ResolvError
end
#The requested operation was refused by the remote resolver
class Refused < ResolvError
end
#The update RR is outside the zone (in dynamic update)
class NotZone < ResolvError
end
#Some name that ought to exist, does not exist (in dynamic update)
class YXDomain < ResolvError
end
#Some RRSet that ought to exist, does not exist (in dynamic update)
class YXRRSet < ResolvError
end
#Some RRSet that ought not to exist, does exist (in dynamic update)
class NXRRSet < ResolvError
end
#The nameserver is not responsible for the zone (in dynamic update)
class NotAuth < ResolvError
end
#Another kind of resolver error has occurred
class OtherResolvError < ResolvError
end
#An error occurred processing the TSIG
class TsigError < OtherResolvError
end
# Sent a signed packet, got an unsigned response
class TsigNotSignedResponseError < TsigError
end
#Indicates an error in decoding an incoming DNS message
class DecodeError < ResolvError
attr_accessor :partial_message
end
#Indicates an error encoding a DNS message for transmission
class EncodeError < ResolvError
end
#Indicates an error verifying
class VerifyError < ResolvError
end
#Indicates a zone transfer has failed due to SOA serial mismatch
class ZoneSerialError < ResolvError
end
#The Resolv class can be used to resolve addresses using /etc/hosts and /etc/resolv.conf,
#
#The DNS class may be used to perform more queries. If greater control over the sending
#of packets is required, then the Resolver or SingleResolver classes may be used.
class Resolv
#Looks up the first IP address for +name+
def self.getaddress(name)
DefaultResolver.getaddress(name)
end
#Looks up all IP addresses for +name+
def self.getaddresses(name)
DefaultResolver.getaddresses(name)
end
#Iterates over all IP addresses for +name+
def self.each_address(name, &block)
DefaultResolver.each_address(name, &block)
end
#Looks up the first hostname of +address+
def self.getname(address)
DefaultResolver.getname(address)
end
#Looks up all hostnames of +address+
def self.getnames(address)
DefaultResolver.getnames(address)
end
#Iterates over all hostnames of +address+
def self.each_name(address, &proc)
DefaultResolver.each_name(address, &proc)
end
#Creates a new Resolv using +resolvers+
def initialize(resolvers=[Hosts.new, DNS.new])
@resolvers = resolvers
end
#Looks up the first IP address for +name+
def getaddress(name)
each_address(name) {|address| return address}
raise ResolvError.new("no address for #{name}")
end
#Looks up all IP addresses for +name+
def getaddresses(name)
ret = []
each_address(name) {|address| ret << address}
return ret
end
#Iterates over all IP addresses for +name+
def each_address(name)
if AddressRegex =~ name
yield name
return
end
yielded = false
@resolvers.each {|r|
r.each_address(name) {|address|
yield address.to_s
yielded = true
}
return if yielded
}
end
#Looks up the first hostname of +address+
def getname(address)
each_name(address) {|name| return name}
raise ResolvError.new("no name for #{address}")
end
#Looks up all hostnames of +address+
def getnames(address)
ret = []
each_name(address) {|name| ret << name}
return ret
end
#Iterates over all hostnames of +address+
def each_name(address)
yielded = false
@resolvers.each {|r|
r.each_name(address) {|name|
yield name.to_s
yielded = true
}
return if yielded
}
end
require 'Dnsruby/Cache'
require 'Dnsruby/DNS'
require 'Dnsruby/Hosts'
require 'Dnsruby/message'
require 'Dnsruby/update'
require 'Dnsruby/zone_transfer'
require 'Dnsruby/dnssec'
require 'Dnsruby/zone_reader'
#Default Resolver to use for Dnsruby class methods
DefaultResolver = self.new
#Address RegExp to use for matching IP addresses
AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
end
end
|