dnsruby 1.60.2 → 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 +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +26 -0
- data/.yardopts +7 -0
- data/README.md +8 -5
- data/RELEASE_NOTES.md +105 -0
- data/Rakefile +1 -0
- data/demo/digdlv.rb +1 -0
- data/demo/digroot.rb +2 -0
- data/dnsruby.gemspec +22 -14
- data/lib/dnsruby/DNS.rb +1 -1
- data/lib/dnsruby/bit_mapping.rb +2 -2
- data/lib/dnsruby/code_mappers.rb +6 -2
- data/lib/dnsruby/config.rb +29 -15
- data/lib/dnsruby/dnssec.rb +4 -1
- data/lib/dnsruby/hosts.rb +1 -4
- data/lib/dnsruby/ipv6.rb +5 -5
- data/lib/dnsruby/message/encoder.rb +5 -5
- data/lib/dnsruby/message/header.rb +15 -18
- data/lib/dnsruby/message/message.rb +2 -2
- data/lib/dnsruby/name.rb +19 -3
- data/lib/dnsruby/packet_sender.rb +25 -17
- data/lib/dnsruby/recursor.rb +17 -7
- data/lib/dnsruby/resolver.rb +43 -26
- data/lib/dnsruby/resource/CAA.rb +5 -2
- data/lib/dnsruby/resource/CDNSKEY.rb +17 -0
- data/lib/dnsruby/resource/CDS.rb +35 -0
- data/lib/dnsruby/resource/DNSKEY.rb +53 -13
- data/lib/dnsruby/resource/DS.rb +2 -5
- data/lib/dnsruby/resource/GPOS.rb +1 -1
- data/lib/dnsruby/resource/IN.rb +4 -1
- data/lib/dnsruby/resource/NSEC.rb +2 -2
- data/lib/dnsruby/resource/NSEC3PARAM.rb +1 -1
- data/lib/dnsruby/resource/NXT.rb +1 -1
- data/lib/dnsruby/resource/RR.rb +1 -1
- data/lib/dnsruby/resource/TLSA.rb +3 -3
- data/lib/dnsruby/resource/TXT.rb +12 -2
- data/lib/dnsruby/resource/URI.rb +57 -0
- data/lib/dnsruby/resource/generic.rb +3 -0
- data/lib/dnsruby/select_thread.rb +36 -28
- data/lib/dnsruby/single_verifier.rb +29 -8
- data/lib/dnsruby/validator_thread.rb +4 -4
- data/lib/dnsruby/version.rb +1 -1
- data/lib/dnsruby/zone_reader.rb +2 -2
- data/lib/dnsruby/zone_transfer.rb +5 -2
- data/lib/dnsruby.rb +4 -4
- data/test/localdns.rb +29 -0
- data/test/spec_helper.rb +34 -9
- data/test/tc_caa.rb +12 -1
- data/test/tc_dns.rb +15 -5
- data/test/tc_dnskey.rb +29 -0
- data/test/tc_ecdsa.rb +27 -0
- data/test/tc_encoding.rb +31 -0
- data/test/tc_escapedchars.rb +8 -9
- data/test/tc_gpos.rb +1 -1
- data/test/tc_hs.rb +4 -8
- data/test/tc_long_labels.rb +46 -0
- data/test/tc_message.rb +2 -2
- data/test/tc_name.rb +21 -2
- data/test/tc_nxt.rb +0 -1
- data/test/tc_recur.rb +4 -7
- data/test/tc_resolv.rb +14 -6
- data/test/tc_resolver.rb +114 -11
- data/test/tc_rr-opt.rb +8 -5
- data/test/tc_rr-txt.rb +7 -1
- data/test/tc_rr-unknown.rb +1 -1
- data/test/tc_rr.rb +37 -4
- data/test/tc_single_resolver.rb +9 -17
- data/test/tc_soak.rb +33 -67
- data/test/tc_tcp.rb +2 -2
- data/test/tc_tcp_pipelining.rb +30 -22
- data/test/tc_tkey.rb +1 -7
- data/test/tc_update.rb +0 -1
- data/test/tc_verifier.rb +15 -0
- data/test/test_dnsserver.rb +110 -17
- data/test/test_utils.rb +0 -2
- metadata +83 -46
- data/.travis.yml +0 -14
|
@@ -152,7 +152,7 @@ module Dnsruby
|
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
def self.encode_types(nsec)
|
|
155
|
-
output = ''
|
|
155
|
+
output = +''
|
|
156
156
|
# types represents all 65536 possible RR types.
|
|
157
157
|
# Split up types into sets of 256 different types.
|
|
158
158
|
type_codes = []
|
|
@@ -171,7 +171,7 @@ module Dnsruby
|
|
|
171
171
|
|
|
172
172
|
unless types_to_go.empty?
|
|
173
173
|
# Then create the bitmap for them
|
|
174
|
-
bitmap = ''
|
|
174
|
+
bitmap = +''
|
|
175
175
|
# keep on adding them until there's none left
|
|
176
176
|
pos = 0
|
|
177
177
|
bitmap_pos = 0
|
|
@@ -85,7 +85,7 @@ module Dnsruby
|
|
|
85
85
|
# end
|
|
86
86
|
#
|
|
87
87
|
def from_data(data) #:nodoc: all
|
|
88
|
-
hash_alg, flags, iterations,
|
|
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)
|
data/lib/dnsruby/resource/NXT.rb
CHANGED
|
@@ -95,7 +95,7 @@ class NXT < RR
|
|
|
95
95
|
next_domain = Name.create(next_domain) if next_domain.is_a?(String)
|
|
96
96
|
types = TypeBitmap.from_type_codes(types) if types.is_a?(Array)
|
|
97
97
|
|
|
98
|
-
binary_string = ''.
|
|
98
|
+
binary_string = ''.b
|
|
99
99
|
binary_string << next_domain.canonical
|
|
100
100
|
binary_string << BitMapping.reverse_binary_string_bits(types.to_binary_string)
|
|
101
101
|
binary_string
|
data/lib/dnsruby/resource/RR.rb
CHANGED
|
@@ -350,7 +350,7 @@ class RR
|
|
|
350
350
|
end
|
|
351
351
|
|
|
352
352
|
def hash # :nodoc:
|
|
353
|
-
vars = (self.instance_variables - [:@ttl]).sort
|
|
353
|
+
vars = (self.instance_variables - [:@ttl, :@rdata]).sort
|
|
354
354
|
vars.inject(0) do |hash_value, var_name|
|
|
355
355
|
hash_value ^ self.instance_variable_get(var_name).hash
|
|
356
356
|
end
|
|
@@ -33,8 +33,8 @@ module Dnsruby
|
|
|
33
33
|
# 255 Private use
|
|
34
34
|
attr_accessor :matching_type
|
|
35
35
|
# sec 2.1.4
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
74
|
+
rescue
|
|
75
75
|
raise ArgumentError, 'data is invalid cert '
|
|
76
76
|
end
|
|
77
77
|
end
|
data/lib/dnsruby/resource/TXT.rb
CHANGED
|
@@ -63,7 +63,7 @@ module Dnsruby
|
|
|
63
63
|
unquoted = false
|
|
64
64
|
seen_strings = false
|
|
65
65
|
pos = 0
|
|
66
|
-
input.sub
|
|
66
|
+
input = input.sub(/^\s*\(\s*/, "")
|
|
67
67
|
input.sub!(/\s*\)\s*$/, "")
|
|
68
68
|
input.each_char {|c|
|
|
69
69
|
if (((c == "'") || (c == '"')) && (!in_escaped) && (!unquoted))
|
|
@@ -82,7 +82,17 @@ module Dnsruby
|
|
|
82
82
|
end
|
|
83
83
|
else
|
|
84
84
|
if (seen_strings && !in_string)
|
|
85
|
-
|
|
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
|
|
@@ -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'
|
|
@@ -138,9 +138,13 @@ module Dnsruby
|
|
|
138
138
|
@@sockets << query_settings.socket
|
|
139
139
|
@@socket_is_persistent[query_settings.socket] = query_settings.is_persistent_socket
|
|
140
140
|
}
|
|
141
|
+
wake_up_select_thread
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def wake_up_select_thread
|
|
141
145
|
begin
|
|
142
146
|
@@wakeup_sockets[0].send("wakeup!", 0)
|
|
143
|
-
rescue Exception
|
|
147
|
+
rescue Exception
|
|
144
148
|
# do nothing
|
|
145
149
|
end
|
|
146
150
|
end
|
|
@@ -190,12 +194,11 @@ module Dnsruby
|
|
|
190
194
|
end
|
|
191
195
|
# next if (timeout < 0)
|
|
192
196
|
begin
|
|
193
|
-
ready,
|
|
197
|
+
ready, _write, _errors = IO.select(sockets, nil, nil, timeout)
|
|
194
198
|
rescue SelectWakeup
|
|
195
199
|
# If SelectWakeup, then just restart this loop - the select call will be made with the new data
|
|
196
200
|
next
|
|
197
|
-
rescue IOError
|
|
198
|
-
# print "IO Error =: #{e}\n"
|
|
201
|
+
rescue IOError, EncodeError
|
|
199
202
|
exceptions = clean_up_closed_sockets
|
|
200
203
|
exceptions.each { |exception| send_exception_to_client(*exception) }
|
|
201
204
|
|
|
@@ -248,7 +251,7 @@ module Dnsruby
|
|
|
248
251
|
# Removes closed sockets from @@sockets, and returns an array containing 1
|
|
249
252
|
# exception for each closed socket contained in @@socket_hash.
|
|
250
253
|
def clean_up_closed_sockets
|
|
251
|
-
|
|
254
|
+
@@mutex.synchronize do
|
|
252
255
|
closed_sockets_in_hash = @@sockets.select(&:closed?).select { |s| @@socket_hash[s] }
|
|
253
256
|
@@sockets.delete_if { | socket | socket.closed? }
|
|
254
257
|
closed_sockets_in_hash.each_with_object([]) do |socket, exceptions|
|
|
@@ -257,6 +260,7 @@ module Dnsruby
|
|
|
257
260
|
end
|
|
258
261
|
end
|
|
259
262
|
end
|
|
263
|
+
exceptions
|
|
260
264
|
end
|
|
261
265
|
|
|
262
266
|
def process_error(errors)
|
|
@@ -295,7 +299,6 @@ module Dnsruby
|
|
|
295
299
|
@@mutex.synchronize do
|
|
296
300
|
ids = get_active_ids(@@query_hash, msg.header.id)
|
|
297
301
|
return if ids.empty? # should be only one
|
|
298
|
-
query_settings = @@query_hash[ids[0]].clone
|
|
299
302
|
end
|
|
300
303
|
|
|
301
304
|
answerip = msg.answerip.downcase
|
|
@@ -369,21 +372,25 @@ module Dnsruby
|
|
|
369
372
|
end
|
|
370
373
|
|
|
371
374
|
def remove_id(id)
|
|
372
|
-
|
|
373
375
|
@@mutex.synchronize do
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
|
387
394
|
end
|
|
388
395
|
end
|
|
389
396
|
|
|
@@ -415,12 +422,12 @@ module Dnsruby
|
|
|
415
422
|
# Keep buffer for all TCP sockets, and return
|
|
416
423
|
# to select after reading available data. Once all data has been received,
|
|
417
424
|
# then process message.
|
|
418
|
-
buf=""
|
|
425
|
+
buf = +""
|
|
419
426
|
expected_length = 0
|
|
420
427
|
@@mutex.synchronize {
|
|
421
428
|
buf, expected_length = @@tcp_buffers[socket]
|
|
422
429
|
if (!buf)
|
|
423
|
-
buf = ""
|
|
430
|
+
buf = +""
|
|
424
431
|
expected_length = 2
|
|
425
432
|
@@tcp_buffers[socket]=[buf, expected_length]
|
|
426
433
|
end
|
|
@@ -444,7 +451,7 @@ module Dnsruby
|
|
|
444
451
|
|
|
445
452
|
return false
|
|
446
453
|
end
|
|
447
|
-
buf << input
|
|
454
|
+
buf << input if input
|
|
448
455
|
rescue
|
|
449
456
|
# Oh well - better luck next time!
|
|
450
457
|
return false
|
|
@@ -456,7 +463,7 @@ module Dnsruby
|
|
|
456
463
|
# We just read the data_length field. Now we need to start reading that many bytes.
|
|
457
464
|
@@mutex.synchronize {
|
|
458
465
|
answersize = buf.unpack('n')[0]
|
|
459
|
-
@@tcp_buffers[socket] = ["", answersize]
|
|
466
|
+
@@tcp_buffers[socket] = [+"", answersize]
|
|
460
467
|
}
|
|
461
468
|
return tcp_read(socket)
|
|
462
469
|
else
|
|
@@ -547,12 +554,10 @@ module Dnsruby
|
|
|
547
554
|
query_header_id = @@query_hash[id].query.header.id
|
|
548
555
|
if (query_header_id == e.partial_message.header.id)
|
|
549
556
|
# process the response
|
|
550
|
-
client_queue = nil
|
|
551
|
-
res = nil
|
|
552
|
-
query=nil
|
|
553
557
|
client_queue = @@query_hash[id].client_queue
|
|
554
558
|
res = @@query_hash[id].single_resolver
|
|
555
559
|
query = @@query_hash[id].query
|
|
560
|
+
remove_id_from_mutex_synchronized_block(id)
|
|
556
561
|
|
|
557
562
|
# NOW RESEND OVER TCP!
|
|
558
563
|
Thread.new {
|
|
@@ -642,6 +647,7 @@ module Dnsruby
|
|
|
642
647
|
do_select
|
|
643
648
|
}
|
|
644
649
|
end
|
|
650
|
+
wake_up_select_thread
|
|
645
651
|
end
|
|
646
652
|
|
|
647
653
|
def push_response_to_select(client_id, client_queue, msg, query, res)
|
|
@@ -662,6 +668,7 @@ module Dnsruby
|
|
|
662
668
|
do_select
|
|
663
669
|
}
|
|
664
670
|
end
|
|
671
|
+
wake_up_select_thread
|
|
665
672
|
end
|
|
666
673
|
|
|
667
674
|
def push_validation_response_to_select(client_id, client_queue, msg, err, query, res)
|
|
@@ -678,6 +685,7 @@ module Dnsruby
|
|
|
678
685
|
do_select
|
|
679
686
|
}
|
|
680
687
|
end
|
|
688
|
+
wake_up_select_thread
|
|
681
689
|
end
|
|
682
690
|
|
|
683
691
|
def send_queued_exceptions
|
|
@@ -732,7 +740,7 @@ module Dnsruby
|
|
|
732
740
|
}
|
|
733
741
|
|
|
734
742
|
responses.each do |item|
|
|
735
|
-
client_id, client_queue, msg, err,
|
|
743
|
+
client_id, client_queue, msg, err, _query, _res = item
|
|
736
744
|
# push_to_client(client_id, client_queue, msg, err)
|
|
737
745
|
client_queue.push([client_id, Resolver::EventType::VALIDATED, msg, err])
|
|
738
746
|
notify_queue_observers(client_queue, client_id)
|
|
@@ -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
|
-
|
|
78
|
+
resolver = Dnssec.default_resolver
|
|
77
79
|
else
|
|
78
|
-
|
|
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?
|
|
@@ -458,7 +462,6 @@ module Dnsruby
|
|
|
458
462
|
def check_no_wildcard_expansion(msg) # :nodoc:
|
|
459
463
|
# @TODO@ Do this for NSEC3 records!!!
|
|
460
464
|
proven_no_wildcards = false
|
|
461
|
-
name = msg.question()[0].qname
|
|
462
465
|
[msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
|
|
463
466
|
nsec_rrsets.each {|nsecs|
|
|
464
467
|
nsecs.rrs.each {|nsec|
|
|
@@ -770,7 +773,7 @@ module Dnsruby
|
|
|
770
773
|
}.to_s # @TODO@ worry about wildcards here?
|
|
771
774
|
rec.ttl = old_ttl
|
|
772
775
|
if (RUBY_VERSION >= "1.9")
|
|
773
|
-
data.force_encoding(
|
|
776
|
+
data.force_encoding(Encoding::BINARY)
|
|
774
777
|
end
|
|
775
778
|
sig_data += data
|
|
776
779
|
end
|
|
@@ -796,6 +799,19 @@ module Dnsruby
|
|
|
796
799
|
|
|
797
800
|
asn1 = OpenSSL::ASN1::Sequence.new([r_asn1, s_asn1]).to_der
|
|
798
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)
|
|
799
815
|
else
|
|
800
816
|
raise RuntimeError.new("Algorithm #{sigrec.algorithm.code} unsupported by Dnsruby")
|
|
801
817
|
end
|
|
@@ -848,6 +864,7 @@ module Dnsruby
|
|
|
848
864
|
end
|
|
849
865
|
end
|
|
850
866
|
end
|
|
867
|
+
res.dnssec = true
|
|
851
868
|
# query = Message.new(name, Types.DNSKEY)
|
|
852
869
|
# query.do_validation = false
|
|
853
870
|
ret = nil
|
|
@@ -1011,6 +1028,7 @@ module Dnsruby
|
|
|
1011
1028
|
end
|
|
1012
1029
|
end
|
|
1013
1030
|
end
|
|
1031
|
+
parent_res.dnssec = true
|
|
1014
1032
|
end
|
|
1015
1033
|
# Use that Resolver to query for DS record and NS for children
|
|
1016
1034
|
ds_rrset = current_anchor
|
|
@@ -1068,6 +1086,7 @@ module Dnsruby
|
|
|
1068
1086
|
child_res = Resolver.new
|
|
1069
1087
|
end
|
|
1070
1088
|
end
|
|
1089
|
+
child_res.dnssec = true
|
|
1071
1090
|
end
|
|
1072
1091
|
end
|
|
1073
1092
|
# Query for DNSKEY record, and verify against DS in parent.
|
|
@@ -1143,11 +1162,14 @@ module Dnsruby
|
|
|
1143
1162
|
if (Dnssec.do_validation_with_recursor?)
|
|
1144
1163
|
return get_recursor
|
|
1145
1164
|
else
|
|
1165
|
+
resolver = nil
|
|
1146
1166
|
if (Dnssec.default_resolver)
|
|
1147
|
-
|
|
1167
|
+
resolver = Dnssec.default_resolver
|
|
1148
1168
|
else
|
|
1149
|
-
|
|
1169
|
+
resolver = Resolver.new
|
|
1150
1170
|
end
|
|
1171
|
+
resolver.dnssec = true
|
|
1172
|
+
return resolver
|
|
1151
1173
|
end
|
|
1152
1174
|
end
|
|
1153
1175
|
|
|
@@ -1306,8 +1328,7 @@ module Dnsruby
|
|
|
1306
1328
|
msg.security_level = Message::SecurityLevel.SECURE
|
|
1307
1329
|
return true
|
|
1308
1330
|
end
|
|
1309
|
-
rescue VerifyError
|
|
1310
|
-
# print "Verify failed : #{e}\n"
|
|
1331
|
+
rescue VerifyError
|
|
1311
1332
|
end
|
|
1312
1333
|
end
|
|
1313
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
|
data/lib/dnsruby/version.rb
CHANGED
data/lib/dnsruby/zone_reader.rb
CHANGED
|
@@ -68,7 +68,7 @@ module Dnsruby
|
|
|
68
68
|
end
|
|
69
69
|
zone.push(rr)
|
|
70
70
|
end
|
|
71
|
-
rescue Exception
|
|
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
|
|
306
|
+
rescue Error
|
|
307
307
|
end
|
|
308
308
|
|
|
309
309
|
# Add the type so we can load the zone one RRSet at a time.
|
|
@@ -33,6 +33,8 @@ module Dnsruby
|
|
|
33
33
|
attr_reader :tsig
|
|
34
34
|
# Returns the tsigstate of the last transfer (nil if no TSIG signed transfer has occurred)
|
|
35
35
|
attr_reader :last_tsigstate
|
|
36
|
+
# Sets the connect timeout in seconds
|
|
37
|
+
attr_accessor :connect_timeout
|
|
36
38
|
|
|
37
39
|
# Sets the TSIG to sign the zone transfer with.
|
|
38
40
|
# Pass in either a Dnsruby::RR::TSIG, or a key_name and key (or just a key)
|
|
@@ -54,6 +56,7 @@ module Dnsruby
|
|
|
54
56
|
@tsig = nil
|
|
55
57
|
@axfr = nil
|
|
56
58
|
@src_address = nil
|
|
59
|
+
@connect_timeout = 5
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
# Perform a zone transfer (RFC1995)
|
|
@@ -107,7 +110,8 @@ module Dnsruby
|
|
|
107
110
|
def do_transfer(zone, server) #:nodoc: all
|
|
108
111
|
@transfer_type = Types.new(@transfer_type)
|
|
109
112
|
@state = :InitialSoa
|
|
110
|
-
socket =
|
|
113
|
+
socket = Socket.tcp(server, @port, @src_address, connect_timeout: @connect_timeout)
|
|
114
|
+
# socket = TCPSocket.new(server, @port, @src_address)
|
|
111
115
|
begin
|
|
112
116
|
# Send an initial query
|
|
113
117
|
msg = Message.new(zone, @transfer_type, @klass)
|
|
@@ -240,7 +244,6 @@ module Dnsruby
|
|
|
240
244
|
end
|
|
241
245
|
|
|
242
246
|
def parseRR(rec) #:nodoc: all
|
|
243
|
-
name = rec.name
|
|
244
247
|
type = rec.type
|
|
245
248
|
delta = Delta.new
|
|
246
249
|
|
data/lib/dnsruby.rb
CHANGED
|
@@ -25,10 +25,6 @@ require 'dnsruby/DNS'
|
|
|
25
25
|
require 'dnsruby/hosts'
|
|
26
26
|
require 'dnsruby/update'
|
|
27
27
|
require 'dnsruby/zone_transfer'
|
|
28
|
-
require 'dnsruby/dnssec'
|
|
29
|
-
require 'dnsruby/zone_reader'
|
|
30
|
-
require 'dnsruby/resolv'
|
|
31
|
-
|
|
32
28
|
|
|
33
29
|
# = Dnsruby library
|
|
34
30
|
# Dnsruby is a thread-aware DNS stub resolver library written in Ruby.
|
|
@@ -239,3 +235,7 @@ module Dnsruby
|
|
|
239
235
|
class ZoneSerialError < ResolvError
|
|
240
236
|
end
|
|
241
237
|
end
|
|
238
|
+
|
|
239
|
+
require 'dnsruby/dnssec'
|
|
240
|
+
require 'dnsruby/zone_reader'
|
|
241
|
+
require 'dnsruby/resolv'
|
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
|
data/test/spec_helper.rb
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
|
+
$VERBOSE = true
|
|
2
|
+
|
|
3
|
+
if Warning.respond_to?(:[]=)
|
|
4
|
+
Warning[:deprecated] = true
|
|
5
|
+
end
|
|
6
|
+
|
|
1
7
|
if ENV['RUN_EXTRA_TASK'] == 'TRUE'
|
|
2
|
-
|
|
3
|
-
|
|
8
|
+
unless "test".frozen?
|
|
9
|
+
# Coverall setup term-ansi-color which isn't yet frozen string literal compatible
|
|
10
|
+
# Ref: https://github.com/flori/term-ansicolor/pull/38
|
|
11
|
+
require 'coveralls'
|
|
12
|
+
Coveralls.wear!
|
|
13
|
+
end
|
|
4
14
|
|
|
5
15
|
require 'simplecov'
|
|
6
16
|
|
|
7
|
-
# SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
|
8
|
-
|
|
9
|
-
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
|
10
|
-
SimpleCov.start do
|
|
11
|
-
|
|
12
|
-
end
|
|
17
|
+
# # SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
|
18
|
+
# # [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter])
|
|
19
|
+
# SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
|
20
|
+
# SimpleCov.start do
|
|
21
|
+
# add_filter 'test/'
|
|
22
|
+
# end
|
|
13
23
|
end
|
|
14
24
|
|
|
15
25
|
require 'minitest'
|
|
16
26
|
require 'minitest/autorun'
|
|
17
27
|
require 'minitest/display'
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
Minitest::Display.options = {
|
|
20
30
|
suite_names: true,
|
|
21
31
|
color: true,
|
|
22
32
|
print: {
|
|
@@ -33,3 +43,18 @@ MiniTest::Display.options = {
|
|
|
33
43
|
require_relative '../lib/dnsruby'
|
|
34
44
|
require_relative 'test_utils'
|
|
35
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_caa.rb
CHANGED
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
# ++
|
|
17
17
|
|
|
18
18
|
require_relative 'spec_helper'
|
|
19
|
-
require 'pry'
|
|
20
19
|
|
|
21
20
|
class TestCAA < Minitest::Test
|
|
22
21
|
|
|
@@ -26,6 +25,7 @@ class TestCAA < Minitest::Test
|
|
|
26
25
|
{'foo.com. IN CAA 0 issue "ca.example.net"' => [0, 'issue', 'ca.example.net'],
|
|
27
26
|
'foo.com. IN CAA 1 issue "ca.example.net"' => [1, 'issue', 'ca.example.net'],
|
|
28
27
|
'foo.com. IN CAA 0 issuewild "ca.example.net"' => [0, 'issuewild', 'ca.example.net'],
|
|
28
|
+
'foo.com. IN CAA 0 issuemail "ca.example.net"' => [0, 'issuemail', 'ca.example.net'],
|
|
29
29
|
'foo.com. IN CAA 0 iodef "mailto:security@example.com"' => [0, 'iodef', 'mailto:security@example.com'],
|
|
30
30
|
'foo.com. IN CAA 0 issue "ca.example.net; account=230123"' => [0, 'issue', 'ca.example.net; account=230123']
|
|
31
31
|
}.each do |text, data|
|
|
@@ -45,5 +45,16 @@ class TestCAA < Minitest::Test
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def test_caa_error
|
|
49
|
+
{
|
|
50
|
+
'foo.com. IN CAA 0 ca.example.net "issue"' => [0, 'ca.example.net', 'issue'],
|
|
51
|
+
'foo.com. IN CAA 0 Issue "ca.example.net"' => [0, 'Issue', 'ca.example.net']
|
|
52
|
+
}.each do |text, data|
|
|
53
|
+
assert_raises DecodeError do
|
|
54
|
+
RR.create(text)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
48
59
|
end
|
|
49
60
|
|