Class: Net::DNS::Packet
Overview
Net::DNS::Packet
The Net::DNS::Packet class represents an entire DNS packet, divided in his main section:
-
Header (instance of Net::DNS::Header)
-
Question (array of Net::DNS::Question objects)
-
Answer, Authority, Additional (each formed by an array of Net::DNS::RR objects)
You can use this class whenever you need to create a DNS packet, whether in an user application, in a resolver instance (have a look, for instance, at the Net::DNS::Resolver#send
method) or for a nameserver.
For example:
# Create a packet
packet = Net::DNS::Packet.new("www.example.com")
mx = Net::DNS::Packet.new("example.com", Net::DNS::MX)
# Getting packet binary data, suitable for network transmission
data = packet.data
A packet object can be created from binary data too, like an answer packet just received from a network stream:
packet = Net::DNS::Packet::parse(data)
Each part of a packet can be gotten by the right accessors:
header = packet.header # Instance of Net::DNS::Header class
question = packet.question # Instance of Net::DNS::Question class
# Iterate over additional RRs
packet.additional.each do |rr|
puts "Got an #{rr.type} record"
end
Some iterators have been written to easy the access of those RRs, which are often the most important. So instead of doing:
packet.answer.each do |rr|
if rr.type == Net::DNS::RR::Types::A
# do something with +rr.address+
end
end
we can do:
packet.each_address do |ip|
# do something with +ip+
end
Be sure you don’t miss all the iterators in the class documentation.
Logging facility
Logger can be set by using logger= to set the logger to any object that implements the necessary functions. If no logger is set then no logging is performed.
Logger level will be set to Logger::Debug
if $DEBUG
variable is set.
Defined Under Namespace
Classes: Error, PacketError
Constant Summary collapse
- @@logger =
nil
Constants included from Names
Instance Attribute Summary collapse
-
#additional ⇒ Object
Returns the value of attribute additional.
-
#answer ⇒ Object
Returns the value of attribute answer.
-
#answerfrom ⇒ Object
readonly
Returns the value of attribute answerfrom.
-
#answersize ⇒ Object
readonly
Returns the value of attribute answersize.
-
#authority ⇒ Object
Returns the value of attribute authority.
-
#header ⇒ Object
Returns the value of attribute header.
-
#question ⇒ Object
Returns the value of attribute question.
Class Method Summary collapse
- .logger=(logger) ⇒ Object
-
.parse(*args) ⇒ Object
Creates a new instance of
Net::DNS::Packet
class from binary data, taken out from a network stream.
Instance Method Summary collapse
-
#data ⇒ Object
Returns the packet object in binary data, suitable for sending across a network stream.
-
#data_comp ⇒ Object
Same as
Net::DNS::Packet#data
, but implements name compression (see RFC1025) for a considerable save of bytes. - #debug(*args) ⇒ Object
-
#each_address(&block) ⇒ Object
Iterates every address in the
answer
section of thisNet::DNS::Packet
instance. -
#each_cname(&block) ⇒ Object
Iterates every canonical name in the
answer
section of thisNet::DNS::Packet
instance. -
#each_mx(&block) ⇒ Object
Iterates every exchange record in the
answer
section of thisNet::DNS::Packet
instance. -
#each_nameserver(&block) ⇒ Object
Iterates every nameserver in the
answer
section of thisNet::DNS::Packet
instance. -
#each_ptr(&block) ⇒ Object
Iterates every pointer in the
answer
section of thisNet::DNS::Packet
instance. -
#elements(type = nil) ⇒ Object
Filters the elements in the
answer
section based on the class given. - #info(*args) ⇒ Object
-
#initialize(name = nil, type = Net::DNS::A, cls = Net::DNS::IN) ⇒ Packet
constructor
Creates a new instance of
Net::DNS::Packet
class. -
#inspect ⇒ Object
(also: #to_s)
Returns a string containing a human-readable representation of this
Net::DNS::Packet
instance. -
#nxdomain? ⇒ Boolean
Checks whether the query returned a NXDOMAIN error, meaning the queried domain name doesn’t exist.
-
#query? ⇒ Boolean
Checks if the packet is a QUERY packet.
-
#size ⇒ Object
Returns the packet size in bytes.
-
#truncated? ⇒ Boolean
Delegates to
Net::DNS::Header#truncated?
. - #warn(*args) ⇒ Object
Methods included from Names
#dn_comp, #dn_expand, #names_array, #pack_name, #valid?
Constructor Details
#initialize(name = nil, type = Net::DNS::A, cls = Net::DNS::IN) ⇒ Packet
Creates a new instance of Net::DNS::Packet
class. Arguments are the canonical name of the resource, an optional type field and an optional class field. If the arguments are omitted, no question is added to the new packet; type and class default to A
and IN
if a name is given.
packet = Net::DNS::Packet.new
packet = Net::DNS::Packet.new("www.example.com")
packet = Net::DNS::Packet.new("example.com", Net::DNS::MX)
packet = Net::DNS::Packet.new("example.com", Net::DNS::TXT, Net::DNS::CH)
This class no longer instantiate object from binary data coming from network streams. Please use Net::DNS::Packet.parse
instead.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/net/dns/packet.rb', line 100 def initialize(name = nil, type = Net::DNS::A, cls = Net::DNS::IN) default_qdcount = 0 @question = [] if not name.nil? default_qdcount = 1 @question = [Net::DNS::Question.new(name, type, cls)] end @header = Net::DNS::Header.new(:qdCount => default_qdcount) @answer = [] = [] @additional = [] end |
Instance Attribute Details
#additional ⇒ Object
Returns the value of attribute additional.
84 85 86 |
# File 'lib/net/dns/packet.rb', line 84 def additional @additional end |
#answer ⇒ Object
Returns the value of attribute answer.
84 85 86 |
# File 'lib/net/dns/packet.rb', line 84 def answer @answer end |
#answerfrom ⇒ Object (readonly)
Returns the value of attribute answerfrom.
85 86 87 |
# File 'lib/net/dns/packet.rb', line 85 def answerfrom @answerfrom end |
#answersize ⇒ Object (readonly)
Returns the value of attribute answersize.
85 86 87 |
# File 'lib/net/dns/packet.rb', line 85 def answersize @answersize end |
#authority ⇒ Object
Returns the value of attribute authority.
84 85 86 |
# File 'lib/net/dns/packet.rb', line 84 def end |
#header ⇒ Object
Returns the value of attribute header.
84 85 86 |
# File 'lib/net/dns/packet.rb', line 84 def header @header end |
#question ⇒ Object
Returns the value of attribute question.
84 85 86 |
# File 'lib/net/dns/packet.rb', line 84 def question @question end |
Class Method Details
.logger=(logger) ⇒ Object
120 121 122 123 124 125 126 |
# File 'lib/net/dns/packet.rb', line 120 def self.logger= logger if logger.respond_to?(:warn) && logger.respond_to?(:debug) && logger.respond_to?(:info) @@logger = logger else raise ArgumentError, "Invalid logger provided to #{self.class}" end end |
.parse(*args) ⇒ Object
Creates a new instance of Net::DNS::Packet
class from binary data, taken out from a network stream. For example:
# udp_socket is an UDPSocket waiting for a response
ans = udp_socket.recvfrom(1500)
packet = Net::DNS::Packet::parse(ans)
An optional from
argument can be used to specify the information of the sender. If data is passed as is from a Socket#recvfrom call, the method will accept it.
Be sure that your network data is clean from any UDP/TCP header, especially when using RAW sockets.
469 470 471 472 473 |
# File 'lib/net/dns/packet.rb', line 469 def self.parse(*args) o = allocate o.send(:new_from_data, *args) o end |
Instance Method Details
#data ⇒ Object
Returns the packet object in binary data, suitable for sending across a network stream.
packet_data = packet.data
puts "Packet is #{packet_data.size} bytes long"
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 |
# File 'lib/net/dns/packet.rb', line 152 def data qdcount=ancount=nscount=arcount=0 data = @header.data headerlength = data.length @question.each do |question| data += question.data qdcount += 1 end @answer.each do |rr| data += rr.data#(data.length) ancount += 1 end .each do |rr| data += rr.data#(data.length) nscount += 1 end @additional.each do |rr| data += rr.data#(data.length) arcount += 1 end @header.qdCount = qdcount @header.anCount = ancount @header.nsCount = nscount @header.arCount = arcount @header.data + data[Net::DNS::HFIXEDSZ..data.size] end |
#data_comp ⇒ Object
Same as Net::DNS::Packet#data
, but implements name compression (see RFC1025) for a considerable save of bytes.
packet = Net::DNS::Packet.new("www.example.com")
puts "Size normal is #{packet.data.size} bytes"
puts "Size compressed is #{packet.data_comp.size} bytes"
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 |
# File 'lib/net/dns/packet.rb', line 189 def data_comp offset = 0 compnames = {} qdcount=ancount=nscount=arcount=0 data = @header.data headerlength = data.length @question.each do |question| str,offset,names = question.data data += str compnames.update(names) qdcount += 1 end @answer.each do |rr| str,offset,names = rr.data(offset,compnames) data += str compnames.update(names) ancount += 1 end .each do |rr| str,offset,names = rr.data(offset,compnames) data += str compnames.update(names) nscount += 1 end @additional.each do |rr| str,offset,names = rr.data(offset,compnames) data += str compnames.update(names) arcount += 1 end @header.qdCount = qdcount @header.anCount = ancount @header.nsCount = nscount @header.arCount = arcount @header.data + data[Net::DNS::HFIXEDSZ..data.size] end |
#debug(*args) ⇒ Object
134 135 136 137 138 |
# File 'lib/net/dns/packet.rb', line 134 def debug *args if @@logger @@logger.debug *args end end |
#each_address(&block) ⇒ Object
Iterates every address in the answer
section of this Net::DNS::Packet
instance.
packet.each_address do |ip|
ping ip.to_s
end
As you can see in the documentation for the Net::DNS::RR::A
class, the address returned is an instance of IPAddr
class.
381 382 383 |
# File 'lib/net/dns/packet.rb', line 381 def each_address(&block) elements(Net::DNS::RR::A).map(&:address).each(&block) end |
#each_cname(&block) ⇒ Object
Iterates every canonical name in the answer
section of this Net::DNS::Packet
instance.
packet.each_cname do |cname|
puts "Canonical name: #{cname}"
end
414 415 416 |
# File 'lib/net/dns/packet.rb', line 414 def each_cname(&block) elements(Net::DNS::RR::CNAME).map(&:cname).each(&block) end |
#each_mx(&block) ⇒ Object
Iterates every exchange record in the answer
section of this Net::DNS::Packet
instance.
packet.each_mx do |pref,name|
puts "Mail exchange #{name} has preference #{pref}"
end
403 404 405 |
# File 'lib/net/dns/packet.rb', line 403 def each_mx(&block) elements(Net::DNS::RR::MX).map{|elem| [elem.preference, elem.exchange]}.each(&block) end |
#each_nameserver(&block) ⇒ Object
Iterates every nameserver in the answer
section of this Net::DNS::Packet
instance.
packet.each_nameserver do |ns|
puts "Nameserver found: #{ns}"
end
392 393 394 |
# File 'lib/net/dns/packet.rb', line 392 def each_nameserver(&block) elements(Net::DNS::RR::NS).map(&:nsdname).each(&block) end |
#each_ptr(&block) ⇒ Object
Iterates every pointer in the answer
section of this Net::DNS::Packet
instance.
packet.each_ptr do |ptr|
puts "Pointer for resource: #{ptr}"
end
425 426 427 |
# File 'lib/net/dns/packet.rb', line 425 def each_ptr(&block) elements(Net::DNS::RR::PTR).map(&:ptrdname).each(&block) end |
#elements(type = nil) ⇒ Object
Filters the elements in the answer
section based on the class given
364 365 366 367 368 369 370 |
# File 'lib/net/dns/packet.rb', line 364 def elements(type = nil) if type @answer.select {|elem| elem.kind_of? type} else @answer end end |
#info(*args) ⇒ Object
140 141 142 143 144 |
# File 'lib/net/dns/packet.rb', line 140 def info *args if @@logger @@logger.info *args end end |
#inspect ⇒ Object Also known as: to_s
Returns a string containing a human-readable representation of this Net::DNS::Packet
instance.
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 |
# File 'lib/net/dns/packet.rb', line 234 def inspect retval = "" if @answerfrom != "0.0.0.0:0" and @answerfrom retval += ";; Answer received from #@answerfrom (#{@answersize} bytes)\n;;\n" end retval += ";; HEADER SECTION\n" retval += @header.inspect retval += "\n" section = (@header.opCode == "UPDATE") ? "ZONE" : "QUESTION" retval += ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '' : 's'}):\n" @question.each do |qr| retval += ";; " + qr.inspect + "\n" end unless @answer.size == 0 retval += "\n" section = (@header.opCode == "UPDATE") ? "PREREQUISITE" : "ANSWER" retval += ";; #{section} SECTION (#{@header.anCount} record#{@header.anCount == 1 ? '' : 's'}):\n" @answer.each do |rr| retval += rr.inspect + "\n" end end unless .size == 0 retval += "\n" section = (@header.opCode == "UPDATE") ? "UPDATE" : "AUTHORITY" retval += ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '' : 's'}):\n" .each do |rr| retval += rr.inspect + "\n" end end unless @additional.size == 0 retval += "\n" retval += ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '' : 's'}):\n" @additional.each do |rr| retval += rr.inspect + "\n" end end retval end |
#nxdomain? ⇒ Boolean
Checks whether the query returned a NXDOMAIN error, meaning the queried domain name doesn’t exist.
%w[a.com google.com ibm.com d.com].each do |domain|
response = Net::DNS::Resolver.new.send(domain)
puts "#{domain} doesn't exist" if response.nxdomain?
end
# => a.com doesn't exist
# => d.com doesn't exist
450 451 452 |
# File 'lib/net/dns/packet.rb', line 450 def nxdomain? header.rCode.code == Net::DNS::Header::RCode::NAME end |
#query? ⇒ Boolean
Checks if the packet is a QUERY packet
116 117 118 |
# File 'lib/net/dns/packet.rb', line 116 def query? @header.query? end |
#size ⇒ Object
Returns the packet size in bytes.
Resolver("www.google.com") do |packet|
puts packet.size + " bytes"}
end
# => 484 bytes
436 437 438 |
# File 'lib/net/dns/packet.rb', line 436 def size data.size end |
#truncated? ⇒ Boolean
Delegates to Net::DNS::Header#truncated?
.
281 282 283 |
# File 'lib/net/dns/packet.rb', line 281 def truncated? @header.truncated? end |
#warn(*args) ⇒ Object
128 129 130 131 132 |
# File 'lib/net/dns/packet.rb', line 128 def warn *args if @@logger @@logger.warn *args end end |