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



290
291
292
293
294
295
# File 'lib/Dnsruby/resource/NSEC.rb', line 290

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



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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# 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) ⇒ Object



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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# 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) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 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

Instance Method Details

#add_type(t) ⇒ Object



101
102
103
# File 'lib/Dnsruby/resource/NSEC.rb', line 101

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

#check_name_in_range(n) ⇒ Object



45
46
47
48
49
50
51
52
53
54
# 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) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
# 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_rdata(msg, canonical = false) ⇒ Object

:nodoc: all



283
284
285
286
287
288
# File 'lib/Dnsruby/resource/NSEC.rb', line 283

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



166
167
168
# File 'lib/Dnsruby/resource/NSEC.rb', line 166

def encode_types
  NSEC.encode_types(self)
end

#from_data(data) ⇒ Object

:nodoc: all



251
252
253
254
255
# File 'lib/Dnsruby/resource/NSEC.rb', line 251

def from_data(data) #:nodoc: all

  next_domain, types = data
  self.next_domain=(next_domain)
  self.types=(types)
end

#from_string(input) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
# 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

#rdata_to_stringObject

:nodoc: all



270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/Dnsruby/resource/NSEC.rb', line 270

def rdata_to_string #:nodoc: all

  if (@next_domain!=nil)
    type_strings = []
    @types.each do |t|
      type_strings.push(t.string)
    end
    types = type_strings.join(" ")
    return "#{@next_domain.to_s(true)} ( #{types} )"
  else
    return ""
  end
end