dnsruby 1.61.2 → 1.61.7

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 (52) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/.yardopts +7 -0
  4. data/Gemfile +0 -2
  5. data/README.md +2 -1
  6. data/RELEASE_NOTES.md +32 -1
  7. data/Rakefile +2 -0
  8. data/dnsruby.gemspec +14 -9
  9. data/lib/dnsruby.rb +4 -4
  10. data/lib/dnsruby/DNS.rb +1 -1
  11. data/lib/dnsruby/config.rb +13 -13
  12. data/lib/dnsruby/dnssec.rb +1 -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 +0 -3
  16. data/lib/dnsruby/name.rb +13 -15
  17. data/lib/dnsruby/packet_sender.rb +12 -16
  18. data/lib/dnsruby/recursor.rb +6 -5
  19. data/lib/dnsruby/resolver.rb +14 -17
  20. data/lib/dnsruby/resource/CAA.rb +2 -2
  21. data/lib/dnsruby/resource/DNSKEY.rb +18 -0
  22. data/lib/dnsruby/resource/NSEC3PARAM.rb +1 -1
  23. data/lib/dnsruby/resource/TLSA.rb +3 -3
  24. data/lib/dnsruby/resource/TXT.rb +11 -1
  25. data/lib/dnsruby/select_thread.rb +6 -7
  26. data/lib/dnsruby/single_verifier.rb +14 -3
  27. data/lib/dnsruby/validator_thread.rb +4 -4
  28. data/lib/dnsruby/version.rb +1 -1
  29. data/lib/dnsruby/zone_reader.rb +2 -2
  30. data/lib/dnsruby/zone_transfer.rb +0 -1
  31. data/test/localdns.rb +29 -0
  32. data/test/spec_helper.rb +6 -0
  33. data/test/tc_caa.rb +0 -1
  34. data/test/tc_dns.rb +7 -2
  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 +12 -12
  42. data/test/tc_rr-opt.rb +8 -5
  43. data/test/tc_rr-txt.rb +7 -1
  44. data/test/tc_soak.rb +31 -69
  45. data/test/tc_tcp.rb +2 -2
  46. data/test/tc_tcp_pipelining.rb +26 -25
  47. data/test/tc_verifier.rb +15 -0
  48. data/test/test_dnsserver.rb +110 -17
  49. data/test/test_utils.rb +0 -2
  50. data/test/ts_offline.rb +8 -8
  51. metadata +40 -51
  52. data/.travis.yml +0 -14
@@ -227,7 +227,7 @@ module Dnsruby
227
227
  # Nice idea.
228
228
 
229
229
  # if (!@@hints || @@hints.length == 0)
230
- resolver.recurse=(1)
230
+ resolver.recurse = true
231
231
  packet=resolver.query_no_validation_or_recursion(".", "NS", "IN")
232
232
  hints = Hash.new
233
233
  if (packet)
@@ -264,7 +264,7 @@ module Dnsruby
264
264
  }
265
265
  }
266
266
  (hints.length * 2).times {
267
- id, result, error = q.pop
267
+ _id, result, _error = q.pop
268
268
  if (result)
269
269
  result.answer.each {|rr|
270
270
  TheLog.debug(";; NS address: " + rr.inspect+"\n")
@@ -303,7 +303,7 @@ module Dnsruby
303
303
  end
304
304
 
305
305
  # Disable recursion flag.
306
- resolver.recurse=(0)
306
+ resolver.recurse = false
307
307
  # end
308
308
 
309
309
  # return $self->nameservers( map { @{ $_ } } values %{ $self->{'hints'} } );
@@ -406,7 +406,7 @@ module Dnsruby
406
406
  @@mutex.synchronize {
407
407
  self.hints=(Hash.new) unless @@hints
408
408
  }
409
- @resolver.recurse=(0)
409
+ @resolver.recurse = false
410
410
  # Make sure the authority cache is clean.
411
411
  # It is only used to store A and AAAA records of
412
412
  # the suposedly authoritative name servers.
@@ -622,6 +622,7 @@ module Dnsruby
622
622
  end
623
623
  resolver = Resolver.new({:nameserver=>nameservers})
624
624
  resolver.dnssec = @dnssec
625
+ resolver.recurse = false
625
626
  servers = []
626
627
  resolver.single_resolvers.each {|s|
627
628
  servers.push(s.server)
@@ -638,7 +639,7 @@ module Dnsruby
638
639
  packet = resolver.send_message(query)
639
640
  # @TODO@ Now prune unrelated RRSets (RFC 5452 section 6)
640
641
  prune_rrsets_to_rfc5452(packet, known_zone)
641
- rescue ResolvTimeout, IOError => e
642
+ rescue ResolvTimeout, IOError
642
643
  # TheLog.debug(";; nameserver #{levelns.to_s} didn't respond")
643
644
  # next
644
645
  TheLog.debug("No response!")
@@ -128,7 +128,9 @@ module Dnsruby
128
128
  # The current Config
129
129
  attr_reader :config
130
130
 
131
- # Does this Resolver cache answers, and attempt to retrieve answer from the cache?
131
+ # Defines whether we will cache responses, or pass every request to the
132
+ # upstream resolver. This is only really useful when querying authoritative
133
+ # servers (as the upstream recursive resolver is likely to cache)
132
134
  attr_reader :do_caching
133
135
 
134
136
  # The array of SingleResolvers used for sending query messages
@@ -171,11 +173,6 @@ module Dnsruby
171
173
  # requirements.
172
174
  attr_accessor :do_validation
173
175
 
174
- # Defines whether we will cache responses, or pass every request to the
175
- # upstream resolver. This is only really useful when querying authoritative
176
- # servers (as the upstream recursive resolver is likely to cache)
177
- attr_accessor :do_caching
178
-
179
176
  # --
180
177
  # @TODO@ add load_balance? i.e. Target nameservers in a random, rather than pre-determined, order?
181
178
  # This is best done when configuring the Resolver, as it will re-order servers based on their response times.
@@ -568,7 +565,7 @@ module Dnsruby
568
565
  def add_server(server)# :nodoc:
569
566
  @configured = true
570
567
  res = PacketSender.new(server)
571
- log_and_raise("Can't create server #{server}", ArgumentError) unless res
568
+ Dnsruby.log_and_raise("Can't create server #{server}", ArgumentError) unless res
572
569
  update_internal_res(res)
573
570
  @single_res_mutex.synchronize { @single_resolvers.push(res) }
574
571
  end
@@ -644,7 +641,7 @@ module Dnsruby
644
641
  a = Resolver.get_ports_from(p)
645
642
  a.each do |x|
646
643
  if (@src_port.length > 0) && (x == 0)
647
- log_and_raise("src_port of 0 only allowed as only src_port value (currently #{@src_port.length} values",
644
+ Dnsruby.log_and_raise("src_port of 0 only allowed as only src_port value (currently #{@src_port.length} values",
648
645
  ArgumentError)
649
646
  end
650
647
  @src_port.push(x)
@@ -668,7 +665,7 @@ module Dnsruby
668
665
  return ! ((p == 0) && (src_port.length > 0))
669
666
  else
670
667
  Dnsruby.log.error("Illegal port (#{p})")
671
- log_and_raise("Illegal port #{p}", ArgumentError)
668
+ Dnsruby.log_and_raise("Illegal port #{p}", ArgumentError)
672
669
  end
673
670
  end
674
671
 
@@ -837,7 +834,7 @@ module Dnsruby
837
834
  timeouts[base + offset]=[res, retry_count]
838
835
  else
839
836
  if timeouts.has_key?(base + retry_delay + offset)
840
- log_and_raise('Duplicate timeout key!')
837
+ Dnsruby.log_and_raise('Duplicate timeout key!')
841
838
  end
842
839
  timeouts[base + retry_delay + offset]=[res, retry_count]
843
840
  end
@@ -878,7 +875,7 @@ module Dnsruby
878
875
  end
879
876
 
880
877
  unless client_queue.kind_of?(Queue)
881
- log_and_raise('Wrong type for client_queue in Resolver# send_async')
878
+ Dnsruby.log_and_raise('Wrong type for client_queue in Resolver# send_async')
882
879
  # @TODO@ Handle different queue tuples - push this to generic send_error method
883
880
  client_queue.push([client_query_id, ArgumentError.new('Wrong type of client_queue passed to Dnsruby::Resolver# send_async - should have been Queue, was #{client_queue.class}')])
884
881
  return
@@ -1059,13 +1056,13 @@ module Dnsruby
1059
1056
  # @TODO@ Also, should have option to speak only to configured resolvers (not follow authoritative chain)
1060
1057
  #
1061
1058
  if queue.empty?
1062
- log_and_raise('Severe internal error - Queue empty in handle_queue_event')
1059
+ Dnsruby.log_and_raise('Severe internal error - Queue empty in handle_queue_event')
1063
1060
  end
1064
1061
  event_id, event_type, response, error = queue.pop
1065
1062
  # We should remove this packet from the list of outstanding packets for this query
1066
1063
  _resolver, _msg, client_query_id, _retry_count = id
1067
1064
  if id != event_id
1068
- log_and_raise("Serious internal error!! #{id} expected, #{event_id} received")
1065
+ Dnsruby.log_and_raise("Serious internal error!! #{id} expected, #{event_id} received")
1069
1066
  end
1070
1067
  # @mutex.synchronize{
1071
1068
  @parent.single_res_mutex.synchronize {
@@ -1078,7 +1075,7 @@ module Dnsruby
1078
1075
  if event_type == Resolver::EventType::RECEIVED ||
1079
1076
  event_type == Resolver::EventType::ERROR
1080
1077
  unless outstanding.include?(id)
1081
- log_and_raise("Query id not on outstanding list! #{outstanding.length} items. #{id} not on #{outstanding}")
1078
+ Dnsruby.log.error("Query id not on outstanding list! #{outstanding.length} items. #{id} not on #{outstanding}")
1082
1079
  end
1083
1080
  outstanding.delete(id)
1084
1081
  end
@@ -1208,7 +1205,7 @@ module Dnsruby
1208
1205
  # @mutex.synchronize{
1209
1206
  _query, _client_queue, s_queue, _outstanding = @query_list[client_query_id]
1210
1207
  if s_queue != select_queue
1211
- log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1208
+ Dnsruby.log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1212
1209
  end
1213
1210
  stop_querying(client_query_id)
1214
1211
  # @TODO@ Does the client want notified at this point?
@@ -1221,7 +1218,7 @@ module Dnsruby
1221
1218
  # @mutex.synchronize {
1222
1219
  _query, client_queue, s_queue, _outstanding = @query_list[client_query_id]
1223
1220
  if s_queue != select_queue
1224
- log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1221
+ Dnsruby.log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1225
1222
  end
1226
1223
  if response.rcode == RCode.NXDOMAIN
1227
1224
  send_result(client_queue, client_query_id, select_queue, response, NXDomain.new)
@@ -1237,7 +1234,7 @@ module Dnsruby
1237
1234
  _resolver, _msg, client_query_id, _retry_count = query_id
1238
1235
  _query, client_queue, s_queue, _outstanding = @query_list[client_query_id]
1239
1236
  if s_queue != select_queue
1240
- log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1237
+ Dnsruby.log_and_raise("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1241
1238
  end
1242
1239
  # For some errors, we immediately send result. For others, should we retry?
1243
1240
  # Either :
@@ -26,7 +26,7 @@ module Dnsruby
26
26
  # The value for the property_tag
27
27
  attr_accessor :property_value
28
28
  # The value for the flag
29
- attr_accessor :flag
29
+ attr_writer :flag
30
30
 
31
31
  def from_hash(hash) #:nodoc: all
32
32
  @property_tag = hash[:property_tag]
@@ -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]
@@ -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!
@@ -377,6 +379,22 @@ module Dnsruby
377
379
 
378
380
  pkey
379
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)
395
+
396
+ pkey
397
+ end
380
398
  end
381
399
  end
382
400
  end
@@ -85,7 +85,7 @@ module Dnsruby
85
85
  # end
86
86
  #
87
87
  def from_data(data) #:nodoc: all
88
- hash_alg, flags, iterations, salt_length, salt = data
88
+ hash_alg, flags, iterations, _salt_length, salt = data
89
89
  self.hash_alg=(hash_alg)
90
90
  self.flags=(flags)
91
91
  self.iterations=(iterations)
@@ -33,8 +33,8 @@ module Dnsruby
33
33
  # 255 Private use
34
34
  attr_accessor :matching_type
35
35
  # sec 2.1.4
36
- attr_accessor :data
37
- attr_accessor :databin
36
+ attr_reader :data
37
+ attr_reader :databin
38
38
 
39
39
  def verify
40
40
  raise ArgumentError, "usage with invalid value: #{@usage}" if @usage < 0 || @usage > 255
@@ -71,7 +71,7 @@ module Dnsruby
71
71
  if @matching_type == 0 && @selector == 0 && @databin
72
72
  begin
73
73
  cert = OpenSSL::X509::Certificate.new(@databin)
74
- rescue => e
74
+ rescue
75
75
  raise ArgumentError, 'data is invalid cert '
76
76
  end
77
77
  end
@@ -82,7 +82,17 @@ module Dnsruby
82
82
  end
83
83
  else
84
84
  if (seen_strings && !in_string)
85
- next
85
+ if (c == ";")
86
+ # Comment in zone file!
87
+ return strings
88
+ end
89
+ if (c != " " && c != "\t")
90
+ in_string = true
91
+ count+=1
92
+ strings[count] = ""
93
+ else
94
+ next
95
+ end
86
96
  end
87
97
  if (pos == 0)
88
98
  unquoted = true
@@ -140,7 +140,7 @@ module Dnsruby
140
140
  }
141
141
  begin
142
142
  @@wakeup_sockets[0].send("wakeup!", 0)
143
- rescue Exception => e
143
+ rescue Exception
144
144
  # do nothing
145
145
  end
146
146
  end
@@ -190,12 +190,11 @@ module Dnsruby
190
190
  end
191
191
  # next if (timeout < 0)
192
192
  begin
193
- ready, write, errors = IO.select(sockets, nil, nil, timeout)
193
+ ready, _write, _errors = IO.select(sockets, nil, nil, timeout)
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, EncodeError => e
198
- # print "IO Error =: #{e}\n"
197
+ rescue IOError, EncodeError
199
198
  exceptions = clean_up_closed_sockets
200
199
  exceptions.each { |exception| send_exception_to_client(*exception) }
201
200
 
@@ -248,7 +247,7 @@ module Dnsruby
248
247
  # Removes closed sockets from @@sockets, and returns an array containing 1
249
248
  # exception for each closed socket contained in @@socket_hash.
250
249
  def clean_up_closed_sockets
251
- exceptions = @@mutex.synchronize do
250
+ @@mutex.synchronize do
252
251
  closed_sockets_in_hash = @@sockets.select(&:closed?).select { |s| @@socket_hash[s] }
253
252
  @@sockets.delete_if { | socket | socket.closed? }
254
253
  closed_sockets_in_hash.each_with_object([]) do |socket, exceptions|
@@ -257,6 +256,7 @@ module Dnsruby
257
256
  end
258
257
  end
259
258
  end
259
+ exceptions
260
260
  end
261
261
 
262
262
  def process_error(errors)
@@ -295,7 +295,6 @@ module Dnsruby
295
295
  @@mutex.synchronize do
296
296
  ids = get_active_ids(@@query_hash, msg.header.id)
297
297
  return if ids.empty? # should be only one
298
- query_settings = @@query_hash[ids[0]].clone
299
298
  end
300
299
 
301
300
  answerip = msg.answerip.downcase
@@ -732,7 +731,7 @@ module Dnsruby
732
731
  }
733
732
 
734
733
  responses.each do |item|
735
- client_id, client_queue, msg, err, query, res = item
734
+ client_id, client_queue, msg, err, _query, _res = item
736
735
  # push_to_client(client_id, client_queue, msg, err)
737
736
  client_queue.push([client_id, Resolver::EventType::VALIDATED, msg, err])
738
737
  notify_queue_observers(client_queue, client_id)
@@ -462,7 +462,6 @@ module Dnsruby
462
462
  def check_no_wildcard_expansion(msg) # :nodoc:
463
463
  # @TODO@ Do this for NSEC3 records!!!
464
464
  proven_no_wildcards = false
465
- name = msg.question()[0].qname
466
465
  [msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
467
466
  nsec_rrsets.each {|nsecs|
468
467
  nsecs.rrs.each {|nsec|
@@ -800,6 +799,19 @@ module Dnsruby
800
799
 
801
800
  asn1 = OpenSSL::ASN1::Sequence.new([r_asn1, s_asn1]).to_der
802
801
  verified = keyrec.public_key.verify(OpenSSL::Digest::DSS1.new, asn1, sig_data)
802
+ elsif [Algorithms.ECDSAP256SHA256, Algorithms.ECDSAP384SHA384].include?(sigrec.algorithm)
803
+ byte_size = (keyrec.public_key.group.degree + 7) / 8
804
+ sig_bytes = sigrec.signature[0..(byte_size - 1)]
805
+ sig_char = sigrec.signature[byte_size..-1] || ''
806
+ asn1 = OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
807
+
808
+ digest_obj = if sigrec.algorithm == Algorithms.ECDSAP384SHA384
809
+ OpenSSL::Digest::SHA384.new
810
+ else
811
+ OpenSSL::Digest::SHA256.new
812
+ end
813
+
814
+ verified = keyrec.public_key.dsa_verify_asn1(digest_obj.digest(sig_data), asn1)
803
815
  else
804
816
  raise RuntimeError.new("Algorithm #{sigrec.algorithm.code} unsupported by Dnsruby")
805
817
  end
@@ -1316,8 +1328,7 @@ module Dnsruby
1316
1328
  msg.security_level = Message::SecurityLevel.SECURE
1317
1329
  return true
1318
1330
  end
1319
- rescue VerifyError => e
1320
- # print "Verify failed : #{e}\n"
1331
+ rescue VerifyError
1321
1332
  end
1322
1333
  end
1323
1334
  if (error)
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Dnsruby
2
- VERSION = '1.61.2'
2
+ VERSION = '1.61.7'
3
3
  end
@@ -68,7 +68,7 @@ module Dnsruby
68
68
  end
69
69
  zone.push(rr)
70
70
  end
71
- rescue Exception => e
71
+ rescue Exception
72
72
  raise ParseException.new("Error reading line #{io.lineno} of #{io.inspect} : [#{line}]")
73
73
  end
74
74
  end
@@ -303,7 +303,7 @@ module Dnsruby
303
303
  (split.length - 2).times {|i| line += "#{split[i+2]} "}
304
304
  line += "\n"
305
305
  split = line.split
306
- rescue Error => e
306
+ rescue Error
307
307
  end
308
308
 
309
309
  # Add the type so we can load the zone one RRSet at a time.
@@ -244,7 +244,6 @@ module Dnsruby
244
244
  end
245
245
 
246
246
  def parseRR(rec) #:nodoc: all
247
- name = rec.name
248
247
  type = rec.type
249
248
  delta = Delta.new
250
249
 
data/test/localdns.rb ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative 'spec_helper'
4
+
5
+ require_relative "test_dnsserver"
6
+
7
+ class SimpleTCPPipeliningUDPServer < Async::DNS::Server
8
+ PORT = 53938
9
+ IP = '127.0.0.1'
10
+
11
+ def initialize(**options)
12
+ super(options)
13
+
14
+ @handlers << TcpPipelineHandler.new(self, IP, PORT)
15
+ @handlers << Async::DNS::UDPServerHandler.new(self, IP, PORT)
16
+
17
+ end
18
+
19
+ def process(name, resource_class, transaction)
20
+ @logger.debug "name: #{name}"
21
+ transaction.respond!("93.184.216.34", { resource_class: ::Resolv::DNS::Resource::IN::A })
22
+ end
23
+
24
+ end
25
+
26
+
27
+ if __FILE__ == $0
28
+ RubyDNS::run_server(server_class: SimpleTCPPipeliningUDPServer)
29
+ end