dnsruby 1.72.4 → 1.73.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fdfd21c32204b5b7e25176c74fc30b08913ebae7470da9c5310b07d9cf276fe
4
- data.tar.gz: 1ea91383c386f569733c3cf25d27b952674e8e30ab2e1c6174567926914f6928
3
+ metadata.gz: 37430615b19024c80842a7a51b1e3bc062edfc5437aaf635b7284a45193f2cff
4
+ data.tar.gz: 8c48e7b36abc8ff85fa07c4d367216f63c9043a117985292d76ef5b2c8374db8
5
5
  SHA512:
6
- metadata.gz: f1a7a0767ba62316d4b5c84e4a944924dca22ddf8a27fbddfc81299362f80ffe72a6a31613a0734a3cb7f49ab8f3bf34af2af9349c04c7c4b3bb732d35f55256
7
- data.tar.gz: a1560b6ac411d65b4ccd360a9741c97a585a401bc0ee9ef2bf72e5f61d87844df2af2092fb0c66ee5b6f7caef92646453daae412ad8f0af088659569c754b6c2
6
+ metadata.gz: 6480cd717d542a445fe756f18fc0a12bb2c46980a5ea828a16d232914a4f77675e239df81b691b775248be0f1598b546392aaa630c96410dfdd073fd2d6d7744
7
+ data.tar.gz: b89a52ced65d7190964aa96b0acbcfdfabb5b2eced3b5cd2e9b0e2659522610681a8c7a08bb074a38e60d58cd2de6d3bff1d2c61e1429bcfdb7c66a08db54e48
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: alexdalitz
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "bundler" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -8,10 +8,10 @@ jobs:
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- ruby: [ '3.1', '3.2', '3.3' ] # , 'ruby-head' ]
11
+ ruby: [ '3.2', '3.3', '3.4' ] # , 'ruby-head' ]
12
12
  rubyopt: ['']
13
13
  include:
14
- - ruby: '3.3'
14
+ - ruby: '3.4'
15
15
  rubyopt: "--enable-frozen-string-literal --debug-frozen-string-literal"
16
16
 
17
17
  name: Ruby ${{ matrix.ruby }} tests
data/RELEASE_NOTES.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Release Notes
2
2
 
3
+ ## v1.73.0
4
+
5
+ * Ruby 3.4 updates - thanks @zarqman!
6
+ * Enable setting up a custom UDP size when DNSSEC validation is disabled
7
+ * EDNS OPT RR for udp_size > 512 - thanks @mrideout!
8
+ * Test code improvements - thanks @mrideout!
9
+ * base64 gem version fixes
10
+ * Fix for file descriptor leak on truncated UDP messages
11
+
3
12
  ## v1.72.4
4
13
 
5
14
  * allow parsing case insensitive property tags for CAA records - thanks ruby-dev!
data/dnsruby.gemspec CHANGED
@@ -15,7 +15,10 @@ SPEC = Gem::Specification.new do |s|
15
15
  stub resolver. It aims to comply with all DNS RFCs, including
16
16
  DNSSEC NSEC3 support.'
17
17
  s.license = "Apache License, Version 2.0"
18
-
18
+
19
+ # Add explicit Ruby version requirement
20
+ s.required_ruby_version = '>= 2.8.0'
21
+
19
22
  s.files = `git ls-files -z`.split("\x0")
20
23
 
21
24
  s.post_install_message = \
@@ -36,18 +39,14 @@ DNSSEC NSEC3 support.'
36
39
  }
37
40
 
38
41
  s.add_development_dependency 'rake', '>= 13.0.6'
39
- s.add_development_dependency 'minitest', '~> 5.18.0'
42
+ s.add_development_dependency 'minitest', '~> 5.25'
40
43
  s.add_development_dependency 'rubydns', '>= 2.0.2'
41
44
  s.add_development_dependency 'nio4r', '>= 2.5.8'
42
45
  s.add_development_dependency 'minitest-display', '>= 0.3.1'
43
- s.add_development_dependency('yard', '>= 0.9')
44
- # s.add_development_dependency('io-event', '>=1.1.7')
45
-
46
- if RUBY_VERSION >= "1.9.3"
47
- s.add_development_dependency 'coveralls', '~> 0.8.23'
48
- end
46
+ s.add_development_dependency 'yard', '>= 0.9'
47
+ s.add_development_dependency 'coveralls', '~> 0.8.23'
49
48
 
50
- s.add_runtime_dependency 'base64', '~> 0.2.0'
51
- s.add_runtime_dependency 'logger', '~> 1.6.5'
49
+ s.add_runtime_dependency 'base64', '>= 0.2'
50
+ s.add_runtime_dependency 'logger', '~> 1.6'
52
51
  s.add_runtime_dependency 'simpleidn', '~> 0.2.1'
53
52
  end
@@ -318,11 +318,6 @@ module Dnsruby
318
318
  f.each {|line|
319
319
  line.sub!(/[#;].*/, '')
320
320
  keyword, *args = line.split(/\s+/)
321
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.8")
322
- args.each { |arg|
323
- arg.untaint
324
- }
325
- end
326
321
  next unless keyword
327
322
  case keyword
328
323
  when 'port'
data/lib/dnsruby/hosts.rb CHANGED
@@ -57,19 +57,12 @@ module Dnsruby
57
57
  line.sub!(/#.*/, '')
58
58
  addr, hostname, *aliases = line.split(/\s+/)
59
59
  next unless addr
60
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.8")
61
- addr.untaint
62
- hostname.untaint
63
- end
64
60
  @addr2name[addr] = [] unless @addr2name.include? addr
65
61
  @addr2name[addr] << hostname
66
62
  @addr2name[addr] += aliases
67
63
  @name2addr[hostname] = [] unless @name2addr.include? hostname
68
64
  @name2addr[hostname] << addr
69
65
  aliases.each {|n|
70
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.8")
71
- n.untaint
72
- end
73
66
  @name2addr[n] = [] unless @name2addr.include? n
74
67
  @name2addr[n] << addr
75
68
  }
@@ -299,15 +299,17 @@ module Dnsruby
299
299
  # is sent (TSIG signatures will be applied if configured on the Resolver).
300
300
  # Retries are handled as the Resolver is configured to do.
301
301
  # Incoming responses to the query are not cached or validated (although TCP
302
- # fallback will be performed if the TC bit is set and the (Single)Resolver has
303
- # ignore_truncation set to false).
304
- # Note that the Message is left untouched - this means that no OPT records are
305
- # added, even if the UDP transport for the server is specified at more than 512
306
- # bytes. If it is desired to use EDNS for this packet, then you should call
307
- # the Dnsruby::PacketSender#prepare_for_dnssec(msg), or
308
- # Dnsruby::PacketSender#add_opt_rr(msg)
309
- # The return value from this method is the [response, error] tuple. Either of
310
- # these values may be nil - it is up to the client to check.
302
+ # fallback will be performed if the TC bit is set and the (Single)Resolver
303
+ # has ignore_truncation set to false).
304
+ # Note that the Message may be modified before sending: if the configured
305
+ # udp_size is >512 bytes, DNSSEC is not set, and no OPT record is already
306
+ # present, then an OPT record will be added automatically to support EDNS
307
+ # per RFC 6891.
308
+ # If it is desired to customize the OPT record or use EDNS in other cases,
309
+ # then you should call the Dnsruby::PacketSender#prepare_for_dnssec(msg),
310
+ # or Dnsruby::PacketSender#add_opt_rr(msg).
311
+ # The return value from this method is the [response, error] tuple. Either
312
+ # of these values may be nil - it is up to the client to check.
311
313
  #
312
314
  # example :
313
315
  #
@@ -888,6 +890,13 @@ module Dnsruby
888
890
  return
889
891
  end
890
892
 
893
+ # According to RFC 6891, a UDP payload size >512 bytes requires an
894
+ # EDNS OPT RR in the message.
895
+ if @parent.udp_size > 512 && !msg.get_opt
896
+ TheLog.debug("Automatically adding EDNS OPT RR for udp_size=#{ @parent.udp_size }")
897
+ msg.add_additional(Dnsruby::RR::OPT.new(@parent.udp_size))
898
+ end
899
+
891
900
  begin
892
901
  msg.encode
893
902
  rescue EncodeError => err
@@ -383,7 +383,7 @@ module Dnsruby
383
383
  ]
384
384
  )
385
385
 
386
- pkey = OpenSSL::PKey::DSA.new(asn1.to_der)
386
+ OpenSSL::PKey::DSA.new(asn1.to_der)
387
387
  end
388
388
 
389
389
  # RFC6605, section 4
@@ -372,21 +372,25 @@ module Dnsruby
372
372
  end
373
373
 
374
374
  def remove_id(id)
375
-
376
375
  @@mutex.synchronize do
377
- socket = @@query_hash[id].socket
378
- @@timeouts.delete(id)
379
- @@query_hash.delete(id)
380
- @@socket_hash[socket].delete(id)
381
-
382
- decrement_remaining_queries(socket) if persistent?(socket)
383
-
384
- if !persistent?(socket) || max_attained?(socket)
385
- @@sockets.delete(socket)
386
- @@socket_hash.delete(socket)
387
- Dnsruby.log.debug("Closing socket #{socket}")
388
- socket.close rescue nil
389
- end
376
+ remove_id_from_mutex_synchronized_block(id)
377
+ end
378
+ end
379
+
380
+ # THIS MUST BE CALLED FROM INSIDE A @@mutex SYNCHRONISED BLOCK!
381
+ def remove_id_from_mutex_synchronized_block(id)
382
+ socket = @@query_hash[id].socket
383
+ @@timeouts.delete(id)
384
+ @@query_hash.delete(id)
385
+ @@socket_hash[socket].delete(id)
386
+
387
+ decrement_remaining_queries(socket) if persistent?(socket)
388
+
389
+ if !persistent?(socket) || max_attained?(socket)
390
+ @@sockets.delete(socket)
391
+ @@socket_hash.delete(socket)
392
+ Dnsruby.log.debug("Closing socket #{socket}")
393
+ socket.close rescue nil
390
394
  end
391
395
  end
392
396
 
@@ -550,12 +554,10 @@ module Dnsruby
550
554
  query_header_id = @@query_hash[id].query.header.id
551
555
  if (query_header_id == e.partial_message.header.id)
552
556
  # process the response
553
- client_queue = nil
554
- res = nil
555
- query=nil
556
557
  client_queue = @@query_hash[id].client_queue
557
558
  res = @@query_hash[id].single_resolver
558
559
  query = @@query_hash[id].query
560
+ remove_id_from_mutex_synchronized_block(id)
559
561
 
560
562
  # NOW RESEND OVER TCP!
561
563
  Thread.new {
@@ -1,3 +1,3 @@
1
1
  module Dnsruby
2
- VERSION = '1.72.4'
2
+ VERSION = '1.73.0'
3
3
  end
data/test/spec_helper.rb CHANGED
@@ -26,7 +26,7 @@ require 'minitest'
26
26
  require 'minitest/autorun'
27
27
  require 'minitest/display'
28
28
 
29
- MiniTest::Display.options = {
29
+ Minitest::Display.options = {
30
30
  suite_names: true,
31
31
  color: true,
32
32
  print: {
@@ -43,3 +43,18 @@ MiniTest::Display.options = {
43
43
  require_relative '../lib/dnsruby'
44
44
  require_relative 'test_utils'
45
45
  end.()
46
+
47
+ def with_retries(max_attempts: 5, exceptions: [Dnsruby::ServFail, Dnsruby::ResolvTimeout], success_check: ->(result) { result }, &block)
48
+ attempts = 0
49
+ while attempts < max_attempts
50
+ begin
51
+ result = block.call
52
+ return result if success_check.call(result) # e.g., for nil-check: ->(r) { r }
53
+ rescue *exceptions => e
54
+ puts "Retry #{attempts + 1}/#{max_attempts}: #{e.class} - #{e.message}" if ENV['DEBUG_TESTS']
55
+ end
56
+ sleep(1)
57
+ attempts += 1
58
+ end
59
+ raise Minitest::Assertion, "Failed after #{max_attempts} retries"
60
+ end
data/test/tc_dns.rb CHANGED
@@ -167,9 +167,9 @@ class TestDNS < Minitest::Test
167
167
  end # test_online
168
168
 
169
169
  def test_search_query_reverse
170
- #
170
+ #
171
171
  # test that getname() DTRT with reverse lookups
172
- #
172
+ #
173
173
  tests = [
174
174
  {
175
175
  :ip => '198.41.0.4',
@@ -183,7 +183,7 @@ class TestDNS < Minitest::Test
183
183
 
184
184
  res = DNS.new
185
185
  tests.each do |test|
186
- name = res.getname(test[:ip])
186
+ name = with_retries { res.getname(test[:ip]) }
187
187
 
188
188
  assert_instance_of(Name,name)
189
189
 
@@ -235,7 +235,7 @@ class TestDNS < Minitest::Test
235
235
  res.config.apply_search_list=true
236
236
  end
237
237
 
238
- ans, query = res.send_query(test[:name])
238
+ ans, _ = res.send_query(test[:name])
239
239
 
240
240
  assert_instance_of(Message, ans)
241
241
 
@@ -249,14 +249,14 @@ class TestDNS < Minitest::Test
249
249
  end
250
250
  end
251
251
 
252
- def test_port
253
- d = DNS.new({:port => 5353})
254
- assert(d.to_s.include?"5353")
255
- end
252
+ def test_port
253
+ d = DNS.new({:port => 5353})
254
+ assert(d.to_s.include?"5353")
255
+ end
256
256
 
257
- def test_port_nil
258
- d = DNS.new({:port => nil})
259
- assert(d.to_s.include? Dnsruby::Config::DEFAULT_PORT.to_s)
260
- end
257
+ def test_port_nil
258
+ d = DNS.new({:port => nil})
259
+ assert(d.to_s.include? Dnsruby::Config::DEFAULT_PORT.to_s)
260
+ end
261
261
 
262
262
  end
@@ -350,7 +350,7 @@ d0
350
350
  packet = Message.decode(packetdata)
351
351
  assert_equal( '\\\\e.eg.secret-wg.org',(packet.answer)[0].name.to_s,"Correctly dealt escaped backslash from wireformat \\\..eg.secret-wg.org")
352
352
 
353
- testrr=RR.create(
353
+ RR.create(
354
354
  :name => '\\e.eg.secret-wg.org',
355
355
  :type => 'TXT',
356
356
  :txtdata => '"WildCard Match"',
@@ -360,7 +360,6 @@ d0
360
360
 
361
361
 
362
362
 
363
- klass = "IN"
364
363
  ttl = 43200
365
364
  name = 'def0au&lt.example.com'
366
365
 
@@ -471,17 +470,17 @@ d0
471
470
  type = data[:type]
472
471
  # foreach my $meth (keys %{$data}) {
473
472
  (data.keys.each do |meth|
474
- if (meth == :type)
475
- assert_equal(Types.new(data[meth]).to_s, rr.send(meth).to_s, "#{type} - #meth() correct")
476
- else
477
- assert_equal(data[meth].to_s, rr.send(meth).to_s, "#{type} - #meth() correct")
478
- end
473
+ if (meth == :type)
474
+ assert_equal(Types.new(data[meth]).to_s, rr.send(meth).to_s, "#{type} - #meth() correct")
475
+ else
476
+ assert_equal(data[meth].to_s, rr.send(meth).to_s, "#{type} - #meth() correct")
477
+ end
479
478
  end)
480
479
 
481
480
  rr2 = RR.new_from_string(rr.to_s)
482
481
  assert_equal(rr.to_s, rr2.to_s, "#{type} - Parsing from string works")
483
- end
482
+ end
484
483
 
485
484
  Name::Label.set_max_length(Name::Label::MaxLabelLength)
486
- end
487
485
  end
486
+ end
data/test/tc_hs.rb CHANGED
@@ -2,11 +2,6 @@ require_relative 'spec_helper'
2
2
 
3
3
  class TestDNS < Minitest::Test
4
4
 
5
- def setup
6
- Dnsruby::Config.reset
7
- end
8
-
9
-
10
5
  # Illustrates that when a message whose class is 'HS' is sent to
11
6
  # a DNS server that does not support the HS class, using send_plain_message,
12
7
  # the response returns with an rcode of NOTIMP and a Dnsruby::NotImp error.
data/test/tc_message.rb CHANGED
@@ -49,7 +49,7 @@ class TestMessage < Minitest::Test
49
49
  def test_rd_flag_displayed_when_true
50
50
  message = sample_message
51
51
  message.header.instance_variable_set(:@rd, true)
52
- assert /;; flags(.+)rd/.match(message.to_s), message
52
+ assert(/;; flags(.+)rd/.match(message.to_s), message)
53
53
  end
54
54
 
55
55
  def test_header_line_contains_opcode_and_status_and_id
data/test/tc_name.rb CHANGED
@@ -24,7 +24,7 @@ class TestName < Minitest::Test
24
24
  Name::Label.set_max_length(Name::Label::MaxLabelLength) # Other tests may have changed this
25
25
  # Test max label length = 63
26
26
  begin
27
- name = Name.create("a.b.12345678901234567890123456789012345678901234567890123456789012345.com")
27
+ Name.create("a.b.12345678901234567890123456789012345678901234567890123456789012345.com")
28
28
  assert(false, "Label of more than max=63 allowed")
29
29
  rescue ResolvError
30
30
  end
@@ -33,7 +33,7 @@ class TestName < Minitest::Test
33
33
  def test_name_length
34
34
  # Test max name length=255
35
35
  begin
36
- name = Name.create("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.com")
36
+ Name.create("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.com")
37
37
  assert(false, "Name of length > 255 allowed")
38
38
  rescue ResolvError
39
39
  end
data/test/tc_nxt.rb CHANGED
@@ -60,7 +60,6 @@ class TestNXT < Minitest::Test
60
60
  def test_binary_string_to_codes
61
61
  test_type_codes_as_code_array = [1, 6, 28, 100]
62
62
  test_type_codes_as_name_array = %w(A SOA AAAA UINFO)
63
- test_type_codes_as_number = 1267650600228229401496971640898 # (2 ** 1) + (2 ** 6) + (2 ** 28) + (2 ** 100)
64
63
  test_type_codes_as_binary_string = "\x10\x0\x0\x0\x0\x0\x0\x0\x0\x10\x0\x0\x42"
65
64
  assert_equal(test_type_codes_as_code_array, RR::NXT::NxtTypes.binary_string_to_codes(test_type_codes_as_binary_string))
66
65
  assert_equal(test_type_codes_as_name_array, RR::NXT::NxtTypes.binary_string_to_names(test_type_codes_as_binary_string))
data/test/tc_recur.rb CHANGED
@@ -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.
@@ -20,10 +20,7 @@ class TestRecur < Minitest::Test
20
20
  def test_recur
21
21
  Dnsruby::PacketSender.clear_caches
22
22
  r = Dnsruby::Recursor.new
23
- # Dnsruby::TheLog.level = Logger::DEBUG
24
- ret = r.query("uk", Dnsruby::Types.DNSKEY)
25
- # print ret
26
- assert ret, "Query result was nil."
23
+ ret = with_retries(max_attempts: 10, exceptions: [Dnsruby::ResolvError]) { r.query("uk", Dnsruby::Types.DNSKEY) }
27
24
  assert ret.answer.length > 0, "Answer length should > 0, but was #{ret.answer.length}."
28
25
  # ret = r.query_dorecursion("aaa.bigzone.uk-dnssec.nic.uk", Dnsruby::Types.DNSKEY)
29
26
  # ret = r.query_dorecursion("uk-dnssec.nic.uk", Dnsruby::Types.DNSKEY)
data/test/tc_resolv.rb CHANGED
@@ -51,19 +51,26 @@ class TestResolv < Minitest::Test
51
51
  end
52
52
  end
53
53
 
54
-
55
54
  def test_resolv_address_to_name
56
55
 
57
- assert_equal(SHORT_ABSOLUTE_NAME, Dnsruby::Resolv.getname(IPV4_ADDR).to_s(true))
56
+ name = with_retries { Dnsruby::Resolv.getname(IPV4_ADDR) }
57
+ assert_equal(SHORT_ABSOLUTE_NAME, name.to_s(true))
58
58
 
59
59
  assert_raises(Dnsruby::ResolvError) do
60
60
  Dnsruby::Resolv.getname(SHORT_ABSOLUTE_NAME)
61
61
  end
62
62
 
63
- names = Dnsruby::Resolv.getnames(IPV4_ADDR)
63
+ names = with_retries { Dnsruby::Resolv.getnames(IPV4_ADDR) }
64
64
  assert_equal(1, names.size)
65
65
  assert_equal(SHORT_ABSOLUTE_NAME, names.first.to_s(true))
66
- Dnsruby::Resolv.each_name(IPV4_ADDR) { |name| assert_equal(SHORT_ABSOLUTE_NAME, name.to_s(true))}
66
+
67
+ found_names = with_retries(success_check: ->(_) { true }) do
68
+ names = []
69
+ Dnsruby::Resolv.each_name(IPV4_ADDR) { |name| names << name }
70
+ names
71
+ end
72
+
73
+ assert_equal(SHORT_ABSOLUTE_NAME, found_names.first.to_s(true))
67
74
  end
68
75
 
69
76
  def test_resolv_address_to_address
data/test/tc_resolver.rb CHANGED
@@ -74,13 +74,25 @@ class TestResolver < Minitest::Test
74
74
 
75
75
  def test_send_plain_message
76
76
  resolver = Resolver.new('1.1.1.1')
77
- response, error = resolver.send_plain_message(Message.new("example.com", Types.A))
77
+
78
+ response, error = with_retries(success_check: ->((res, err)) { err.nil? || ! [Dnsruby::ServFail, Dnsruby::ResolvTimeout].include?(err.class) }) do
79
+ res, err = resolver.send_plain_message(Message.new("example.com", Types.A))
80
+ raise err if [Dnsruby::ServFail, Dnsruby::ResolvTimeout].include?(err.class)
81
+ [res, err]
82
+ end
83
+
78
84
  assert_nil_error(error)
79
85
  assert_valid_response(response)
80
86
 
81
87
  m = Message.new(BAD_DOMAIN_NAME)
82
88
  m.header.rd = true
83
- response, error = resolver.send_plain_message(m)
89
+
90
+ response, error = with_retries(success_check: ->((res, err)) { err.class == Dnsruby::NXDomain || ! [Dnsruby::ServFail, Dnsruby::ResolvTimeout].include?(err.class) }) do
91
+ res, err = resolver.send_plain_message(m)
92
+ raise err if [Dnsruby::ServFail, Dnsruby::ResolvTimeout].include?(err.class)
93
+ [res, err]
94
+ end
95
+
84
96
  assert_valid_response(response)
85
97
  assert_error_is_exception(error, NXDomain)
86
98
  end
@@ -284,8 +296,73 @@ class TestResolver < Minitest::Test
284
296
  def test_eventtype_api
285
297
  # @TODO@ TEST THE Resolver::EventType interface!
286
298
  end
287
- end
288
299
 
300
+ def capture_sent_message(res, domain, pre_opt=nil)
301
+ q = Queue.new
302
+ res.send_async(Dnsruby::Message.new("test.invalid"), q)
303
+ q.pop
304
+ resolver_ruby = res.instance_variable_get("@resolver_ruby")
305
+ class << resolver_ruby
306
+ attr_accessor :message
307
+ alias_method :original_send_async, :send_async
308
+ def send_async(msg, client_queue, client_query_id=nil)
309
+ @message = msg
310
+ original_send_async(msg, client_queue, client_query_id)
311
+ end
312
+ end
313
+ msg = Dnsruby::Message.new(domain)
314
+ msg.add_additional(pre_opt) if pre_opt
315
+ res.send_async(msg, q)
316
+ _id, _response, _error = q.pop
317
+ resolver_ruby.message
318
+ end
319
+
320
+ def test_custom_udp_size
321
+ [false, true].each do |dnssec_setting|
322
+ [512, 513].each do |udp_size_setting|
323
+ res = Dnsruby::Resolver.new(:udp_size => udp_size_setting, :dnssec => dnssec_setting)
324
+ sent_msg = capture_sent_message(res, "example.com")
325
+
326
+ # The OPT RR is only present if the udp_size is > 512
327
+ opt = sent_msg.get_opt
328
+ if dnssec_setting
329
+ # DNSSEC overrides udp_size to 4096
330
+ assert(opt)
331
+ assert_equal(4096, opt.klass.code)
332
+ else
333
+ if udp_size_setting <= 512
334
+ assert_nil(opt)
335
+ else
336
+ assert(opt)
337
+ assert_equal(udp_size_setting, opt.klass.code)
338
+ end
339
+ end
340
+ if opt
341
+ assert_equal(0, opt.version)
342
+ assert_equal(0, opt.flags)
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ def test_no_duplicate_opt_when_pre_existing
349
+ [false, true].each do |dnssec_setting|
350
+ [512, 513].each do |udp_size_setting|
351
+ res = Dnsruby::Resolver.new(:udp_size => udp_size_setting, :dnssec => dnssec_setting)
352
+ pre_size = dnssec_setting ? 4096 : 1024
353
+ pre_opt = Dnsruby::RR::OPT.new(pre_size)
354
+ sent_msg = capture_sent_message(res, "example.com", pre_opt)
355
+
356
+ opt = sent_msg.get_opt
357
+ assert(opt)
358
+ assert_equal(1, sent_msg.additional.length) # No duplicate added
359
+ assert_equal(pre_size, opt.klass.code) # Original payload size unchanged
360
+ assert_equal(0, opt.version)
361
+ assert_equal(0, opt.flags) # Flags unchanged (code doesn't modify existing OPT)
362
+ end
363
+ end
364
+ end
365
+ end
289
366
 
290
367
  # Tests to see that query_raw handles send_plain_message's return values correctly.
291
368
  class TestRawQuery < Minitest::Test
@@ -58,7 +58,7 @@ class TestRrUnknown < Minitest::Test
58
58
  assert_equal('10.0.0.1', rr.address.to_s,'Unknown RR representation for A parsed OK')
59
59
 
60
60
  begin
61
- res=RR.new_from_string('e.example IN A \# 4 0A0000 01 11 ')
61
+ RR.new_from_string('e.example IN A \# 4 0A0000 01 11 ')
62
62
  flunk "Should fail on inconsistent length and hex presentation"
63
63
  rescue Exception
64
64
  # like($@, '/\\\# 4 0A0000 01 11 assert_equal inconsistent\ length does not match content/', 'Fails on inconsassert_equaltent length and hex presentation')
data/test/tc_rr.rb CHANGED
@@ -319,10 +319,10 @@ class TestRR < Minitest::Test
319
319
  end
320
320
 
321
321
  def test_cert
322
- rr = RR.create("test.kht.se. 60 IN CERT PGP 0 0 mQGiBDnY2vERBAD3cOxqoAYHYzS+xttvuyN9wZS8CrgwLIlT8Ewo/CCFI11PEO+gJyNPvWPRQsyt1SE60reaIsie2bQTg3DYIg0PmH+ZOlNkpKesPULzdlw4Rx3dD/M3Lkrm977h4Y70ZKC+tbvoYKCCOIkUVevny1PVZ+mB94rb0mMgawSTrct03QCg/w6aHNJFQV7O9ZQ1Fir85M3RS8cEAOo4/1ASVudz3qKZQEhU2Z9O2ydXqpEanHfGirjWYi5RelVsQ9IfBSPFaPAWzQ24nvQ18NU7TgdDQhP4meZXiVXcLBR5Mee2kByf2KAnBUF9aah5s8wZbSrC6u8xEZLuiauvWmCUIWe0Ylc1/L37XeDjrBI2pT+k183X119d6Fr1BACGfZVGsot5rxBUEFPPSrBqYXG/0hRYv9Eq8a4rJAHK2IUWYfivZgL4DtrJnHlha+H5EPQVYkIAN3nGjXoHmosY+J3Sk+GyR+dCBHEwCkoHMKph3igczCEfxAWgqKeYd5mf+QQq2JKrkn2jceiIO7s3CrepeEFAjDSGuxhZjPJVm7QoRGFuaWVsIFAuIE1haG9uZXkgPGRhbm1AcHJpbWUuZ3VzaGkub3JnPohOBBARAgAOBQI52NrxBAsDAQICGQEACgkQ+75aMGJLskn6LgCbBXUD7UmGla5e1zyhuY667hP3F+UAoJIeDZJyRFkQAmb+u8KekRyLD1MLtDJEYW5pZWwgTWFob25leSAoU2Vjb25kYXJ5IEVtYWlsKSA8Z3VzaGlAZ3VzaGkub3JnPohgBBMRAgAgBQJF1J/XAhsjBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ+75aMGJLskkVhACggsivQ9qLhfdA1rGm6f8LRJBSC4wAoI930h+/hshClj6AkNwGRtHdf5XJuQINBDnY2vQQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/9eGjzF2gDh6U7I72x/6bSdlExx2LvIF92OZKc0S55IOS4Lgzs7Hbfm1aOL4oJt7wBg94xkF4cerxz7y8R9J+k3GNl14KOjbYaMAh1rdxdAzikYMH1p1hS78GMtwxky6jE5en87BGGMmnbC84JlxwN+MD7diu8D0Gkgjj/pxOp32D5jEe02wBPVjFTpFLJjpFniLUY6AohRDEdSuZwWPuoKVWhpeWkasNn5qgwGyDREbXpyPsU02BkwE4JiGs+JMMdOn9KMh5dxiuwsMM9gHiQZS3mSNBBKPWI5ZXsdStVFvapjf2FUFDXLUbTROPv1Xhqf0u7YYORFnWeVtvzKIxVaiEYEGBECAAYFAjnY2vQACgkQ+75aMGJLsklBWgCeN7z9xk52y/aoaCuF6hYb0d+3k98AoMRxvHuXI1Nc2FXY/x65PwHiUbaY")
323
- rr = RR.create("all.rr.org. IN CERT 6 0 0 FFsAyW1dVK7hIGuvhN56r26UwJx/")
324
- # rr = RR.create("all.rr.org. IN WKS 128.32.0.10 UDP who route timed domain")
325
- rr = RR.create('selector._domainkey.all.rr.org. IN TXT "v=DKIM1; n=Use=20DKIM; p=AwEAAZfbYw8SffZwsbrCLbC+JLErREIF6Yfe9aqsa1Pz6tpGWiLxm9rSL6/YoBvNP3UWX91YDF0JMo6lhu3UIZjITvIwDhx+RJYko9vLzaaJKXGf3ygy6z+deWoZJAV1lTY0Ltx9genboe88CSCHw9aSLkh0obN9Ck8R6zAMYR19ciM/; t=s"')
322
+ RR.create("test.kht.se. 60 IN CERT PGP 0 0 mQGiBDnY2vERBAD3cOxqoAYHYzS+xttvuyN9wZS8CrgwLIlT8Ewo/CCFI11PEO+gJyNPvWPRQsyt1SE60reaIsie2bQTg3DYIg0PmH+ZOlNkpKesPULzdlw4Rx3dD/M3Lkrm977h4Y70ZKC+tbvoYKCCOIkUVevny1PVZ+mB94rb0mMgawSTrct03QCg/w6aHNJFQV7O9ZQ1Fir85M3RS8cEAOo4/1ASVudz3qKZQEhU2Z9O2ydXqpEanHfGirjWYi5RelVsQ9IfBSPFaPAWzQ24nvQ18NU7TgdDQhP4meZXiVXcLBR5Mee2kByf2KAnBUF9aah5s8wZbSrC6u8xEZLuiauvWmCUIWe0Ylc1/L37XeDjrBI2pT+k183X119d6Fr1BACGfZVGsot5rxBUEFPPSrBqYXG/0hRYv9Eq8a4rJAHK2IUWYfivZgL4DtrJnHlha+H5EPQVYkIAN3nGjXoHmosY+J3Sk+GyR+dCBHEwCkoHMKph3igczCEfxAWgqKeYd5mf+QQq2JKrkn2jceiIO7s3CrepeEFAjDSGuxhZjPJVm7QoRGFuaWVsIFAuIE1haG9uZXkgPGRhbm1AcHJpbWUuZ3VzaGkub3JnPohOBBARAgAOBQI52NrxBAsDAQICGQEACgkQ+75aMGJLskn6LgCbBXUD7UmGla5e1zyhuY667hP3F+UAoJIeDZJyRFkQAmb+u8KekRyLD1MLtDJEYW5pZWwgTWFob25leSAoU2Vjb25kYXJ5IEVtYWlsKSA8Z3VzaGlAZ3VzaGkub3JnPohgBBMRAgAgBQJF1J/XAhsjBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ+75aMGJLskkVhACggsivQ9qLhfdA1rGm6f8LRJBSC4wAoI930h+/hshClj6AkNwGRtHdf5XJuQINBDnY2vQQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/9eGjzF2gDh6U7I72x/6bSdlExx2LvIF92OZKc0S55IOS4Lgzs7Hbfm1aOL4oJt7wBg94xkF4cerxz7y8R9J+k3GNl14KOjbYaMAh1rdxdAzikYMH1p1hS78GMtwxky6jE5en87BGGMmnbC84JlxwN+MD7diu8D0Gkgjj/pxOp32D5jEe02wBPVjFTpFLJjpFniLUY6AohRDEdSuZwWPuoKVWhpeWkasNn5qgwGyDREbXpyPsU02BkwE4JiGs+JMMdOn9KMh5dxiuwsMM9gHiQZS3mSNBBKPWI5ZXsdStVFvapjf2FUFDXLUbTROPv1Xhqf0u7YYORFnWeVtvzKIxVaiEYEGBECAAYFAjnY2vQACgkQ+75aMGJLsklBWgCeN7z9xk52y/aoaCuF6hYb0d+3k98AoMRxvHuXI1Nc2FXY/x65PwHiUbaY")
323
+ RR.create("all.rr.org. IN CERT 6 0 0 FFsAyW1dVK7hIGuvhN56r26UwJx/")
324
+ # RR.create("all.rr.org. IN WKS 128.32.0.10 UDP who route timed domain")
325
+ RR.create('selector._domainkey.all.rr.org. IN TXT "v=DKIM1; n=Use=20DKIM; p=AwEAAZfbYw8SffZwsbrCLbC+JLErREIF6Yfe9aqsa1Pz6tpGWiLxm9rSL6/YoBvNP3UWX91YDF0JMo6lhu3UIZjITvIwDhx+RJYko9vLzaaJKXGf3ygy6z+deWoZJAV1lTY0Ltx9genboe88CSCHw9aSLkh0obN9Ck8R6zAMYR19ciM/; t=s"')
326
326
  end
327
327
 
328
328
  def test_dhcid
@@ -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.
@@ -53,7 +53,7 @@ class TestSingleResolver < Minitest::Test
53
53
 
54
54
  def test_simple
55
55
  res = SingleResolver.new()
56
- m = res.query("ns1.google.com.")
56
+ res.query("ns1.google.com.")
57
57
  end
58
58
 
59
59
  def test_timeout
@@ -71,7 +71,7 @@ class TestSingleResolver < Minitest::Test
71
71
  res.port = port
72
72
  res.packet_timeout=1
73
73
  start_time = Time.now.to_i
74
- m = res.query("a.t.net-dns.org")
74
+ res.query("a.t.net-dns.org")
75
75
  fail "Got response when should have got none"
76
76
  rescue ResolvTimeout
77
77
  stop_time = Time.now.to_i
@@ -87,7 +87,7 @@ class TestSingleResolver < Minitest::Test
87
87
  res.packet_timeout=1
88
88
  start_time = Time.now.to_i
89
89
  # TheLog.level = Logger::DEBUG
90
- m = res.query("a.t.net-dns.org")
90
+ res.query("a.t.net-dns.org")
91
91
  fail "TCP timeouts"
92
92
  rescue ResolvTimeout
93
93
  # print "Got Timeout for TCP\n"
@@ -131,15 +131,7 @@ class TestSingleResolver < Minitest::Test
131
131
  res = SingleResolver.new
132
132
 
133
133
  Rrs.each do |data|
134
- packet=nil
135
- 2.times do
136
- begin
137
- packet = res.query(data[:name], data[:type])
138
- rescue ResolvTimeout
139
- end
140
- break if packet
141
- end
142
- assert(packet)
134
+ packet = with_retries { res.query(data[:name], data[:type]) }
143
135
  assert_equal(packet.question[0].qclass, 'IN', 'Class correct')
144
136
 
145
137
  assert(packet, "Got an answer for #{data[:name]} IN #{data[:type]}")
@@ -189,11 +181,11 @@ class TestSingleResolver < Minitest::Test
189
181
  def test_res_config
190
182
  res = Dnsruby::SingleResolver.new
191
183
 
192
- res.server=('a.t.net-dns.org')
184
+ with_retries(exceptions: [ArgumentError], success_check: ->(_) { true }) { res.server=('a.t.net-dns.org') }
193
185
  ip = res.server
194
186
  assert_equal('10.0.1.128', ip.to_s, 'nameserver() looks up IP.')
195
187
 
196
- res.server=('cname.t.net-dns.org')
188
+ with_retries(exceptions: [ArgumentError], success_check: ->(_) { true }) { res.server=('cname.t.net-dns.org') }
197
189
  ip = res.server
198
190
  assert_equal('10.0.1.128', ip.to_s, 'nameserver() looks up cname.')
199
191
  end
@@ -67,9 +67,9 @@ class TestTCPPipelining < Minitest::Test
67
67
 
68
68
  # Instantiate a new server that uses our tcp pipelining handler
69
69
  # For each query the server sends the query upstream (193.0.14.129)
70
- options = {
71
- server_class: TCPPipeliningServer,
72
- }
70
+ # options = {
71
+ # server_class: TCPPipeliningServer,
72
+ # }
73
73
 
74
74
  #RubyDNS::run_server(options) || true
75
75
  if !@@server
data/test/tc_tkey.rb CHANGED
@@ -29,12 +29,7 @@ class TestTKey < Minitest::Test
29
29
  # Canned data.
30
30
  # ------------------------------------------------------------------------------
31
31
 
32
- zone = "example.com"
33
- name = "123456789-test"
34
- klass = "IN"
35
- type = Dnsruby::Types.TKEY
36
32
  algorithm = "fake.algorithm.example.com"
37
- key = "fake key"
38
33
  inception = 100000 # use a strange fixed inception time to give a fixed
39
34
  # checksum
40
35
  expiration = inception + 24*60*60
@@ -72,5 +67,4 @@ class TestTKey < Minitest::Test
72
67
  # @TODO@ Test TKEY against server!
73
68
 
74
69
  end
75
-
76
- end
70
+ end
data/test/tc_update.rb CHANGED
@@ -34,7 +34,6 @@ class TestUpdate < Minitest::Test
34
34
  zone = "example.com";
35
35
  name = "foo.example.com";
36
36
  klass = Classes.CLASS32;
37
- klass2 = Classes.CH;
38
37
  type = Types.A;
39
38
  ttl = 43200;
40
39
  rdata = "10.1.2.3";
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dnsruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.72.4
4
+ version: 1.73.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dalitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-01 00:00:00.000000000 Z
11
+ date: 2025-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 5.18.0
33
+ version: '5.25'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 5.18.0
40
+ version: '5.25'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubydns
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -112,30 +112,30 @@ dependencies:
112
112
  name: base64
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 0.2.0
117
+ version: '0.2'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 0.2.0
124
+ version: '0.2'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: logger
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.6.5
131
+ version: '1.6'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.6.5
138
+ version: '1.6'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: simpleidn
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +164,8 @@ extra_rdoc_files:
164
164
  - EVENTMACHINE
165
165
  files:
166
166
  - ".coveralls.yml"
167
+ - ".github/FUNDING.yml"
168
+ - ".github/dependabot.yml"
167
169
  - ".github/workflows/ci.yml"
168
170
  - ".gitignore"
169
171
  - ".yardopts"
@@ -357,14 +359,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
357
359
  requirements:
358
360
  - - ">="
359
361
  - !ruby/object:Gem::Version
360
- version: '0'
362
+ version: 2.8.0
361
363
  required_rubygems_version: !ruby/object:Gem::Requirement
362
364
  requirements:
363
365
  - - ">="
364
366
  - !ruby/object:Gem::Version
365
367
  version: '0'
366
368
  requirements: []
367
- rubygems_version: 3.2.30
369
+ rubygems_version: 3.5.3
368
370
  signing_key:
369
371
  specification_version: 4
370
372
  summary: Ruby DNS(SEC) implementation