Class: Net::DNS::Packet
Overview
Name
Net::DNS::Packet - DNS packet object class
Synopsis
require 'net/dns/packet'
Description
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.
Some 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
As Net::DNS::Resolver class, Net::DNS::Packet class has its own logging facility too. It work in the same way the other one do, so you can maybe want to override it or change the file descriptor.
packet = Net::DNS::Packet.new("www.example.com")
packet.logger = $stderr
# or even
packet.logger = Logger.new("/tmp/packet.log")
If the Net::DNS::Packet class is directly instantiated by the Net::DNS::Resolver class, like the great majority of the time, it will use the same logger facility.
Logger level will be set to Logger::Debug if $DEBUG variable is set.
Error classes
Some error classes has been defined for the Net::DNS::Packet class, which are listed here to keep a light and browsable main documentation. We have:
-
PacketArgumentError: Generic argument error for class Net::DNS::Packet
-
PacketError: Generic Packet error
Copyright
Copyright © 2006 Marco Ceresa
All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Ruby itself.
Constant Summary
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
-
.parse(*args) ⇒ Object
Create a new instance of Net::DNS::Packet class from binary data, taken out by a network stream.
Instance Method Summary collapse
-
#data ⇒ Object
Return 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.
-
#each_address ⇒ Object
Iterate for every address in the
answer
section of a Net::DNS::Packet object. -
#each_cname ⇒ Object
Iterate for every canonical name in the
answer
section of a Net::DNS::Packet object. -
#each_mx ⇒ Object
Iterate for every exchange record in the
answer
section of a Net::DNS::Packet object. -
#each_nameserver ⇒ Object
Iterate for every nameserver in the
answer
section of a Net::DNS::Packet object. -
#each_ptr ⇒ Object
Iterate for every pointer in the
answer
section of a Net::DNS::Packet object. -
#initialize(name, type = Net::DNS::A, cls = Net::DNS::IN) ⇒ Packet
constructor
Create a new instance of Net::DNS::Packet class.
-
#inspect ⇒ Object
Inspect method.
-
#nxdomain? ⇒ Boolean
Chacks whether a query has returned a NXDOMAIN error, meaning the domain name queried doesn’t exists.
-
#query? ⇒ Boolean
Checks if the packet is a QUERY packet.
-
#size ⇒ Object
Returns the packet size in bytes.
-
#truncated? ⇒ Boolean
Wrapper to Header#truncated?.
Methods included from Names
#dn_comp, #dn_expand, #names_array, #pack_name, #valid?
Constructor Details
#initialize(name, type = Net::DNS::A, cls = Net::DNS::IN) ⇒ Packet
Create a new instance of Net::DNS::Packet class. Arguments are the canonical name of the resourse, an optional type field and an optional class field. The record type and class can be omitted; they default to A
and IN
.
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.new_from_data instead.
126 127 128 129 130 131 132 133 134 |
# File 'lib/net/dns/packet.rb', line 126 def initialize(name,type=Net::DNS::A,cls=Net::DNS::IN) @header = Net::DNS::Header.new(:qdCount => 1) @question = [Net::DNS::Question.new(name,type,cls)] @answer = [] @authority = [] @additional = [] @logger = Logger.new $stdout @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN end |
Instance Attribute Details
#additional ⇒ Object
Returns the value of attribute additional.
111 112 113 |
# File 'lib/net/dns/packet.rb', line 111 def additional @additional end |
#answer ⇒ Object
Returns the value of attribute answer.
111 112 113 |
# File 'lib/net/dns/packet.rb', line 111 def answer @answer end |
#answerfrom ⇒ Object (readonly)
Returns the value of attribute answerfrom.
112 113 114 |
# File 'lib/net/dns/packet.rb', line 112 def answerfrom @answerfrom end |
#answersize ⇒ Object (readonly)
Returns the value of attribute answersize.
112 113 114 |
# File 'lib/net/dns/packet.rb', line 112 def answersize @answersize end |
#authority ⇒ Object
Returns the value of attribute authority.
111 112 113 |
# File 'lib/net/dns/packet.rb', line 111 def @authority end |
#header ⇒ Object
Returns the value of attribute header.
111 112 113 |
# File 'lib/net/dns/packet.rb', line 111 def header @header end |
#question ⇒ Object
Returns the value of attribute question.
111 112 113 |
# File 'lib/net/dns/packet.rb', line 111 def question @question end |
Class Method Details
.parse(*args) ⇒ Object
Create a new instance of Net::DNS::Packet class from binary data, taken out by 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, expecially when using RAW sockets.
150 151 152 153 154 |
# File 'lib/net/dns/packet.rb', line 150 def Packet.parse(*args) o = allocate o.send(:new_from_data, *args) o end |
Instance Method Details
#data ⇒ Object
Return 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"
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 |
# File 'lib/net/dns/packet.rb', line 168 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 @authority.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
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 |
# File 'lib/net/dns/packet.rb', line 205 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 @authority.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 |
#each_address ⇒ Object
Iterate for every address in the answer
section of a Net::DNS::Packet object.
packet.each_address do |ip|
ping ip.to_s
end
As you can see in the documentation for Net::DNS::RR::A class, the address returned is an instance of IPAddr class.
397 398 399 400 401 402 |
# File 'lib/net/dns/packet.rb', line 397 def each_address @answer.each do |elem| next unless elem.class == Net::DNS::RR::A yield elem.address end end |
#each_cname ⇒ Object
Iterate for every canonical name in the answer
section of a Net::DNS::Packet object.
packet.each_cname do |cname|
puts "Canonical name: #{cname}"
end
439 440 441 442 443 444 |
# File 'lib/net/dns/packet.rb', line 439 def each_cname @answer.each do |elem| next unless elem.class == Net::DNS::RR::CNAME yield elem.cname end end |
#each_mx ⇒ Object
Iterate for every exchange record in the answer
section of a Net::DNS::Packet object.
packet.each_mx do |pref,name|
puts "Mail exchange #{name} has preference #{pref}"
end
425 426 427 428 429 430 |
# File 'lib/net/dns/packet.rb', line 425 def each_mx @answer.each do |elem| next unless elem.class == Net::DNS::RR::MX yield elem.preference,elem.exchange end end |
#each_nameserver ⇒ Object
Iterate for every nameserver in the answer
section of a Net::DNS::Packet object.
packet.each_nameserver do |ns|
puts "Nameserver found: #{ns}"
end
411 412 413 414 415 416 |
# File 'lib/net/dns/packet.rb', line 411 def each_nameserver @answer.each do |elem| next unless elem.class == Net::DNS::RR::NS yield elem.nsdname end end |
#each_ptr ⇒ Object
Iterate for every pointer in the answer
section of a Net::DNS::Packet object.
packet.each_ptr do |ptr|
puts "Pointer for resource: #{ptr}"
end
453 454 455 456 457 458 |
# File 'lib/net/dns/packet.rb', line 453 def each_ptr @answer.each do |elem| next unless elem.class == Net::DNS::RR::PTR yield elem.ptrdname end end |
#inspect ⇒ Object
Inspect method
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 |
# File 'lib/net/dns/packet.rb', line 249 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 @authority.size == 0 retval += "\n" section = (@header.opCode == "UPDATE") ? "UPDATE" : "AUTHORITY" retval += ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '' : 's'}):\n" @authority.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
Chacks whether a query has returned a NXDOMAIN error, meaning the domain name queried doesn’t exists.
%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
481 482 483 |
# File 'lib/net/dns/packet.rb', line 481 def nxdomain? header.rCode == Net::DNS::Header::NAME end |
#query? ⇒ Boolean
Checks if the packet is a QUERY packet
158 159 160 |
# File 'lib/net/dns/packet.rb', line 158 def query? @header.opCode == Net::DNS::Header::QUERY end |
#size ⇒ Object
Returns the packet size in bytes
Resolver("www.google.com") do |packet|
puts packet.size + " bytes"}
end
#=> 484 bytes
467 468 469 |
# File 'lib/net/dns/packet.rb', line 467 def size data.size end |
#truncated? ⇒ Boolean
Wrapper to Header#truncated?
297 298 299 |
# File 'lib/net/dns/packet.rb', line 297 def truncated? @header.truncated? end |