dnsruby 1.60.2 → 1.61.5

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.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +9 -6
  3. data/.yardopts +7 -0
  4. data/README.md +7 -4
  5. data/RELEASE_NOTES.md +43 -0
  6. data/Rakefile +1 -0
  7. data/demo/digroot.rb +2 -0
  8. data/demo/rubydig.rb +1 -0
  9. data/dnsruby.gemspec +15 -8
  10. data/lib/dnsruby/code_mappers.rb +3 -0
  11. data/lib/dnsruby/config.rb +30 -8
  12. data/lib/dnsruby/dnssec.rb +4 -0
  13. data/lib/dnsruby/hosts.rb +8 -4
  14. data/lib/dnsruby/message/encoder.rb +2 -2
  15. data/lib/dnsruby/message/header.rb +15 -15
  16. data/lib/dnsruby/name.rb +18 -2
  17. data/lib/dnsruby/packet_sender.rb +14 -2
  18. data/lib/dnsruby/recursor.rb +10 -1
  19. data/lib/dnsruby/resolver.rb +11 -0
  20. data/lib/dnsruby/resource/CAA.rb +1 -1
  21. data/lib/dnsruby/resource/CDNSKEY.rb +17 -0
  22. data/lib/dnsruby/resource/CDS.rb +35 -0
  23. data/lib/dnsruby/resource/DNSKEY.rb +33 -6
  24. data/lib/dnsruby/resource/IN.rb +4 -1
  25. data/lib/dnsruby/resource/URI.rb +57 -0
  26. data/lib/dnsruby/resource/generic.rb +3 -0
  27. data/lib/dnsruby/select_thread.rb +1 -1
  28. data/lib/dnsruby/single_verifier.rb +27 -4
  29. data/lib/dnsruby/validator_thread.rb +4 -4
  30. data/lib/dnsruby/version.rb +1 -1
  31. data/lib/dnsruby/zone_transfer.rb +5 -1
  32. data/test/localdns.rb +29 -0
  33. data/test/tc_caa.rb +0 -1
  34. data/test/tc_dns.rb +11 -1
  35. data/test/tc_dnskey.rb +29 -0
  36. data/test/tc_encoding.rb +31 -0
  37. data/test/tc_hs.rb +4 -3
  38. data/test/tc_long_labels.rb +46 -0
  39. data/test/tc_name.rb +19 -0
  40. data/test/tc_resolv.rb +5 -4
  41. data/test/tc_resolver.rb +28 -2
  42. data/test/tc_rr-opt.rb +9 -3
  43. data/test/tc_rr.rb +33 -0
  44. data/test/tc_soak.rb +33 -67
  45. data/test/tc_tcp_pipelining.rb +27 -19
  46. data/test/tc_verifier.rb +15 -0
  47. data/test/test_dnsserver.rb +110 -17
  48. metadata +50 -44
@@ -331,7 +331,14 @@ module Dnsruby
331
331
  client_query_id = Time.now + rand(10000) # is this safe?!
332
332
  end
333
333
 
334
- query_packet = make_query_packet(msg, use_tcp)
334
+ begin
335
+ query_packet = make_query_packet(msg, use_tcp)
336
+ rescue EncodeError => err
337
+ Dnsruby.log.error { "#{err}" }
338
+ st = SelectThread.instance
339
+ st.push_exception_to_select(client_query_id, client_queue, err, nil)
340
+ return
341
+ end
335
342
 
336
343
  if (msg.do_caching && (msg.class != Update))
337
344
  # Check the cache!!
@@ -449,7 +456,7 @@ module Dnsruby
449
456
  socket, new_socket = tcp_pipeline_socket(src_port)
450
457
  src_port = @tcp_pipeline_local_port
451
458
  else
452
- socket = TCPSocket.new(@server, @port, src_address, src_port)
459
+ socket = Socket.tcp(@server, @port, src_address, src_port, connect_timeout: @packet_timeout)
453
460
  new_socket = true
454
461
  end
455
462
  rescue Errno::EBADF, Errno::ENETUNREACH => e
@@ -622,6 +629,11 @@ module Dnsruby
622
629
  # Should send error back up to Resolver here, and then NOT QUERY AGAIN!!!
623
630
  return sig_value
624
631
  end
632
+ if ((response.header.get_header_rcode == RCode.FORMERR) &&
633
+ (query.header.arcount == 0))
634
+ # Raise an error
635
+ return true
636
+ end
625
637
  # Should check that question section is same as question that was sent! RFC 5452
626
638
  # If it's not an update...
627
639
  if (query.class == Update)
@@ -153,7 +153,7 @@ module Dnsruby
153
153
  end
154
154
  end
155
155
  attr_accessor :nameservers, :callback, :recurse, :ipv6_ok
156
- attr_reader :hints
156
+ attr_reader :hints, :dnssec
157
157
  # The resolver to use for the queries
158
158
  attr_accessor :resolver
159
159
 
@@ -164,6 +164,11 @@ module Dnsruby
164
164
  @@zones_cache = nil
165
165
  @@nameservers = nil
166
166
 
167
+ def dnssec=(dnssec_on)
168
+ @dnssec = dnssec_on
169
+ @resolver.dnssec = dnssec_on
170
+ end
171
+
167
172
  def initialize(res = nil)
168
173
  if (res)
169
174
  @resolver = res
@@ -174,6 +179,7 @@ module Dnsruby
174
179
  @resolver = Resolver.new
175
180
  end
176
181
  end
182
+ @resolver.dnssec = @dnssec
177
183
  @ipv6_ok = false
178
184
  end
179
185
  # Initialize the hint servers. Recursive queries need a starting name
@@ -196,6 +202,7 @@ module Dnsruby
196
202
  @resolver = resolver
197
203
  if (resolver.single_resolvers.length == 0)
198
204
  resolver = Resolver.new()
205
+ resolver.dnssec = @dnssec
199
206
  end
200
207
  if (hints && hints.length > 0)
201
208
  resolver.nameservers=hints
@@ -372,6 +379,7 @@ module Dnsruby
372
379
  end
373
380
 
374
381
  def Recursor.clear_caches(resolver = Resolver.new)
382
+ resolver.dnssec = @dnssec
375
383
  Recursor.set_hints(Hash.new, resolver)
376
384
  @@zones_cache = Hash.new # key zone_name, values Hash of servers and AddressCaches
377
385
  @@zones_cache["."] = @@hints
@@ -613,6 +621,7 @@ module Dnsruby
613
621
  }
614
622
  end
615
623
  resolver = Resolver.new({:nameserver=>nameservers})
624
+ resolver.dnssec = @dnssec
616
625
  servers = []
617
626
  resolver.single_resolvers.each {|s|
618
627
  servers.push(s.server)
@@ -891,6 +891,14 @@ module Dnsruby
891
891
  return
892
892
  end
893
893
 
894
+ begin
895
+ msg.encode
896
+ rescue EncodeError => err
897
+ Dnsruby.log.error { "Can't encode " + msg.to_s + " : #{err}" }
898
+ client_queue.push([client_query_id, err])
899
+ return
900
+ end
901
+
894
902
  tick_needed = false
895
903
  # add to our data structures
896
904
  # @mutex.synchronize{
@@ -1124,6 +1132,9 @@ module Dnsruby
1124
1132
  increment_resolver_priority(resolver) unless response.cached
1125
1133
  stop_querying(client_query_id)
1126
1134
  # @TODO@ Does the client want notified at this point?
1135
+ elsif error.kind_of?(EncodeError)
1136
+ Dnsruby.log.debug{'Encode error - sending to client'}
1137
+ send_result_and_stop_querying(client_queue, client_query_id, select_queue, response, error)
1127
1138
  else
1128
1139
  # - if it was any other error, then remove that server from the list for that query
1129
1140
  # If a Too Many Open Files error, then don't remove, but let retry work.
@@ -43,7 +43,7 @@ module Dnsruby
43
43
  end
44
44
 
45
45
  def from_string(input) #:nodoc: all
46
- matches = (/(\d+) (issuewild|issue|iodef) "(.+)"$/).match(input)
46
+ matches = (/(\d+) (issuewild|issue|iodef|contactemail|contactphone) "(.+)"$/).match(input)
47
47
  @flag = matches[1]
48
48
  @property_tag = matches[2]
49
49
  @property_value = matches[3]
@@ -0,0 +1,17 @@
1
+ module Dnsruby
2
+ class RR
3
+ # RFC4034, section 2
4
+ # DNSSEC uses public key cryptography to sign and authenticate DNS
5
+ # resource record sets (RRsets). The public keys are stored in DNSKEY
6
+ # resource records and are used in the DNSSEC authentication process
7
+ # described in [RFC4035]: A zone signs its authoritative RRsets by
8
+ # using a private key and stores the corresponding public key in a
9
+ # DNSKEY RR. A resolver can then use the public key to validate
10
+ # signatures covering the RRsets in the zone, and thus to authenticate
11
+ # them.
12
+ class CDNSKEY < DNSKEY
13
+ ClassValue = nil #:nodoc: all
14
+ TypeValue = Types::CDNSKEY #:nodoc: all
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ # --
2
+ # Copyright 2018 Caerketton Tech Ltd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+ module Dnsruby
17
+ class RR
18
+ # RFC4034, section 4
19
+ # The DS Resource Record refers to a DNSKEY RR and is used in the DNS
20
+ # DNSKEY authentication process. A DS RR refers to a DNSKEY RR by
21
+ # storing the key tag, algorithm number, and a digest of the DNSKEY RR.
22
+ # Note that while the digest should be sufficient to identify the
23
+ # public key, storing the key tag and key algorithm helps make the
24
+ # identification process more efficient. By authenticating the DS
25
+ # record, a resolver can authenticate the DNSKEY RR to which the DS
26
+ # record points. The key authentication process is described in
27
+ # [RFC4035].
28
+
29
+ class CDS < DS
30
+
31
+ ClassValue = nil #:nodoc: all
32
+ TypeValue = Types::CDS #:nodoc: all
33
+ end
34
+ end
35
+ end
@@ -313,6 +313,8 @@ module Dnsruby
313
313
  elsif [Algorithms.DSA,
314
314
  Algorithms.DSA_NSEC3_SHA1].include?(@algorithm)
315
315
  @public_key = dsa_key
316
+ elsif [Algorithms.ECDSAP256SHA256, Algorithms.ECDSAP384SHA384].include?(@algorithm)
317
+ @public_key = ec_key(Algorithms.ECDSAP256SHA256 == @algorithm ? 'prime256v1' : 'secp384r1')
316
318
  end
317
319
  end
318
320
  # @TODO@ Support other key encodings!
@@ -340,8 +342,12 @@ module Dnsruby
340
342
  @key_length = (@key.length - pos) * 8
341
343
 
342
344
  pkey = OpenSSL::PKey::RSA.new
343
- pkey.e = exponent
344
- pkey.n = modulus
345
+ begin
346
+ pkey.set_key(modulus, exponent, nil) # use set_key, present in later versions of openssl gem
347
+ rescue NoMethodError
348
+ pkey.e = exponent # set_key not available in earlier versions, use this approach instead
349
+ pkey.n = modulus
350
+ end
345
351
  return pkey
346
352
  end
347
353
 
@@ -361,10 +367,31 @@ module Dnsruby
361
367
  @key_length = (pgy_len * 8)
362
368
 
363
369
  pkey = OpenSSL::PKey::DSA.new
364
- pkey.p = p
365
- pkey.q = q
366
- pkey.g = g
367
- pkey.pub_key = y
370
+ begin
371
+ pkey.set_pgq(p,g,q)
372
+ pkey.set_key(y, nil) # use set_pgq and set_key, present in later versions of openssl gem
373
+ rescue NoMethodError
374
+ pkey.p = p # set_key not available in earlier versions, use this approach instead
375
+ pkey.q = q
376
+ pkey.g = g
377
+ pkey.pub_key = y
378
+ end
379
+
380
+ pkey
381
+ end
382
+
383
+ # RFC6605, section 4
384
+ # ECDSA public keys consist of a single value, called "Q" in FIPS
385
+ # 186-3. In DNSSEC keys, Q is a simple bit string that represents the
386
+ # uncompressed form of a curve point, "x | y".
387
+ def ec_key(curve = 'prime256v1')
388
+ group = OpenSSL::PKey::EC::Group.new(curve)
389
+ pkey = OpenSSL::PKey::EC.new(group)
390
+
391
+ # DNSSEC pub does not have first octet that determines whether it's uncompressed
392
+ # or compressed form, but it's required by OpenSSL to parse EC point correctly
393
+ point_from_pub = "\x04" + @key.to_s # octet string, \x04 prefix determines uncompressed
394
+ pkey.public_key = OpenSSL::PKey::EC::Point.new(group, point_from_pub)
368
395
 
369
396
  pkey
370
397
  end
@@ -19,7 +19,11 @@ module Dnsruby
19
19
  Types::NS => NS,
20
20
  Types::CNAME => CNAME,
21
21
  Types::DNAME => DNAME,
22
+ Types::URI => URI,
23
+ Types::DS => DS,
24
+ Types::CDS => CDS,
22
25
  Types::DNSKEY => DNSKEY,
26
+ Types::CDNSKEY => CDNSKEY,
23
27
  Types::SOA => SOA,
24
28
  Types::PTR => PTR,
25
29
  Types::HINFO => HINFO,
@@ -45,7 +49,6 @@ module Dnsruby
45
49
  Types::ANY => ANY,
46
50
  Types::RRSIG => RRSIG,
47
51
  Types::NSEC => NSEC,
48
- Types::DS => DS,
49
52
  Types::NSEC3 => NSEC3,
50
53
  Types::NSEC3PARAM => NSEC3PARAM,
51
54
  Types::DLV => DLV,
@@ -0,0 +1,57 @@
1
+ module Dnsruby
2
+ class RR
3
+ class URI < RR
4
+ ClassValue = nil #:nodoc: all
5
+ TypeValue= Types::URI #:nodoc: all
6
+
7
+ # The NAPTR RR order field
8
+ attr_accessor :priority
9
+
10
+ # The NAPTR RR order field
11
+ attr_accessor :weight
12
+
13
+ # The NAPTR RR order field
14
+ attr_accessor :target
15
+
16
+ def from_hash(hash) #:nodoc: all
17
+ @priority = hash[:priority]
18
+ @weight = hash[:weight]
19
+ @target = hash[:target]
20
+ end
21
+
22
+ def from_data(data) #:nodoc: all
23
+ @priority, @weight, @target = data
24
+ end
25
+
26
+ def from_string(input) #:nodoc: all
27
+ if (input.strip.length > 0)
28
+ values = input.split(" ")
29
+ @priority = values [0].to_i
30
+ @weight = values [1].to_i
31
+ @target = values [2].gsub!("\"", "")
32
+ end
33
+ end
34
+
35
+ def rdata_to_string #:nodoc: all
36
+ "#{@priority} #{@weight} \"#{@target}\""
37
+ end
38
+
39
+ def encode_rdata(msg, canonical=false) #:nodoc: all
40
+ if (@priority != nil)
41
+ msg.put_pack('n', @priority)
42
+ msg.put_pack('n', @weight)
43
+ msg.put_bytes(@target)
44
+ end
45
+ end
46
+
47
+ def self.decode_rdata(msg) #:nodoc: all
48
+ priority, = msg.get_unpack('n')
49
+ weight, = msg.get_unpack('n')
50
+ target = msg.get_bytes
51
+ return self.new([priority, weight, target])
52
+ end
53
+
54
+
55
+ end
56
+ end
57
+ end
@@ -152,9 +152,12 @@ require 'dnsruby/resource/OPT'
152
152
  require 'dnsruby/resource/TSIG'
153
153
  require 'dnsruby/resource/TKEY'
154
154
  require 'dnsruby/resource/DNSKEY'
155
+ require 'dnsruby/resource/CDNSKEY'
155
156
  require 'dnsruby/resource/RRSIG'
156
157
  require 'dnsruby/resource/NSEC'
157
158
  require 'dnsruby/resource/DS'
159
+ require 'dnsruby/resource/CDS'
160
+ require 'dnsruby/resource/URI'
158
161
  require 'dnsruby/resource/NSEC3'
159
162
  require 'dnsruby/resource/NSEC3PARAM'
160
163
  require 'dnsruby/resource/DLV'
@@ -194,7 +194,7 @@ module Dnsruby
194
194
  rescue SelectWakeup
195
195
  # If SelectWakeup, then just restart this loop - the select call will be made with the new data
196
196
  next
197
- rescue IOError => e
197
+ rescue IOError, EncodeError => e
198
198
  # print "IO Error =: #{e}\n"
199
199
  exceptions = clean_up_closed_sockets
200
200
  exceptions.each { |exception| send_exception_to_client(*exception) }
@@ -65,6 +65,7 @@ module Dnsruby
65
65
  @@recursor = Recursor.new
66
66
  end
67
67
  end
68
+ @@recursor.dnssec = true
68
69
  return @@recursor
69
70
  end
70
71
 
@@ -72,12 +73,15 @@ module Dnsruby
72
73
  # if (Dnssec.do_validation_with_recursor?)
73
74
  # return Recursor.new
74
75
  # else
76
+ resolver = nil
75
77
  if (Dnssec.default_resolver)
76
- return Dnssec.default_resolver
78
+ resolver = Dnssec.default_resolver
77
79
  else
78
- return Resolver.new
80
+ resolver = Resolver.new
79
81
  end
80
82
  # end
83
+ resolver.dnssec = true
84
+ return resolver
81
85
  end
82
86
  def add_dlv_key(key)
83
87
  # Is this a ZSK or a KSK?
@@ -796,6 +800,19 @@ module Dnsruby
796
800
 
797
801
  asn1 = OpenSSL::ASN1::Sequence.new([r_asn1, s_asn1]).to_der
798
802
  verified = keyrec.public_key.verify(OpenSSL::Digest::DSS1.new, asn1, sig_data)
803
+ elsif [Algorithms.ECDSAP256SHA256, Algorithms.ECDSAP384SHA384].include?(sigrec.algorithm)
804
+ byte_size = (keyrec.public_key.group.degree + 7) / 8
805
+ sig_bytes = sigrec.signature[0..(byte_size - 1)]
806
+ sig_char = sigrec.signature[byte_size..-1] || ''
807
+ asn1 = OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
808
+
809
+ digest_obj = if sigrec.algorithm == Algorithms.ECDSAP384SHA384
810
+ OpenSSL::Digest::SHA384.new
811
+ else
812
+ OpenSSL::Digest::SHA256.new
813
+ end
814
+
815
+ verified = keyrec.public_key.dsa_verify_asn1(digest_obj.digest(sig_data), asn1)
799
816
  else
800
817
  raise RuntimeError.new("Algorithm #{sigrec.algorithm.code} unsupported by Dnsruby")
801
818
  end
@@ -848,6 +865,7 @@ module Dnsruby
848
865
  end
849
866
  end
850
867
  end
868
+ res.dnssec = true
851
869
  # query = Message.new(name, Types.DNSKEY)
852
870
  # query.do_validation = false
853
871
  ret = nil
@@ -1011,6 +1029,7 @@ module Dnsruby
1011
1029
  end
1012
1030
  end
1013
1031
  end
1032
+ parent_res.dnssec = true
1014
1033
  end
1015
1034
  # Use that Resolver to query for DS record and NS for children
1016
1035
  ds_rrset = current_anchor
@@ -1068,6 +1087,7 @@ module Dnsruby
1068
1087
  child_res = Resolver.new
1069
1088
  end
1070
1089
  end
1090
+ child_res.dnssec = true
1071
1091
  end
1072
1092
  end
1073
1093
  # Query for DNSKEY record, and verify against DS in parent.
@@ -1143,11 +1163,14 @@ module Dnsruby
1143
1163
  if (Dnssec.do_validation_with_recursor?)
1144
1164
  return get_recursor
1145
1165
  else
1166
+ resolver = nil
1146
1167
  if (Dnssec.default_resolver)
1147
- return Dnssec.default_resolver
1168
+ resolver = Dnssec.default_resolver
1148
1169
  else
1149
- return Resolver.new
1170
+ resolver = Resolver.new
1150
1171
  end
1172
+ resolver.dnssec = true
1173
+ return resolver
1151
1174
  end
1152
1175
  end
1153
1176
 
@@ -1,12 +1,12 @@
1
1
  # --
2
2
  # Copyright 2007 Nominet UK
3
- #
3
+ #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
6
6
  # You may obtain a copy of the License at
7
- #
7
+ #
8
8
  # http://www.apache.org/licenses/LICENSE-2.0
9
- #
9
+ #
10
10
  # Unless required by applicable law or agreed to in writing, software
11
11
  # distributed under the License is distributed on an "AS IS" BASIS,
12
12
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -109,7 +109,7 @@ module Dnsruby
109
109
  return true
110
110
  rescue VerifyError => e
111
111
  response.security_error = e
112
- response.security_level = BOGUS
112
+ response.security_level = Message::SecurityLevel.BOGUS
113
113
  # Response security_level should already be set
114
114
  return false
115
115
  end