Class: Dnsruby::RR::NSEC3
- Inherits:
-
Dnsruby::RR
- Object
- Dnsruby::RR
- Dnsruby::RR::NSEC3
- Defined in:
- lib/dnsruby/resource/NSEC3.rb
Overview
The NSEC3 Resource Record (RR) provides authenticated denial of existence for DNS Resource Record Sets.
The NSEC3 RR lists RR types present at the original owner name of the NSEC3 RR. It includes the next hashed owner name in the hash order of the zone. The complete set of NSEC3 RRs in a zone indicates which RRSets exist for the original owner name of the RR and form a chain of hashed owner names in the zone. This information is used to provide authenticated denial of existence for DNS data. To provide protection against zone enumeration, the owner names used in the NSEC3 RR are cryptographic hashes of the original owner name prepended as a single label to the name of the zone. The NSEC3 RR indicates which hash function is used to construct the hash, which salt is used, and how many iterations of the hash function are performed over the original owner name.
Constant Summary collapse
Constants inherited from Dnsruby::RR
Instance Attribute Summary collapse
-
#flags ⇒ Object
The Flags field contains 8 one-bit flags that can be used to indicate different processing.
-
#hash_alg ⇒ Object
The Hash Algorithm field identifies the cryptographic hash algorithm used to construct the hash-value.
-
#hash_length ⇒ Object
The Hash Length field defines the length of the Next Hashed Owner Name field, ranging in value from 1 to 255 octets.
-
#iterations ⇒ Object
The Iterations field defines the number of additional times the hash function has been performed.
-
#next_hashed ⇒ Object
The Next Hashed Owner Name field contains the next hashed owner name in hash order.
-
#salt_length ⇒ Object
readonly
The Salt Length field defines the length of the Salt field in octets, ranging in value from 0 to 255.
-
#types ⇒ Object
The Type Bit Maps field identifies the RRset types that exist at the NSEC RR’s owner name.
Attributes inherited from Dnsruby::RR
#klass, #name, #rdata, #ttl, #type
Class Method Summary collapse
- .calculate_hash(name, iterations, salt, hash_alg) ⇒ Object
- .decode_next_hashed(input) ⇒ Object
-
.decode_rdata(msg) ⇒ Object
:nodoc: all.
- .decode_salt(input) ⇒ Object
- .encode_next_hashed(n) ⇒ Object
- .encode_salt(s) ⇒ Object
-
.h(x, hash_alg) ⇒ Object
:nodoc: all.
Instance Method Summary collapse
- #add_type(t) ⇒ Object
- #calculate_hash ⇒ Object
- #check_name_in_range(_name) ⇒ Object
- #check_name_in_wildcard_range(_name) ⇒ Object
- #decode_next_hashed(input) ⇒ Object
- #encode_next_hashed(n) ⇒ Object
-
#encode_rdata(msg, canonical = false) ⇒ Object
:nodoc: all.
-
#from_data(data) ⇒ Object
:nodoc: all.
- #from_string(input) ⇒ Object
-
#h(x) ⇒ Object
:nodoc: all.
-
#opt_out? ⇒ Boolean
If the Opt-Out flag is set, the NSEC3 record covers zero or more unsigned delegations.
-
#rdata_to_string ⇒ Object
:nodoc: all.
-
#salt ⇒ Object
The Salt field is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks.
- #salt=(s) ⇒ Object
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
#flags ⇒ Object
The Flags field contains 8 one-bit flags that can be used to indicate different processing. All undefined flags must be zero. The only flag defined by the NSEC3 specification is the Opt-Out flag.
71 72 73 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 71 def flags @flags end |
#hash_alg ⇒ Object
The Hash Algorithm field identifies the cryptographic hash algorithm used to construct the hash-value.
66 67 68 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 66 def hash_alg @hash_alg end |
#hash_length ⇒ Object
The Hash Length field defines the length of the Next Hashed Owner Name field, ranging in value from 1 to 255 octets.
83 84 85 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 83 def hash_length @hash_length end |
#iterations ⇒ Object
The Iterations field defines the number of additional times the hash function has been performed.
75 76 77 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 75 def iterations @iterations end |
#next_hashed ⇒ Object
The Next Hashed Owner Name field contains the next hashed owner name in hash order.
87 88 89 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 87 def next_hashed @next_hashed end |
#salt_length ⇒ Object (readonly)
The Salt Length field defines the length of the Salt field in octets, ranging in value from 0 to 255.
79 80 81 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 79 def salt_length @salt_length end |
#types ⇒ Object
The Type Bit Maps field identifies the RRset types that exist at the NSEC RR’s owner name
91 92 93 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 91 def types @types end |
Class Method Details
.calculate_hash(name, iterations, salt, hash_alg) ⇒ Object
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 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 107 def NSEC3.calculate_hash(name, iterations, salt, hash_alg) # RFC5155 # 5. Calculation of the Hash # Define H(x) to be the hash of x using the Hash Algorithm selected by # the NSEC3 RR, k to be the number of Iterations, and || to indicate # concatenation. Then define: # # IH(salt, x, 0) = H(x || salt), and # # IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k > 0 # # Then the calculated hash of an owner name is # # IH(salt, owner name, iterations), # # where the owner name is in the canonical form, defined as: # # The wire format of the owner name where: # # 1. The owner name is fully expanded (no DNS name compression) and # fully qualified; # 2. All uppercase US-ASCII letters are replaced by the corresponding # lowercase US-ASCII letters; # 3. If the owner name is a wildcard name, the owner name is in its # original unexpanded form, including the '*' label (no wildcard # substitution); # # This form is as defined in Section 6.2 of [RFC 4034]. # n = Name.create(name) out = n.canonical begin (iterations + 1).times { out = NSEC3.h(out + salt, hash_alg) } return Base32.encode32hex(out).downcase rescue ArgumentError TheLog.error("Unknown hash algorithm #{hash_alg} used for NSEC3 hash") return 'Unknown NSEC3 hash algorithm' end end |
.decode_next_hashed(input) ⇒ Object
247 248 249 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 247 def NSEC3.decode_next_hashed(input) return Base32.decode32hex(input) end |
.decode_rdata(msg) ⇒ Object
:nodoc: all
317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 317 def self.decode_rdata(msg) #:nodoc: all hash_alg, flags, iterations, salt_length = msg.get_unpack('ccnc') # Salt may be omitted salt = [] if salt_length > 0 salt = msg.get_bytes(salt_length) end hash_length, = msg.get_unpack('c') next_hashed = msg.get_bytes(hash_length) types = NSEC.decode_types(msg.get_bytes) return self.new( [hash_alg, flags, iterations, salt_length, salt, hash_length, next_hashed, types]) end |
.decode_salt(input) ⇒ Object
235 236 237 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 235 def NSEC3.decode_salt(input) input == '-' ? '' : [input].pack('H*') end |
.encode_next_hashed(n) ⇒ Object
255 256 257 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 255 def NSEC3.encode_next_hashed(n) return Base32.encode32hex(n).downcase end |
.encode_salt(s) ⇒ Object
239 240 241 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 239 def NSEC3.encode_salt(s) (!s || s.length == 0) ? '-' : s.unpack('H*')[0] end |
.h(x, hash_alg) ⇒ Object
:nodoc: all
153 154 155 156 157 158 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 153 def NSEC3.h(x, hash_alg) # :nodoc: all if Nsec3HashAlgorithms.SHA_1 == hash_alg return Digest::SHA1.digest(x) end raise ArgumentError.new('Unknown hash algorithm') end |
Instance Method Details
#add_type(t) ⇒ Object
178 179 180 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 178 def add_type(t) self.types = (@types + [t]) end |
#calculate_hash ⇒ Object
103 104 105 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 103 def calculate_hash NSEC3.calculate_hash(@name, @iterations, @salt, @hash_alg) end |
#check_name_in_range(_name) ⇒ Object
93 94 95 96 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 93 def check_name_in_range(_name) # @TODO@ Check if the name is covered by this record false end |
#check_name_in_wildcard_range(_name) ⇒ Object
98 99 100 101 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 98 def check_name_in_wildcard_range(_name) # @TODO@ Check if the name is covered by this record false end |
#decode_next_hashed(input) ⇒ Object
243 244 245 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 243 def decode_next_hashed(input) @next_hashed = NSEC3.decode_next_hashed(input) end |
#encode_next_hashed(n) ⇒ Object
251 252 253 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 251 def encode_next_hashed(n) return NSEC3.encode_next_hashed(n) end |
#encode_rdata(msg, canonical = false) ⇒ Object
:nodoc: all
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 300 def encode_rdata(msg, canonical=false) #:nodoc: all # s = salt() s = @salt sl = s.length if s == '-' sl = 0 end msg.put_pack('ccnc', @hash_alg.code, @flags, @iterations, sl) if sl > 0 msg.put_bytes(s) end msg.put_pack('c', @hash_length) msg.put_bytes(@next_hashed) types = NSEC.encode_types(self) msg.put_bytes(types) end |
#from_data(data) ⇒ Object
:nodoc: all
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 211 def from_data(data) #:nodoc: all hash_alg, flags, iterations, _salt_length, salt, hash_length, next_hashed, types = data self.hash_alg = hash_alg self.flags = flags self.iterations = iterations # self.salt_length=(salt_length) # self.salt=(salt) @salt = salt self.hash_length = hash_length self.next_hashed = next_hashed self.types = types end |
#from_string(input) ⇒ Object
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 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 259 def from_string(input) if input.length > 0 data = input.split self.hash_alg = (data[0]).to_i self.flags = (data[1]).to_i self.iterations = (data[2]).to_i self.salt = (data[3]) len = data[0].length + data[1].length + data[2].length + data[3].length + 4 # There may or may not be brackets around next_hashed if data[4] == '(' len += data[4].length + 1 end next_hashed_and_types = (input[len, input.length-len]) data2 = next_hashed_and_types.split() self.next_hashed = decode_next_hashed(data2[0]) self.hash_length = @next_hashed.length len2 = data2[0].length + 1 self.types = next_hashed_and_types[len2, next_hashed_and_types.length - len2] # self.types=data2[1] # # len = data[0].length + data[1].length + data[2].length + data[3].length + data[5].length + 7 # # self.types=(input[len, input.length-len]) end end |
#h(x) ⇒ Object
:nodoc: all
149 150 151 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 149 def h(x) # :nodoc: all NSEC3.h(x, @hash_alg) end |
#opt_out? ⇒ Boolean
If the Opt-Out flag is set, the NSEC3 record covers zero or more unsigned delegations.
193 194 195 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 193 def opt_out? @flags == OPT_OUT end |
#rdata_to_string ⇒ Object
:nodoc: all
286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 286 def rdata_to_string #:nodoc: all if @next_hashed type_strings = [] @types.each { |t| type_strings << t.string } # salt = NSEC3.encode_salt(@salt) salt = salt() # TODO: Remove this? next_hashed = encode_next_hashed(@next_hashed) types = type_strings.join(' ') "#{@hash_alg.code} #{@flags} #{@iterations} #{salt} ( #{next_hashed} #{types} )" else '' end end |
#salt ⇒ Object
The Salt field is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks.
226 227 228 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 226 def salt return NSEC3.encode_salt(@salt) end |
#salt=(s) ⇒ Object
230 231 232 233 |
# File 'lib/dnsruby/resource/NSEC3.rb', line 230 def salt=(s) @salt = NSEC3.decode_salt(s) @salt_length = @salt.length end |