class DNSMessage::Message

Message is the central class that most users of the API will use

Constants

HEADER_SIZE
NAME_POINTER
POINTER_MASK
QUERY
REPLY

Attributes

aa[RW]
additionals[RW]
ancount[R]
answers[RW]
arcount[R]
authority[RW]
id[RW]
nscount[R]
opcode[RW]
qdcount[R]
qr[RW]
questions[RW]
ra[RW]
rcode[RW]
rd[RW]
tc[RW]
z[RW]

Public Class Methods

new() click to toggle source
# File lib/dnsmessage/message.rb, line 16
def initialize
  @questions   = []
  @answers     = []
  @additionals = []
  @authority   = []
  @qdcount     = 0
  @ancount     = 0
  @nscount     = 0
  @arcount     = 0
  @id = @qr = @opcode = @aa = @tc = @rd = @ra = @z = @rcode = 0
end
parse(input) click to toggle source
# File lib/dnsmessage/message.rb, line 37
def self.parse(input)
  new.tap do |m|
    m.parse(input)
  end
end
reply_to(query) click to toggle source
# File lib/dnsmessage/message.rb, line 43
def self.reply_to(query)
  new.tap do |r|
    r.id = query.id
    r.qr = REPLY
    r.questions = query.questions
  end
end

Public Instance Methods

build() click to toggle source
# File lib/dnsmessage/message.rb, line 91
def build
  ptr = Pointer.new
  packet = build_header
  packet << build_questions(ptr, packet.size)
  packet << build_answers(ptr, packet.size)
  packet << build_authority(ptr, packet.size)
  packet << build_additionals(ptr, packet.size)
end
build_aa() click to toggle source
# File lib/dnsmessage/message.rb, line 121
def build_aa
  (@aa & 0x1) << 10
end
build_additionals(ptr, idx) click to toggle source
# File lib/dnsmessage/message.rb, line 161
def build_additionals(ptr, idx)
  build_record(ptr, idx, @additionals)
end
build_answers(ptr, idx) click to toggle source
# File lib/dnsmessage/message.rb, line 153
def build_answers(ptr, idx)
  build_record(ptr, idx, @answers)
end
build_authority(ptr, idx) click to toggle source
# File lib/dnsmessage/message.rb, line 157
def build_authority(ptr, idx)
  build_record(ptr, idx, @authority)
end
build_header() click to toggle source
# File lib/dnsmessage/message.rb, line 100
def build_header
  [@id, build_opts,
   @questions.length,
   @answers.length,
   @authority.length,
   @additionals.length].pack("n6")
end
build_opcode() click to toggle source
# File lib/dnsmessage/message.rb, line 117
def build_opcode
  (@opcode & 0xf) << 11
end
build_opts() click to toggle source
# File lib/dnsmessage/message.rb, line 108
def build_opts
  build_qr | build_opcode | build_aa | build_tc | build_rd | build_ra |
    build_z | build_rcode
end
build_qr() click to toggle source
# File lib/dnsmessage/message.rb, line 113
def build_qr
  (@qr & 0x1) << 15
end
build_questions(ptr, idx) click to toggle source
# File lib/dnsmessage/message.rb, line 145
def build_questions(ptr, idx)
  @questions.map do |q|
    q.build(ptr, idx).tap do |bytes|
      idx += bytes.length
    end
  end.join("")
end
build_ra() click to toggle source
# File lib/dnsmessage/message.rb, line 133
def build_ra
  (@ra & 0x1) << 7
end
build_rcode() click to toggle source
# File lib/dnsmessage/message.rb, line 141
def build_rcode
  (@rcode & 0xf)
end
build_rd() click to toggle source
# File lib/dnsmessage/message.rb, line 129
def build_rd
  (@rd & 0x1) << 8
end
build_record(ptr, idx, records) click to toggle source
# File lib/dnsmessage/message.rb, line 165
def build_record(ptr, idx, records)
  records.map do |rr|
    rr.build(ptr, idx).tap do |r|
      idx += r.length
    end
  end.join("")
end
build_tc() click to toggle source
# File lib/dnsmessage/message.rb, line 125
def build_tc
  (@tc & 0x1) << 9
end
build_z() click to toggle source
# File lib/dnsmessage/message.rb, line 137
def build_z
  (@z & 0x1) << 7
end
check_validity() click to toggle source
# File lib/dnsmessage/message.rb, line 173
def check_validity
  raise(StandardError, "Bad qr type") if @qr != 0
  raise(StandardError, "No questions in query") if @qdcount < 1
  raise(StandardError, "Empty domain")  if @domain_name.empty?
end
parse(input) click to toggle source
# File lib/dnsmessage/message.rb, line 28
def parse(input)
  ptr = Pointer.new
  parse_header(input)
  idx = parse_questions(input, @qdcount, ptr)
  @answers, idx = parse_records(input, @ancount, idx, ptr)
  @authority, idx = parse_records(input, @nscount, idx, ptr)
  @additionals, = parse_records(input, @arcount, idx, ptr)
end
parse_header(message) click to toggle source
# File lib/dnsmessage/message.rb, line 51
def parse_header(message)
  return nil if message.nil? || message.empty?

  @id, opts, @qdcount, @ancount, @nscount, @arcount =
    message[0...12].unpack("n6")

  parse_opts(opts)
end
parse_opts(opts) click to toggle source
# File lib/dnsmessage/message.rb, line 60
def parse_opts(opts)
  @qr     = (opts >> 15) & 0x1
  @opcode = (opts >> 11) & 0xf
  @aa     = (opts >> 10) & 0x1
  @tc     = (opts >>  9) & 0x1
  @rd     = (opts >>  8) & 0x1
  @ra     = (opts >>  7) & 0x1
  @z      = (opts >>  4) & 0x7
  @rcode  =  opts        & 0xf
end
parse_questions(message, num_questions, ptr) click to toggle source
# File lib/dnsmessage/message.rb, line 71
def parse_questions(message, num_questions, ptr)
  idx = HEADER_SIZE # Header takes up the first 12 bytes
  @questions = (0...num_questions).map do
    Question.parse(message, ptr, idx).tap do |q|
      idx += q.size
    end
  end
  idx
end
parse_records(message, num_records, idx, ptr) click to toggle source
# File lib/dnsmessage/message.rb, line 81
def parse_records(message, num_records, idx, ptr)
  [num_records.times.map do
    ResourceRecord.parse(message[idx..], ptr).tap do |rr|
      ptr.add_arr(rr.add_to_hash, idx)
      idx += rr.size
    end
  end,
   idx]
end