class Dnsruby::RR::NSEC

RFC4034, section 4 The NSEC resource record lists two separate things: the next owner name (in the canonical ordering of the zone) that contains authoritative data or a delegation point NS RRset, and the set of RR types present at the NSEC RR's owner name [RFC3845]. The complete set of NSEC RRs in a zone indicates which authoritative RRsets exist in a zone and also form a chain of authoritative owner names in the zone. This information is used to provide authenticated denial of existence for DNS data, as described in [RFC4035].

Attributes

next_domain[R]

The next name which exists after this NSEC The Next Domain field contains the next owner name (in the canonical ordering of the zone) that has authoritative data or contains a delegation point NS RRset

types[R]

The Type Bit Maps field identifies the RRset types that exist at the NSEC RR's owner name

Public Class Methods

decode_types(bytes) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 105
def self.decode_types(bytes)
  types = []
  #RFC4034 section 4.1.2

  #The RR type space is split into 256 window blocks, each representing

  #the low-order 8 bits of the 16-bit RR type space.  Each block that

  #has at least one active RR type is encoded using a single octet

  #window number (from 0 to 255), a single octet bitmap length (from 1

  #to 32) indicating the number of octets used for the window block's

  #bitmap, and up to 32 octets (256 bits) of bitmap.


  #Blocks are present in the NSEC RR RDATA in increasing numerical

  #order.


  #  Type Bit Maps Field = ( Window Block # | Bitmap Length | Bitmap )+


  #  where "|" denotes concatenation.

 
  pos = 0
  while (pos < bytes.length)
    #So, read the first two octets

    if (bytes.length-pos < 2)
      raise DecodeError.new("NSEC : Expected window number and bitmap length octets")
    end
    window_number = bytes[pos]
    bitmap_length = bytes[pos+1]
    if (window_number.class == String) # Ruby 1.9

      window_number = window_number.getbyte(0)
      bitmap_length = bitmap_length.getbyte(0)
    end
    pos += 2
    bitmap = bytes[pos,bitmap_length]
    pos += bitmap_length
    #Each bitmap encodes the low-order 8 bits of RR types within the

    #window block, in network bit order.  The first bit is bit 0.  For

    #window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds

    #to RR type 2 (NS), and so forth.  For window block 1, bit 1

    #corresponds to RR type 257, and bit 2 to RR type 258.  If a bit is

    #set, it indicates that an RRset of that type is present for the NSEC

    #RR's owner name.  If a bit is clear, it indicates that no RRset of

    #that type is present for the NSEC RR's owner name.

    index = 0
    bitmap.each_byte do |char|
      if char.to_i != 0
        # decode these RR types

        0..8.times do |i|
          if (((1 << (7-i)) & char) == (1 << (7-i)))
            type = Types.new((256 * window_number) + (8 * index) + i)
            #Bits representing pseudo-types MUST be clear, as they do not appear

            #in zone data.  If encountered, they MUST be ignored upon being read.

            if (!([Types::OPT, Types::TSIG].include?(type)))
              types.push(type)
            end
          end               
        end
      end
      index += 1
    end
  end
  return types
end
encode_types(nsec) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 170
def self.encode_types(nsec)
  output=""
  #types represents all 65536 possible RR types.

  #Split up types into sets of 256 different types.

  type_codes = []
  nsec.types.each do |type|
    type_codes.push(type.code)
  end
  type_codes.sort!
  window = -1
  0.step(65536,256) { |step|
    # Gather up the RR types for this set of 256

    types_to_go = []
    while (!type_codes.empty? && type_codes[0] < step)
      types_to_go.push(type_codes[0])
      # And delete them from type_codes

      type_codes=type_codes.last(type_codes.length-1)
      break if (type_codes.empty?)
    end
    
    if (!types_to_go.empty?)
      # Then create the bitmap for them

      bitmap=""
      # keep on adding them until there's none left

      pos = 0
      bitmap_pos = 0
      while (!types_to_go.empty?)
        
        # Check the next eight

        byte = 0
        pos += 8
        while (types_to_go[0] < pos + step-256)
          byte = byte | (1 << (pos-1-(types_to_go[0] - (step-256) )))
          # Add it to the list

          # And remove it from the to_go queue

          types_to_go =types_to_go.last(types_to_go.length-1)
          break if (types_to_go.empty?)
        end
        bitmap += " "
        if (bitmap[bitmap_pos].class == String)
          bitmap.setbyte(bitmap_pos, byte) # Ruby 1.9

        else
          bitmap[bitmap_pos]=byte              
        end
        bitmap_pos+=1
      end
      
      # Now add data to output bytes

      start = output.length
      (2+bitmap.length).times do 
        output += " "
      end
    
      if (output[start].class == String)
        output.setbyte(start, window)
        output.setbyte(start+1, bitmap.length)
        bitmap.length.times do |i|
          output.setbyte(start+2+i, bitmap[i].getbyte(0))
        end
      else
        output[start] = window
        output[start+1] = bitmap.length
        bitmap.length.times do |i|
          output[start+2+i] = bitmap[i]
        end
      end
    end
    window += 1
    
    # Are there any more types after this?

    if (type_codes.empty?)
      # If not, then break (so we don't add more zeros)

      break
    end
  }
  if (output[0].class == String)
    output = output.force_encoding("ascii-8bit")
  end
  return output
end
get_types(t) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 76
def self.get_types(t)
  types = nil
  if (t.instance_of?Array)
    # from the wire, already decoded

    types =t
  elsif (t.instance_of?String)
    if (index = t.index";")
      t = t[0, index]
    end
    if (index = t.index")")
      t = t[0, index]
    end
    # List of mnemonics

    types=[]
    mnemonics = t.split(" ")
    mnemonics.each do |m|
      type = Types.new(m)
      types.push(type)
    end
  else
    raise DecodeError.new("Unknown format of types for Dnsruby::RR::NSEC")
  end
  return types
end

Public Instance Methods

add_type(t) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 101
def add_type(t)
  self.types=(@types + [t])
end
check_name_in_range(n) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 45
def check_name_in_range(n)
  # Check if the name is covered by this record

  if (@name.wild?)
    return check_name_in_wildcard_range(n)
  end
  if (name.canonically_before(n) && (n.canonically_before(next_domain)))
    return true
  end
  return false
end
check_name_in_wildcard_range(n) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 56
def check_name_in_wildcard_range(n)
  #  Check if the name is covered by this record

  return false if !@name.wild?
  return false if @next_domain.canonically_before(n)
  # Now just check that the wildcard is *before* the name

  # Strip the first label ("*") and then compare

  n2 = Name.create(@name)
  n2.labels.delete_at(0)
  return false if n.canonically_before(n2)
  return true
end
encode_types() click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 166
def encode_types
  NSEC.encode_types(self)
end
from_string(input) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 257
def from_string(input)
  if (input.length > 0)
    data = input.split(" ")
    self.next_domain=(data[0])
    len = data[0].length+ 1
    if (data[1] == "(")
      len = len + data[1].length
    end
    self.types=(input[len, input.length-len])
    @types = NSEC.get_types(input[len, input.length-len])
  end
end
next_domain=(n) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 40
def next_domain=(n)
  nxt = Name.create(n)
  @next_domain = nxt
end
types=(t) click to toggle source
# File lib/Dnsruby/resource/NSEC.rb, line 68
def types=(t)
  if (t && t.length > 0)
  @types = NSEC.get_types(t)
  else
    @types = []
  end
end