Class: Dnsruby::RR::NSEC

Inherits:
Dnsruby::RR show all
Defined in:
lib/dnsruby/resource/NSEC.rb

Overview

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].

Constant Summary collapse

ClassValue =

:nodoc: all

nil
TypeValue =

:nodoc: all

Types::NSEC

Constants inherited from Dnsruby::RR

ClassInsensitiveTypes

Instance Attribute Summary collapse

Attributes inherited from Dnsruby::RR

#klass, #name, #rdata, #ttl, #type

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Dnsruby::RR

#<=>, #==, #clone, create, #eql?, find_class, #from_hash, get_class, get_num, #hash, implemented_rrs, #init_defaults, new_from_data, new_from_hash, new_from_string, #rdlength, #sameRRset, #to_s

Instance Attribute Details

#next_domainObject

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



35
36
37
# File 'lib/dnsruby/resource/NSEC.rb', line 35

def next_domain
  @next_domain
end

#typesObject

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



38
39
40
# File 'lib/dnsruby/resource/NSEC.rb', line 38

def types
  @types
end

Class Method Details

.decode_rdata(msg) ⇒ Object

:nodoc: all



268
269
270
271
272
# File 'lib/dnsruby/resource/NSEC.rb', line 268

def self.decode_rdata(msg) #:nodoc: all
  next_domain = msg.get_name
  types = decode_types(msg.get_bytes)
  return self.new([next_domain, types])
end

.decode_types(bytes) ⇒ Object



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
# File 'lib/dnsruby/resource/NSEC.rb', line 89

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
        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.
            unless [Types::OPT, Types::TSIG].include?(type)
              types << type
            end
          end
        end
      end
      index += 1
    end
  end
  return types
end

.encode_types(nsec) ⇒ Object



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
# File 'lib/dnsruby/resource/NSEC.rb', line 154

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 { |type| type_codes << type.code }
  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 << type_codes[0]
      #  And delete them from type_codes
      type_codes = type_codes.last(type_codes.length - 1)
      break if type_codes.empty?
    end

    unless 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
      output << (' ' * (2 + bitmap.length))

      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
  output
end

.get_types(t) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/dnsruby/resource/NSEC.rb', line 67

def self.get_types(t)
  if t.instance_of?(Array)
    #  from the wire, already decoded
    types = t
  elsif t.instance_of?(String)
    if (index = t.index(/[;)]/)) # check for ; or )
      t = t[0, index]
    end
    #  List of mnemonics
    types = []
    mnemonics = t.split(' ')
    mnemonics.each { |m| types << Types.new(m) }
  else
    raise DecodeError.new('Unknown format of types for Dnsruby::RR::NSEC')
  end
  types
end

Instance Method Details

#add_type(t) ⇒ Object



85
86
87
# File 'lib/dnsruby/resource/NSEC.rb', line 85

def add_type(t)
  self.types = (@types + [t])
end

#check_name_in_range(n) ⇒ Object



45
46
47
48
49
50
# File 'lib/dnsruby/resource/NSEC.rb', line 45

def check_name_in_range(n)
  #  Check if the name is covered by this record
  @name.wild? \
      ? check_name_in_wildcard_range(n) \
      : name.canonically_before(n) && n.canonically_before(next_domain)
end

#check_name_in_wildcard_range(n) ⇒ Object



52
53
54
55
56
57
58
59
60
61
# File 'lib/dnsruby/resource/NSEC.rb', line 52

def check_name_in_wildcard_range(n)
  #   Check if the name is covered by this record
  return false unless @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)
  ! n.canonically_before(n2)
end

#encode_rdata(msg, canonical = false) ⇒ Object

:nodoc: all



261
262
263
264
265
266
# File 'lib/dnsruby/resource/NSEC.rb', line 261

def encode_rdata(msg, canonical=false) #:nodoc: all
  #  Canonical
  msg.put_name(@next_domain, canonical, false) # dnssec-bis-updates says NSEC should not be downcased
  types = encode_types
  msg.put_bytes(types)
end

#encode_typesObject



150
151
152
# File 'lib/dnsruby/resource/NSEC.rb', line 150

def encode_types
  NSEC.encode_types(self)
end

#from_data(data) ⇒ Object

:nodoc: all



231
232
233
234
235
# File 'lib/dnsruby/resource/NSEC.rb', line 231

def from_data(data) #:nodoc: all
  next_domain, types = data
  self.next_domain = next_domain
  self.types = types
end

#from_string(input) ⇒ Object



237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/dnsruby/resource/NSEC.rb', line 237

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 += data[1].length
    end
    self.types = input[len, input.length-len]
    @types = NSEC.get_types(input[len, input.length-len])
  end
end

#rdata_to_stringObject

:nodoc: all



250
251
252
253
254
255
256
257
258
259
# File 'lib/dnsruby/resource/NSEC.rb', line 250

def rdata_to_string #:nodoc: all
  if @next_domain
    type_strings = []
    @types.each { |t| type_strings << t.string }
    types = type_strings.join(' ')
    "#{@next_domain.to_s(true)} ( #{types} )"
  else
    ''
  end
end