dnsruby 1.30 → 1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EXAMPLES +9 -5
- data/demo/digdlv.rb +1 -0
- data/demo/digitar.rb +1 -0
- data/html/created.rid +1 -1
- data/html/fr_class_index.html +6 -2
- data/html/fr_method_index.html +275 -273
- data/lib/Dnsruby/Cache.rb +2 -2
- data/lib/Dnsruby/Recursor.rb +42 -42
- data/lib/Dnsruby/dnssec.rb +1 -1
- data/lib/Dnsruby/message.rb +10 -0
- data/lib/Dnsruby/name.rb +19 -0
- data/lib/Dnsruby/resource/DNSKEY.rb +10 -2
- data/lib/Dnsruby/resource/NSEC.rb +4 -1
- data/lib/Dnsruby/resource/NSEC3.rb +113 -32
- data/lib/Dnsruby/resource/NSEC3PARAM.rb +33 -20
- data/lib/Dnsruby/resource/RRSIG.rb +6 -0
- data/lib/Dnsruby/resource/resource.rb +13 -2
- data/lib/Dnsruby/select_thread.rb +1 -2
- data/lib/Dnsruby/single_verifier.rb +2 -4
- data/lib/Dnsruby/update.rb +2 -2
- data/lib/dnsruby.rb +39 -1
- data/test/tc_dnskey.rb +5 -0
- data/test/tc_nsec.rb +5 -0
- data/test/tc_nsec3.rb +37 -12
- data/test/tc_nsec3param.rb +9 -1
- data/test/tc_rrsig.rb +5 -0
- data/test/tc_tkey.rb +1 -0
- metadata +2 -2
    
        data/lib/Dnsruby/Cache.rb
    CHANGED
    
    | @@ -66,7 +66,7 @@ module Dnsruby | |
| 66 66 | 
             
                    @cache.delete(key)
         | 
| 67 67 | 
             
                  }
         | 
| 68 68 | 
             
                end
         | 
| 69 | 
            -
                class CacheKey
         | 
| 69 | 
            +
                class CacheKey # :nodoc: all
         | 
| 70 70 | 
             
                  attr_accessor :qname, :qtype, :qclass
         | 
| 71 71 | 
             
                  def initialize(*args)
         | 
| 72 72 | 
             
                    self.qclass = Classes.IN
         | 
| @@ -85,7 +85,7 @@ module Dnsruby | |
| 85 85 | 
             
                    return "#{qname.inspect.downcase} #{qclass} #{qtype}"
         | 
| 86 86 | 
             
                  end
         | 
| 87 87 | 
             
                end
         | 
| 88 | 
            -
                class CacheData
         | 
| 88 | 
            +
                class CacheData # :nodoc: all
         | 
| 89 89 | 
             
                  attr_reader :expiration
         | 
| 90 90 | 
             
                  def message=(m)
         | 
| 91 91 | 
             
                    @expiration = get_expiration(m)
         | 
    
        data/lib/Dnsruby/Recursor.rb
    CHANGED
    
    | @@ -14,48 +14,6 @@ | |
| 14 14 | 
             
            #limitations under the License.
         | 
| 15 15 | 
             
            #++
         | 
| 16 16 | 
             
            module Dnsruby
         | 
| 17 | 
            -
              class Recursor
         | 
| 18 | 
            -
                class AddressCache # :nodoc: all
         | 
| 19 | 
            -
                  # Like an array, but stores the expiration of each record.
         | 
| 20 | 
            -
                  def initialize(*args)
         | 
| 21 | 
            -
                    @hash = Hash.new # stores addresses against their expiration
         | 
| 22 | 
            -
                    @mutex = Mutex.new # This class is thread-safe
         | 
| 23 | 
            -
                  end
         | 
| 24 | 
            -
                  def push(item)
         | 
| 25 | 
            -
                    address, ttl = item
         | 
| 26 | 
            -
                    expiration = Time.now + ttl
         | 
| 27 | 
            -
                    @mutex.synchronize {
         | 
| 28 | 
            -
                      @hash[address] = expiration
         | 
| 29 | 
            -
                    }
         | 
| 30 | 
            -
                  end
         | 
| 31 | 
            -
                  def values
         | 
| 32 | 
            -
                    ret =[]
         | 
| 33 | 
            -
                    keys_to_delete = []
         | 
| 34 | 
            -
                    @mutex.synchronize {
         | 
| 35 | 
            -
                      @hash.keys.each {|address|
         | 
| 36 | 
            -
                        if (@hash[address] > Time.now)
         | 
| 37 | 
            -
                          ret.push(address)
         | 
| 38 | 
            -
                        else
         | 
| 39 | 
            -
                          keys_to_delete.push(address)
         | 
| 40 | 
            -
                        end
         | 
| 41 | 
            -
                      }
         | 
| 42 | 
            -
                      keys_to_delete.each {|key|
         | 
| 43 | 
            -
                        @hash.delete(key)
         | 
| 44 | 
            -
                      }
         | 
| 45 | 
            -
                    }
         | 
| 46 | 
            -
                    return ret
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
                  def length
         | 
| 49 | 
            -
                    @mutex.synchronize {
         | 
| 50 | 
            -
                      return @hash.length
         | 
| 51 | 
            -
                    }
         | 
| 52 | 
            -
                  end
         | 
| 53 | 
            -
                  def each()
         | 
| 54 | 
            -
                    values.each {|v|
         | 
| 55 | 
            -
                      yield v
         | 
| 56 | 
            -
                    }
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
                end
         | 
| 59 17 | 
             
                #Dnsruby::Recursor - Perform recursive dns lookups
         | 
| 60 18 | 
             
                #
         | 
| 61 19 | 
             
                #  require 'Dnsruby'
         | 
| @@ -152,6 +110,48 @@ module Dnsruby | |
| 152 110 | 
             
                #;; Received 135 bytes from 139.134.2.18#53(sy-dns02.tmns.net.au) in 525 ms
         | 
| 153 111 | 
             
                #  ;;; FINALLY, THE ANSWER!
         | 
| 154 112 | 
             
                # Now,DNSSEC validation is performed (unless disabled).
         | 
| 113 | 
            +
              class Recursor
         | 
| 114 | 
            +
                class AddressCache # :nodoc: all
         | 
| 115 | 
            +
                  # Like an array, but stores the expiration of each record.
         | 
| 116 | 
            +
                  def initialize(*args)
         | 
| 117 | 
            +
                    @hash = Hash.new # stores addresses against their expiration
         | 
| 118 | 
            +
                    @mutex = Mutex.new # This class is thread-safe
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                  def push(item)
         | 
| 121 | 
            +
                    address, ttl = item
         | 
| 122 | 
            +
                    expiration = Time.now + ttl
         | 
| 123 | 
            +
                    @mutex.synchronize {
         | 
| 124 | 
            +
                      @hash[address] = expiration
         | 
| 125 | 
            +
                    }
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
                  def values
         | 
| 128 | 
            +
                    ret =[]
         | 
| 129 | 
            +
                    keys_to_delete = []
         | 
| 130 | 
            +
                    @mutex.synchronize {
         | 
| 131 | 
            +
                      @hash.keys.each {|address|
         | 
| 132 | 
            +
                        if (@hash[address] > Time.now)
         | 
| 133 | 
            +
                          ret.push(address)
         | 
| 134 | 
            +
                        else
         | 
| 135 | 
            +
                          keys_to_delete.push(address)
         | 
| 136 | 
            +
                        end
         | 
| 137 | 
            +
                      }
         | 
| 138 | 
            +
                      keys_to_delete.each {|key|
         | 
| 139 | 
            +
                        @hash.delete(key)
         | 
| 140 | 
            +
                      }
         | 
| 141 | 
            +
                    }
         | 
| 142 | 
            +
                    return ret
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  def length
         | 
| 145 | 
            +
                    @mutex.synchronize {
         | 
| 146 | 
            +
                      return @hash.length
         | 
| 147 | 
            +
                    }
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
                  def each()
         | 
| 150 | 
            +
                    values.each {|v|
         | 
| 151 | 
            +
                      yield v
         | 
| 152 | 
            +
                    }
         | 
| 153 | 
            +
                  end
         | 
| 154 | 
            +
                end
         | 
| 155 155 | 
             
                attr_accessor :nameservers, :callback, :recurse, :ipv6_ok
         | 
| 156 156 | 
             
                attr_reader :hints
         | 
| 157 157 | 
             
                # The resolver to use for the queries
         | 
    
        data/lib/Dnsruby/dnssec.rb
    CHANGED
    
    | @@ -149,7 +149,7 @@ module Dnsruby | |
| 149 149 |  | 
| 150 150 |  | 
| 151 151 | 
             
                @@do_validation_with_recursor = true # Many nameservers don't handle DNSSEC correctly yet
         | 
| 152 | 
            -
                @@default_resolver =  | 
| 152 | 
            +
                @@default_resolver = Resolver.new
         | 
| 153 153 | 
             
                # This method defines the choice of Resolver or Recursor, when the validator
         | 
| 154 154 | 
             
                # is checking responses.
         | 
| 155 155 | 
             
                # If set to true, then a Recursor will be used to query for the DNSSEC records.
         | 
    
        data/lib/Dnsruby/message.rb
    CHANGED
    
    | @@ -282,6 +282,16 @@ module Dnsruby | |
| 282 282 | 
             
                    exception = NotImp.new
         | 
| 283 283 | 
             
                  elsif (rcode==RCode.REFUSED)
         | 
| 284 284 | 
             
                    exception = Refused.new
         | 
| 285 | 
            +
                  elsif (rcode==RCode.NOTZONE)
         | 
| 286 | 
            +
                    exception = NotZone.new
         | 
| 287 | 
            +
                  elsif (rcode==RCode.NOTAUTH)
         | 
| 288 | 
            +
                    exception = NotAuth.new
         | 
| 289 | 
            +
                  elsif (rcode==RCode.NXRRSET)
         | 
| 290 | 
            +
                    exception = NXRRSet.new
         | 
| 291 | 
            +
                  elsif (rcode==RCode.YXRRSET)
         | 
| 292 | 
            +
                    exception = YXRRSet.new
         | 
| 293 | 
            +
                  elsif (rcode==RCode.YXDOMAIN)
         | 
| 294 | 
            +
                    exception = YXDomain.new
         | 
| 285 295 | 
             
                  elsif (rcode >= RCode.BADSIG && rcode <= RCode.BADALG)
         | 
| 286 296 | 
             
                    return VerifyError.new # @TODO@
         | 
| 287 297 | 
             
                  end
         | 
    
        data/lib/Dnsruby/name.rb
    CHANGED
    
    | @@ -28,6 +28,7 @@ module Dnsruby | |
| 28 28 | 
             
              #* Name#labels
         | 
| 29 29 | 
             
              #
         | 
| 30 30 | 
             
              class Name
         | 
| 31 | 
            +
                include Comparable
         | 
| 31 32 | 
             
                MaxNameLength=255
         | 
| 32 33 | 
             
                #--
         | 
| 33 34 | 
             
                # A Name is a collection of Labels. Each label is presentation-formatted
         | 
| @@ -116,6 +117,24 @@ module Dnsruby | |
| 116 117 | 
             
                  return (labels[0].string == '*')
         | 
| 117 118 | 
             
                end
         | 
| 118 119 |  | 
| 120 | 
            +
                # Return the canonical form of this name (RFC 4034 section 6.2)
         | 
| 121 | 
            +
                def canonical
         | 
| 122 | 
            +
                  #
         | 
| 123 | 
            +
                  return MessageEncoder.new {|msg|
         | 
| 124 | 
            +
                          msg.put_name(self, true)
         | 
| 125 | 
            +
                  }.to_s
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                def <=>(other)
         | 
| 130 | 
            +
                  # return -1 if other less than us, +1 if greater than us
         | 
| 131 | 
            +
                  return 0 if (canonical == other.canonical)
         | 
| 132 | 
            +
                  if (canonically_before(other))
         | 
| 133 | 
            +
                    return +1
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
                  return -1
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 119 138 | 
             
                def canonically_before(n)
         | 
| 120 139 | 
             
                  if (!(Name === n))
         | 
| 121 140 | 
             
                    n = Name.create(n)
         | 
| @@ -52,6 +52,7 @@ module Dnsruby | |
| 52 52 | 
             
                    self.protocol=3
         | 
| 53 53 | 
             
                    self.flags=ZONE_KEY
         | 
| 54 54 | 
             
                    @algorithm=Algorithms.RSASHA1
         | 
| 55 | 
            +
                    @public_key = nil
         | 
| 55 56 | 
             
                  end
         | 
| 56 57 |  | 
| 57 58 | 
             
                  def protocol=(p)
         | 
| @@ -149,6 +150,7 @@ module Dnsruby | |
| 149 150 | 
             
                      # until we come to " )" at the end, and then gsub
         | 
| 150 151 | 
             
                      # the white space out
         | 
| 151 152 | 
             
                      # Also, brackets may or may not be present
         | 
| 153 | 
            +
                      # Not to mention comments! ";"
         | 
| 152 154 | 
             
                      buf = ""
         | 
| 153 155 | 
             
                      index = 3
         | 
| 154 156 | 
             
                      end_index = data.length - 1
         | 
| @@ -157,7 +159,13 @@ module Dnsruby | |
| 157 159 | 
             
                        index = 4
         | 
| 158 160 | 
             
                      end
         | 
| 159 161 | 
             
                      (index..end_index).each {|i|
         | 
| 160 | 
            -
                         | 
| 162 | 
            +
                        if (comment_index = data[i].index(";"))
         | 
| 163 | 
            +
                          buf += data[i].slice(0, comment_index)
         | 
| 164 | 
            +
                          # @TODO@ We lose the comments here - we should really keep them for when we write back to string format?
         | 
| 165 | 
            +
                          break
         | 
| 166 | 
            +
                        else
         | 
| 167 | 
            +
                          buf += data[i]
         | 
| 168 | 
            +
                        end
         | 
| 161 169 | 
             
                      }
         | 
| 162 170 | 
             
                      self.key=(buf)
         | 
| 163 171 | 
             
                    end
         | 
| @@ -238,7 +246,7 @@ module Dnsruby | |
| 238 246 | 
             
                  end
         | 
| 239 247 |  | 
| 240 248 | 
             
                  def public_key
         | 
| 241 | 
            -
                    if ( | 
| 249 | 
            +
                    if (!@public_key)
         | 
| 242 250 | 
             
                      if [Algorithms.RSASHA1,
         | 
| 243 251 | 
             
                          Algorithms.RSASHA1_NSEC3_SHA1].include?(@algorithm)
         | 
| 244 252 | 
             
                        @public_key = rsa_key
         | 
| @@ -75,6 +75,9 @@ module Dnsruby | |
| 75 75 | 
             
                      # from the wire, already decoded
         | 
| 76 76 | 
             
                      types =t
         | 
| 77 77 | 
             
                    elsif (t.instance_of?String)
         | 
| 78 | 
            +
                      if t[t.length-1, t.length]!=")"
         | 
| 79 | 
            +
                        t = t + " )"
         | 
| 80 | 
            +
                      end
         | 
| 78 81 | 
             
                      # List of mnemonics
         | 
| 79 82 | 
             
                      types=[]
         | 
| 80 83 | 
             
                      mnemonics = t.split(" ")
         | 
| @@ -171,7 +174,7 @@ module Dnsruby | |
| 171 174 | 
             
                    0.step(65536,256) { |step|
         | 
| 172 175 | 
             
                      # Gather up the RR types for this set of 256
         | 
| 173 176 | 
             
                      types_to_go = []
         | 
| 174 | 
            -
                      while (type_codes[0] < step)
         | 
| 177 | 
            +
                      while (!type_codes.empty? && type_codes[0] < step)
         | 
| 175 178 | 
             
                        types_to_go.push(type_codes[0])
         | 
| 176 179 | 
             
                        # And delete them from type_codes
         | 
| 177 180 | 
             
                        type_codes=type_codes.last(type_codes.length-1)
         | 
| @@ -13,6 +13,7 @@ | |
| 13 13 | 
             
            #See the License for the specific language governing permissions and 
         | 
| 14 14 | 
             
            #limitations under the License.
         | 
| 15 15 | 
             
            #++
         | 
| 16 | 
            +
            require 'digest/sha1'
         | 
| 16 17 | 
             
            module Base32
         | 
| 17 18 | 
             
              module_function
         | 
| 18 19 | 
             
              def encode32hex(str)
         | 
| @@ -73,9 +74,6 @@ module Dnsruby | |
| 73 74 | 
             
                  #The Salt Length field defines the length of the Salt field in octets,
         | 
| 74 75 | 
             
                  #ranging in value from 0 to 255.
         | 
| 75 76 | 
             
                  attr_reader :salt_length
         | 
| 76 | 
            -
                  #The Salt field is appended to the original owner name before hashing
         | 
| 77 | 
            -
                  #in order to defend against pre-calculated dictionary attacks.
         | 
| 78 | 
            -
                  attr_accessor :salt
         | 
| 79 77 | 
             
                  #The Hash Length field defines the length of the Next Hashed Owner
         | 
| 80 78 | 
             
                  #Name field, ranging in value from 1 to 255 octets.
         | 
| 81 79 | 
             
                  attr_reader :hash_length
         | 
| @@ -96,6 +94,61 @@ module Dnsruby | |
| 96 94 | 
             
                    return false
         | 
| 97 95 | 
             
                  end
         | 
| 98 96 |  | 
| 97 | 
            +
                  def calculate_hash
         | 
| 98 | 
            +
                    return NSEC3.calculate_hash(@name, @iterations, @salt, @hash_alg)
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  def NSEC3.calculate_hash(name, iterations, salt, hash_alg)
         | 
| 102 | 
            +
                    # RFC5155
         | 
| 103 | 
            +
                    #5.  Calculation of the Hash
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                    #   Define H(x) to be the hash of x using the Hash Algorithm selected by
         | 
| 106 | 
            +
                    #   the NSEC3 RR, k to be the number of Iterations, and || to indicate
         | 
| 107 | 
            +
                    #   concatenation.  Then define:
         | 
| 108 | 
            +
                    #
         | 
| 109 | 
            +
                    #      IH(salt, x, 0) = H(x || salt), and
         | 
| 110 | 
            +
                    #
         | 
| 111 | 
            +
                    #      IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k > 0
         | 
| 112 | 
            +
                    #
         | 
| 113 | 
            +
                    #   Then the calculated hash of an owner name is
         | 
| 114 | 
            +
                    #
         | 
| 115 | 
            +
                    #      IH(salt, owner name, iterations),
         | 
| 116 | 
            +
                    #
         | 
| 117 | 
            +
                    #   where the owner name is in the canonical form, defined as:
         | 
| 118 | 
            +
                    #
         | 
| 119 | 
            +
                    #   The wire format of the owner name where:
         | 
| 120 | 
            +
                    #
         | 
| 121 | 
            +
                    #   1.  The owner name is fully expanded (no DNS name compression) and
         | 
| 122 | 
            +
                    #       fully qualified;
         | 
| 123 | 
            +
                    #   2.  All uppercase US-ASCII letters are replaced by the corresponding
         | 
| 124 | 
            +
                    #       lowercase US-ASCII letters;
         | 
| 125 | 
            +
                    #   3.  If the owner name is a wildcard name, the owner name is in its
         | 
| 126 | 
            +
                    #       original unexpanded form, including the "*" label (no wildcard
         | 
| 127 | 
            +
                    #       substitution);
         | 
| 128 | 
            +
                    #
         | 
| 129 | 
            +
                    #   This form is as defined in Section 6.2 of [RFC 4034].
         | 
| 130 | 
            +
                    #
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                    n = Name.create(name)
         | 
| 133 | 
            +
                    out = n.canonical
         | 
| 134 | 
            +
                    (0..iterations).each  {
         | 
| 135 | 
            +
                      out =NSEC3.h(out + salt, hash_alg);
         | 
| 136 | 
            +
                    }
         | 
| 137 | 
            +
                    return Base32.encode32hex(out).downcase
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  def h(x) # :nodoc: all
         | 
| 141 | 
            +
                    return NSEC3.h(x, @hash_alg)
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  def NSEC3.h(x, hash_alg) # :nodoc: all
         | 
| 145 | 
            +
                    if Nsec3HashAlgorithms.SHA_1 == hash_alg
         | 
| 146 | 
            +
                      return Digest::SHA1.digest(x)
         | 
| 147 | 
            +
                    end
         | 
| 148 | 
            +
                    TheLog.error("Unknown hash algorithm #{hash_alg} used for NSEC3 hash")
         | 
| 149 | 
            +
                    return "Unknown NSEC3 hash algorithm"
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
             | 
| 99 152 | 
             
                  def hash_alg=(a)
         | 
| 100 153 | 
             
                    if (a.instance_of?String)
         | 
| 101 154 | 
             
                      if (a.length == 1)
         | 
| @@ -103,7 +156,7 @@ module Dnsruby | |
| 103 156 | 
             
                      end
         | 
| 104 157 | 
             
                    end
         | 
| 105 158 | 
             
                    begin
         | 
| 106 | 
            -
                      alg =  | 
| 159 | 
            +
                      alg = Nsec3HashAlgorithms.new(a)
         | 
| 107 160 | 
             
                      @hash_alg = alg
         | 
| 108 161 | 
             
                    rescue ArgumentError => e
         | 
| 109 162 | 
             
                      raise DecodeError.new(e)
         | 
| @@ -118,27 +171,28 @@ module Dnsruby | |
| 118 171 | 
             
                    self.types=(@types + [t])
         | 
| 119 172 | 
             
                  end
         | 
| 120 173 |  | 
| 174 | 
            +
                  OPT_OUT = 1
         | 
| 121 175 | 
             
                  def flags=(f)
         | 
| 122 | 
            -
                    if (f==0 || f== | 
| 176 | 
            +
                    if (f==0 || f==OPT_OUT)
         | 
| 123 177 | 
             
                      @flags=f
         | 
| 124 178 | 
             
                    else
         | 
| 125 179 | 
             
                      raise DecodeError.new("Unknown NSEC3 flags field - #{f}")
         | 
| 126 180 | 
             
                    end
         | 
| 127 181 | 
             
                  end
         | 
| 128 | 
            -
             | 
| 182 | 
            +
             | 
| 129 183 | 
             
                  #If the Opt-Out flag is set, the NSEC3 record covers zero or more
         | 
| 130 184 | 
             
                  #unsigned delegations.
         | 
| 131 185 | 
             
                  def opt_out?
         | 
| 132 | 
            -
                    return (@flags== | 
| 133 | 
            -
                  end
         | 
| 134 | 
            -
                  
         | 
| 135 | 
            -
                  def salt_length=(l)
         | 
| 136 | 
            -
                    if ((l < 0) || (l > 255))
         | 
| 137 | 
            -
                      raise DecodeError.new("NSEC3 salt length must be between 0 and 255")
         | 
| 138 | 
            -
                    end
         | 
| 139 | 
            -
                    @salt_length = l
         | 
| 186 | 
            +
                    return (@flags==OPT_OUT)
         | 
| 140 187 | 
             
                  end
         | 
| 141 188 |  | 
| 189 | 
            +
                  #      def salt_length=(l)
         | 
| 190 | 
            +
                  #        if ((l < 0) || (l > 255))
         | 
| 191 | 
            +
                  #          raise DecodeError.new("NSEC3 salt length must be between 0 and 255")
         | 
| 192 | 
            +
                  #        end
         | 
| 193 | 
            +
                  #        @salt_length = l
         | 
| 194 | 
            +
                  #      end
         | 
| 195 | 
            +
                  #
         | 
| 142 196 | 
             
                  def hash_length=(l)
         | 
| 143 197 | 
             
                    if ((l < 0) || (l > 255))
         | 
| 144 198 | 
             
                      raise DecodeError.new("NSEC3 hash length must be between 0 and 255")
         | 
| @@ -151,34 +205,52 @@ module Dnsruby | |
| 151 205 | 
             
                    self.hash_alg=(hash_alg)
         | 
| 152 206 | 
             
                    self.flags=(flags)
         | 
| 153 207 | 
             
                    self.iterations=(iterations)
         | 
| 154 | 
            -
                    self.salt_length=(salt_length)
         | 
| 208 | 
            +
            #        self.salt_length=(salt_length)
         | 
| 155 209 | 
             
                    self.salt=(salt)
         | 
| 156 210 | 
             
                    self.hash_length=(hash_length)
         | 
| 157 211 | 
             
                    self.next_hashed=(next_hashed)
         | 
| 158 212 | 
             
                    self.types=(types)
         | 
| 159 213 | 
             
                  end
         | 
| 160 214 |  | 
| 161 | 
            -
                   | 
| 215 | 
            +
                  #The Salt field is appended to the original owner name before hashing
         | 
| 216 | 
            +
                  #in order to defend against pre-calculated dictionary attacks.
         | 
| 217 | 
            +
                  def salt
         | 
| 218 | 
            +
                    return NSEC3.encode_salt(@salt)
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                  def salt=(s)
         | 
| 222 | 
            +
                    @salt = NSEC3.decode_salt(s)
         | 
| 223 | 
            +
                    @salt_length = @salt.length
         | 
| 224 | 
            +
                  end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                  def NSEC3.decode_salt(input)
         | 
| 162 227 | 
             
                    if (input == "-")
         | 
| 163 | 
            -
                       | 
| 228 | 
            +
                      return []
         | 
| 164 229 | 
             
                    end
         | 
| 165 | 
            -
                     | 
| 166 | 
            -
                      @salt = input
         | 
| 230 | 
            +
                    return [input].pack("H*")
         | 
| 167 231 | 
             
                  end
         | 
| 168 232 |  | 
| 169 | 
            -
                  def encode_salt(s)
         | 
| 170 | 
            -
                    if (s.length == 0)
         | 
| 233 | 
            +
                  def NSEC3.encode_salt(s)
         | 
| 234 | 
            +
                    if (!s || s.length == 0)
         | 
| 171 235 | 
             
                      return "-"
         | 
| 172 236 | 
             
                    end
         | 
| 173 | 
            -
                    return s
         | 
| 237 | 
            +
                    return s.unpack("H*")[0]
         | 
| 174 238 | 
             
                  end
         | 
| 175 239 |  | 
| 176 240 | 
             
                  def decode_next_hashed(input)
         | 
| 177 | 
            -
                    @next_hashed =  | 
| 241 | 
            +
                    @next_hashed = NSEC3.decode_next_hashed(input)
         | 
| 242 | 
            +
                    end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                  def NSEC3.decode_next_hashed(input)
         | 
| 245 | 
            +
                    return Base32.decode32hex(input)
         | 
| 178 246 | 
             
                  end
         | 
| 179 247 |  | 
| 180 248 | 
             
                  def encode_next_hashed(n)
         | 
| 181 | 
            -
                    return  | 
| 249 | 
            +
                    return NSEC3.encode_next_hashed(n)
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  def NSEC3.encode_next_hashed(n)
         | 
| 253 | 
            +
                    return Base32.encode32hex(n).downcase
         | 
| 182 254 | 
             
                  end
         | 
| 183 255 |  | 
| 184 256 | 
             
                  def from_string(input)
         | 
| @@ -187,8 +259,9 @@ module Dnsruby | |
| 187 259 | 
             
                      self.hash_alg=(data[0]).to_i
         | 
| 188 260 | 
             
                      self.flags=(data[1]).to_i
         | 
| 189 261 | 
             
                      self.iterations=(data[2]).to_i
         | 
| 190 | 
            -
                      self.salt=decode_salt(data[3])
         | 
| 191 | 
            -
                      self. | 
| 262 | 
            +
                      #          self.salt=NSEC3.decode_salt(data[3])
         | 
| 263 | 
            +
                      self.salt=(data[3])
         | 
| 264 | 
            +
                      #          self.salt_length=(@salt.length)
         | 
| 192 265 |  | 
| 193 266 | 
             
                      len = data[0].length + data[1].length + data[2].length + data[3].length + 4
         | 
| 194 267 | 
             
                      # There may or may not be brackets around next_hashed
         | 
| @@ -203,9 +276,9 @@ module Dnsruby | |
| 203 276 | 
             
                      self.hash_length=(@next_hashed.length)
         | 
| 204 277 | 
             
                      len2 = data2[0].length + 1
         | 
| 205 278 | 
             
                      self.types = next_hashed_and_types[len2, next_hashed_and_types.length - len2]
         | 
| 206 | 
            -
            #          self.types=data2[1]
         | 
| 207 | 
            -
            #          #          len = data[0].length + data[1].length + data[2].length + data[3].length + data[5].length + 7
         | 
| 208 | 
            -
            #          #          self.types=(input[len, input.length-len])
         | 
| 279 | 
            +
                      #          self.types=data2[1]
         | 
| 280 | 
            +
                      #          #          len = data[0].length + data[1].length + data[2].length + data[3].length + data[5].length + 7
         | 
| 281 | 
            +
                      #          #          self.types=(input[len, input.length-len])
         | 
| 209 282 | 
             
                    end
         | 
| 210 283 | 
             
                  end
         | 
| 211 284 |  | 
| @@ -215,7 +288,8 @@ module Dnsruby | |
| 215 288 | 
             
                      @types.each do |t|
         | 
| 216 289 | 
             
                        type_strings.push(t.string)
         | 
| 217 290 | 
             
                      end
         | 
| 218 | 
            -
                      salt = encode_salt(@salt)
         | 
| 291 | 
            +
                      #          salt = NSEC3.encode_salt(@salt)
         | 
| 292 | 
            +
                      salt = salt()
         | 
| 219 293 | 
             
                      next_hashed = encode_next_hashed(@next_hashed)
         | 
| 220 294 | 
             
                      types = type_strings.join(" ")
         | 
| 221 295 | 
             
                      return "#{@hash_alg.code} #{@flags} #{@iterations} #{salt} ( #{next_hashed} #{types} )"
         | 
| @@ -225,8 +299,15 @@ module Dnsruby | |
| 225 299 | 
             
                  end
         | 
| 226 300 |  | 
| 227 301 | 
             
                  def encode_rdata(msg, canonical=false) #:nodoc: all
         | 
| 228 | 
            -
                     | 
| 229 | 
            -
                     | 
| 302 | 
            +
                    s = salt()
         | 
| 303 | 
            +
                    sl = s.length()
         | 
| 304 | 
            +
                    if (s == "-")
         | 
| 305 | 
            +
                      sl = 0
         | 
| 306 | 
            +
                    end
         | 
| 307 | 
            +
                    msg.put_pack("ccnc", @hash_alg.code, @flags, @iterations, sl)
         | 
| 308 | 
            +
                    if (sl > 0)
         | 
| 309 | 
            +
                      msg.put_bytes(s)
         | 
| 310 | 
            +
                    end
         | 
| 230 311 | 
             
                    msg.put_pack("c", @hash_length)
         | 
| 231 312 | 
             
                    msg.put_bytes(@next_hashed)
         | 
| 232 313 | 
             
                    types = NSEC.encode_types(self)
         |