dnsruby 1.30 → 1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EXAMPLES +9 -5
- data/demo/digdlv.rb +1 -0
- data/demo/digitar.rb +1 -0
- data/html/created.rid +1 -1
- data/html/fr_class_index.html +6 -2
- data/html/fr_method_index.html +275 -273
- data/lib/Dnsruby/Cache.rb +2 -2
- data/lib/Dnsruby/Recursor.rb +42 -42
- data/lib/Dnsruby/dnssec.rb +1 -1
- data/lib/Dnsruby/message.rb +10 -0
- data/lib/Dnsruby/name.rb +19 -0
- data/lib/Dnsruby/resource/DNSKEY.rb +10 -2
- data/lib/Dnsruby/resource/NSEC.rb +4 -1
- data/lib/Dnsruby/resource/NSEC3.rb +113 -32
- data/lib/Dnsruby/resource/NSEC3PARAM.rb +33 -20
- data/lib/Dnsruby/resource/RRSIG.rb +6 -0
- data/lib/Dnsruby/resource/resource.rb +13 -2
- data/lib/Dnsruby/select_thread.rb +1 -2
- data/lib/Dnsruby/single_verifier.rb +2 -4
- data/lib/Dnsruby/update.rb +2 -2
- data/lib/dnsruby.rb +39 -1
- data/test/tc_dnskey.rb +5 -0
- data/test/tc_nsec.rb +5 -0
- data/test/tc_nsec3.rb +37 -12
- data/test/tc_nsec3param.rb +9 -1
- data/test/tc_rrsig.rb +5 -0
- data/test/tc_tkey.rb +1 -0
- metadata +2 -2
@@ -39,10 +39,18 @@ module Dnsruby
|
|
39
39
|
#The Salt Length field defines the length of the Salt field in octets,
|
40
40
|
#ranging in value from 0 to 255.
|
41
41
|
attr_reader :salt_length
|
42
|
+
|
42
43
|
#The Salt field is appended to the original owner name before hashing
|
43
44
|
#in order to defend against pre-calculated dictionary attacks.
|
44
|
-
|
45
|
-
|
45
|
+
def salt
|
46
|
+
return NSEC3.encode_salt(@salt)
|
47
|
+
end
|
48
|
+
|
49
|
+
def salt=(s)
|
50
|
+
@salt = NSEC3.decode_salt(s)
|
51
|
+
@salt_length = @salt.length
|
52
|
+
end
|
53
|
+
|
46
54
|
def hash_alg=(a)
|
47
55
|
if (a.instance_of?String)
|
48
56
|
if (a.length == 1)
|
@@ -50,11 +58,11 @@ module Dnsruby
|
|
50
58
|
end
|
51
59
|
end
|
52
60
|
begin
|
53
|
-
alg =
|
61
|
+
alg = Nsec3HashAlgorithms.new(a)
|
54
62
|
@hash_alg = alg
|
55
63
|
rescue ArgumentError => e
|
56
64
|
raise DecodeError.new(e)
|
57
|
-
end
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def types=(t)
|
@@ -69,19 +77,19 @@ module Dnsruby
|
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
72
|
-
def salt_length=(l)
|
73
|
-
if ((l < 0) || (l > 255))
|
74
|
-
raise DecodeError.new("NSEC3 salt length must be between 0 and 255")
|
75
|
-
end
|
76
|
-
@salt_length = l
|
77
|
-
end
|
78
|
-
|
80
|
+
# def salt_length=(l) # :nodoc: all
|
81
|
+
# if ((l < 0) || (l > 255))
|
82
|
+
# raise DecodeError.new("NSEC3 salt length must be between 0 and 255")
|
83
|
+
# end
|
84
|
+
# @salt_length = l
|
85
|
+
# end
|
86
|
+
#
|
79
87
|
def from_data(data) #:nodoc: all
|
80
88
|
hash_alg, flags, iterations, salt_length, salt = data
|
81
89
|
self.hash_alg=(hash_alg)
|
82
90
|
self.flags=(flags)
|
83
91
|
self.iterations=(iterations)
|
84
|
-
self.salt_length=(salt_length)
|
92
|
+
# self.salt_length=(salt_length)
|
85
93
|
self.salt=(salt)
|
86
94
|
end
|
87
95
|
|
@@ -92,21 +100,26 @@ module Dnsruby
|
|
92
100
|
self.flags=(data[1]).to_i
|
93
101
|
self.iterations=(data[2]).to_i
|
94
102
|
self.salt=(data[3])
|
95
|
-
self.salt_length=(data[3].length)
|
103
|
+
# self.salt_length=(data[3].length)
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
99
107
|
def rdata_to_string #:nodoc: all
|
100
|
-
|
101
|
-
return "#{@hash_alg.code} #{@flags} #{@iterations} #{
|
102
|
-
else
|
103
|
-
return ""
|
104
|
-
end
|
108
|
+
s = salt()
|
109
|
+
return "#{@hash_alg.code} #{@flags} #{@iterations} #{s}"
|
105
110
|
end
|
106
111
|
|
107
112
|
def encode_rdata(msg, canonical=false) #:nodoc: all
|
108
|
-
|
109
|
-
|
113
|
+
s = salt()
|
114
|
+
sl = s.length()
|
115
|
+
if (s == "-")
|
116
|
+
sl == 0
|
117
|
+
end
|
118
|
+
msg.put_pack("ccnc", @hash_alg.code, @flags, @iterations, sl)
|
119
|
+
|
120
|
+
if (sl > 0)
|
121
|
+
msg.put_bytes(s)
|
122
|
+
end
|
110
123
|
end
|
111
124
|
|
112
125
|
def self.decode_rdata(msg) #:nodoc: all
|
@@ -165,7 +165,13 @@ module Dnsruby
|
|
165
165
|
# the white space out
|
166
166
|
buf=""
|
167
167
|
(index+3..end_index).each {|i|
|
168
|
+
if (comment_index = data[i].index(";"))
|
169
|
+
buf += data[i].slice(0, comment_index)
|
170
|
+
# @TODO@ We lose the comments here - we should really keep them for when we write back to string format?
|
171
|
+
break
|
172
|
+
else
|
168
173
|
buf += data[i]
|
174
|
+
end
|
169
175
|
}
|
170
176
|
buf.gsub!(/\n/, "")
|
171
177
|
buf.gsub!(/ /, "")
|
@@ -23,6 +23,7 @@ module Dnsruby
|
|
23
23
|
# (RRSet)."
|
24
24
|
# This class also stores the RRSIG records which cover the RRSet
|
25
25
|
class RRSet
|
26
|
+
include Comparable
|
26
27
|
# The number of RRSIGs stored in this RRSet
|
27
28
|
attr_reader :num_sigs
|
28
29
|
def initialize(rrs = [])
|
@@ -90,9 +91,19 @@ module Dnsruby
|
|
90
91
|
end
|
91
92
|
|
92
93
|
return privateAdd(r)
|
93
|
-
return true
|
94
|
+
# return true
|
94
95
|
end
|
95
|
-
|
96
|
+
|
97
|
+
def <=>(other)
|
98
|
+
# return 1 if ((!other) || !(other.name) || !(other.type))
|
99
|
+
# return -1 if (!@name)
|
100
|
+
if (@name.canonical == other.name.canonical)
|
101
|
+
return @type.code <=> other.type.code
|
102
|
+
else
|
103
|
+
return @name <=> other.name
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
96
107
|
def sort_canonical
|
97
108
|
#Make a list, for all the RRs, where each RR contributes
|
98
109
|
#the canonical RDATA encoding
|
@@ -492,11 +492,10 @@ module Dnsruby
|
|
492
492
|
# push_to_client(client_id, client_queue, msg, err)
|
493
493
|
client_queue.push([client_id, Resolver::EventType::RECEIVED, msg, err])
|
494
494
|
notify_queue_observers(client_queue, client_id)
|
495
|
-
#
|
495
|
+
# Do we need to validate this? The response has come from the cache -
|
496
496
|
# validate it only if it has not been validated already
|
497
497
|
# So, if we need to validate it, send it to the validation thread
|
498
498
|
# Otherwise, send VALIDATED to the requester.
|
499
|
-
# Should we really just be checking (level != SECURE) ?
|
500
499
|
if (((msg.security_level == Message::SecurityLevel::UNCHECKED) ||
|
501
500
|
(msg.security_level == Message::SecurityLevel::INDETERMINATE)) &&
|
502
501
|
(ValidatorThread.requires_validation?(query, msg, err, res)))
|
@@ -641,7 +641,7 @@ module Dnsruby
|
|
641
641
|
|
642
642
|
sigrecs.each {|sig|
|
643
643
|
if ((key.key_tag == sig.key_tag) && (key.algorithm == sig.algorithm))
|
644
|
-
|
644
|
+
# print "Found key #{key.key_tag}\n"
|
645
645
|
return key, sig
|
646
646
|
end
|
647
647
|
}
|
@@ -654,10 +654,8 @@ module Dnsruby
|
|
654
654
|
#
|
655
655
|
# Returns true if the RRSet verified, false otherwise.
|
656
656
|
def verify_rrset(rrset, keys = nil)
|
657
|
-
# @TODO@ Finer-grained reporting than "false".
|
658
657
|
# print "Verify_rrset #{rrset.name}, #{rrset.type}\n"
|
659
658
|
sigrecs = rrset.sigs
|
660
|
-
# return false if (rrset.num_sigs == 0)
|
661
659
|
if (rrset.rrs.length == 0)
|
662
660
|
raise VerifyError.new("No RRSet to veryify")
|
663
661
|
end
|
@@ -755,7 +753,7 @@ module Dnsruby
|
|
755
753
|
expiration_diff = (sigrec.expiration.to_i - Time.now.to_i).abs
|
756
754
|
rrset.ttl = ([rrset.ttl, sigrec.ttl, sigrec.original_ttl,
|
757
755
|
expiration_diff].sort)[0]
|
758
|
-
|
756
|
+
# print "VERIFIED OK\n"
|
759
757
|
return true
|
760
758
|
end
|
761
759
|
|
data/lib/Dnsruby/update.rb
CHANGED
@@ -252,8 +252,8 @@ module Dnsruby
|
|
252
252
|
resource = RR.create("#{args[0]} #{ttl} #{klass} #{args[1]} #{rdata}")
|
253
253
|
add_update(resource)
|
254
254
|
when 3 # name, type, rdata
|
255
|
-
|
256
|
-
resource =
|
255
|
+
resource = RR.create("#{args[0]} #{ttl} IN #{args[1]} #{args[2]}")
|
256
|
+
resource.klass = Classes.NONE
|
257
257
|
add_update(resource)
|
258
258
|
end
|
259
259
|
return resource
|
data/lib/dnsruby.rb
CHANGED
@@ -75,7 +75,17 @@ require 'Dnsruby/TheLog'
|
|
75
75
|
#* NotImp < ResolvError
|
76
76
|
#
|
77
77
|
#* Refused < ResolvError
|
78
|
+
#
|
79
|
+
#* NotZone < ResolvError
|
80
|
+
#
|
81
|
+
#* YXDomain < ResolvError
|
82
|
+
#
|
83
|
+
#* YXRRSet < ResolvError
|
78
84
|
#
|
85
|
+
#* NXRRSet < ResolvError
|
86
|
+
#
|
87
|
+
#* NotAuth < ResolvError
|
88
|
+
#
|
79
89
|
#* OtherResolvError < ResolvError
|
80
90
|
#
|
81
91
|
#== I/O
|
@@ -377,7 +387,14 @@ module Dnsruby
|
|
377
387
|
# Referred to as Algoriths.RSASHA1_NSEC3_SHA1
|
378
388
|
add_pair("RSASHA1-NSEC3-SHA1", 7)
|
379
389
|
end
|
380
|
-
|
390
|
+
|
391
|
+
# http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml
|
392
|
+
class Nsec3HashAlgorithms < CodeMapper
|
393
|
+
RESERVED = 0
|
394
|
+
update()
|
395
|
+
add_pair("SHA-1", 1)
|
396
|
+
end
|
397
|
+
|
381
398
|
#An error raised while querying for a resource
|
382
399
|
class ResolvError < StandardError
|
383
400
|
end
|
@@ -405,6 +422,27 @@ module Dnsruby
|
|
405
422
|
#The requested operation was refused by the remote resolver
|
406
423
|
class Refused < ResolvError
|
407
424
|
end
|
425
|
+
|
426
|
+
#The update RR is outside the zone (in dynamic update)
|
427
|
+
class NotZone < ResolvError
|
428
|
+
end
|
429
|
+
|
430
|
+
#Some name that ought to exist, does not exist (in dynamic update)
|
431
|
+
class YXDomain < ResolvError
|
432
|
+
end
|
433
|
+
|
434
|
+
#Some RRSet that ought to exist, does not exist (in dynamic update)
|
435
|
+
class YXRRSet < ResolvError
|
436
|
+
end
|
437
|
+
|
438
|
+
#Some RRSet that ought not to exist, does exist (in dynamic update)
|
439
|
+
class NXRRSet < ResolvError
|
440
|
+
end
|
441
|
+
|
442
|
+
#The nameserver is not responsible for the zone (in dynamic update)
|
443
|
+
class NotAuth < ResolvError
|
444
|
+
end
|
445
|
+
|
408
446
|
|
409
447
|
#Another kind of resolver error has occurred
|
410
448
|
class OtherResolvError < ResolvError
|
data/test/tc_dnskey.rb
CHANGED
@@ -34,6 +34,11 @@ class DnskeyTest < Test::Unit::TestCase
|
|
34
34
|
assert(dnskey2.to_s == dnskey.to_s, "#{dnskey.to_s} not equal to \n#{dnskey2.to_s}")
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_from_string_with_comments
|
38
|
+
k = Dnsruby::RR.create("tjeb.nl. 3600 IN DNSKEY 256 3 7 AwEAAcglEOS7bECRK5fqTuGTMJycmDhTzmUu/EQbAhKJOYJxDb5SG/RYqsJgzG7wgtGy0W1aP7I4k6SPtHmwcqjLaZLVUwRNWCGr2adjb9JTFyBR7F99Ngi11lEGM6Uiw/eDRk66lhoSGzohjj/rmhRTV6gN2+0ADPnafv3MBkPgryA3 ;{id = 53177 (zsk), size = 1024b}")
|
39
|
+
assert_equal(53177, k.key_tag)
|
40
|
+
end
|
41
|
+
|
37
42
|
def test_dnskey_from_data
|
38
43
|
dnskey = Dnsruby::RR.create(INPUT)
|
39
44
|
m = Dnsruby::Message.new
|
data/test/tc_nsec.rb
CHANGED
@@ -13,6 +13,11 @@ class NsecTest < Test::Unit::TestCase
|
|
13
13
|
|
14
14
|
nsec2 = Dnsruby::RR.create(nsec.to_s)
|
15
15
|
assert(nsec2.to_s == nsec.to_s)
|
16
|
+
|
17
|
+
s = "tjeb.nl. 3600 IN NSEC dragon.tjeb.nl. A NS SOA MX AAAA RRSIG NSEC DNSKEY"
|
18
|
+
nsec = Dnsruby::RR.create(s)
|
19
|
+
assert(nsec.types.include?(Types.A))
|
20
|
+
assert(nsec.types.include?(Types.DNSKEY))
|
16
21
|
end
|
17
22
|
|
18
23
|
def test_nsec_from_data
|
data/test/tc_nsec3.rb
CHANGED
@@ -12,7 +12,7 @@ class Nsec3Test < Test::Unit::TestCase
|
|
12
12
|
assert(nsec.opt_out?)
|
13
13
|
assert_equal(12, nsec.iterations)
|
14
14
|
assert_equal("aabbccdd", nsec.salt)
|
15
|
-
assert_equal(Dnsruby::
|
15
|
+
assert_equal(Dnsruby::Nsec3HashAlgorithms.SHA_1, nsec.hash_alg)
|
16
16
|
|
17
17
|
nsec2 = Dnsruby::RR.create(nsec.to_s)
|
18
18
|
assert(nsec2.to_s == nsec.to_s)
|
@@ -39,19 +39,44 @@ class Nsec3Test < Test::Unit::TestCase
|
|
39
39
|
nsec3 = m2.additional()[0]
|
40
40
|
assert_equal(nsec.to_s, nsec3.to_s)
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
|
+
def test_calculate_hash
|
44
|
+
input = [
|
45
|
+
[ "example" , "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom"],
|
46
|
+
[ "a.example" , "35mthgpgcu1qg68fab165klnsnk3dpvl"],
|
47
|
+
[ "ai.example" , "gjeqe526plbf1g8mklp59enfd789njgi"],
|
48
|
+
[ "ns1.example" , "2t7b4g4vsa5smi47k61mv5bv1a22bojr"],
|
49
|
+
[ "ns2.example" , "q04jkcevqvmu85r014c7dkba38o0ji5r"],
|
50
|
+
[ "w.example" , "k8udemvp1j2f7eg6jebps17vp3n8i58h"],
|
51
|
+
[ "*.w.example" , "r53bq7cc2uvmubfu5ocmm6pers9tk9en"],
|
52
|
+
[ "x.w.example" , "b4um86eghhds6nea196smvmlo4ors995"],
|
53
|
+
[ "y.w.example" , "ji6neoaepv8b5o6k4ev33abha8ht9fgc"],
|
54
|
+
[ "x.y.w.example" , "2vptu5timamqttgl4luu9kg21e0aor3s"],
|
55
|
+
[ "xx.example" , "t644ebqk9bibcna874givr6joj62mlhv"],
|
56
|
+
[ "2t7b4g4vsa5smi47k61mv5bv1a22bojr.example" , "kohar7mbb8dc2ce8a9qvl8hon4k53uhi"]
|
57
|
+
]
|
58
|
+
input.each {|name, hash|
|
59
|
+
nsec3 = Dnsruby::RR.create({:type => Dnsruby::Types.NSEC3, :name => name, :salt => "aabbccdd", :iterations => 12, :hash_alg => 1})
|
60
|
+
n = nsec3.calculate_hash
|
61
|
+
assert_equal(n, hash, "Expected #{hash} but got #{n} for #{name}")
|
62
|
+
c = Dnsruby::RR::NSEC3.calculate_hash(name, 12, Dnsruby::RR::NSEC3.decode_salt("aabbccdd"), 1)
|
63
|
+
assert_equal(c, hash, "Expected #{hash} but got #{c} for #{name}")
|
64
|
+
}
|
65
|
+
#
|
66
|
+
end
|
67
|
+
|
43
68
|
def test_nsec_other_stuff
|
44
69
|
nsec = Dnsruby::RR.create(INPUT)
|
45
|
-
begin
|
46
|
-
nsec.salt_length=256
|
47
|
-
fail
|
48
|
-
rescue DecodeError
|
49
|
-
end
|
50
|
-
begin
|
51
|
-
nsec.hash_length=256
|
52
|
-
fail
|
53
|
-
rescue DecodeError
|
54
|
-
end
|
70
|
+
# begin
|
71
|
+
# nsec.salt_length=256
|
72
|
+
# fail
|
73
|
+
# rescue DecodeError
|
74
|
+
# end
|
75
|
+
# begin
|
76
|
+
# nsec.hash_length=256
|
77
|
+
# fail
|
78
|
+
# rescue DecodeError
|
79
|
+
# end
|
55
80
|
# Be liberal in what you accept...
|
56
81
|
# begin
|
57
82
|
# nsec.hash_alg = 8
|
data/test/tc_nsec3param.rb
CHANGED
@@ -8,7 +8,7 @@ class Nsec3ParamTest < Test::Unit::TestCase
|
|
8
8
|
def test_nsec_from_string
|
9
9
|
nsec = Dnsruby::RR.create(INPUT)
|
10
10
|
|
11
|
-
assert_equal(Dnsruby::
|
11
|
+
assert_equal(Dnsruby::Nsec3HashAlgorithms.SHA_1, nsec.hash_alg)
|
12
12
|
assert_equal(0, nsec.flags)
|
13
13
|
assert_equal(12, nsec.iterations)
|
14
14
|
assert_equal("aabbccdd", nsec.salt)
|
@@ -25,6 +25,14 @@ class Nsec3ParamTest < Test::Unit::TestCase
|
|
25
25
|
m2 = Dnsruby::Message.decode(data)
|
26
26
|
nsec3 = m2.additional()[0]
|
27
27
|
assert_equal(nsec.to_s, nsec3.to_s)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_from_real_string
|
32
|
+
r = Dnsruby::RR.create("tjeb.nl. 3600 IN NSEC3PARAM 1 0 5 beef")
|
33
|
+
assert_equal(Dnsruby::Name.create("tjeb.nl."), r.name)
|
34
|
+
assert_equal("beef", r.salt)
|
35
|
+
assert_equal(Dnsruby::Nsec3HashAlgorithms.SHA_1, r.hash_alg)
|
28
36
|
end
|
29
37
|
|
30
38
|
end
|
data/test/tc_rrsig.rb
CHANGED
@@ -29,4 +29,9 @@ class RrsigTest < Test::Unit::TestCase
|
|
29
29
|
rrsig2 = Dnsruby::RR.create(rrsig.to_s)
|
30
30
|
assert(rrsig2.to_s == rrsig.to_s)
|
31
31
|
end
|
32
|
+
|
33
|
+
def test_string_with_comments
|
34
|
+
r = Dnsruby::RR.create("tjeb.nl. 3600 IN RRSIG NSEC3PARAM 7 2 3600 20090630164649 20090602164649 53177 tjeb.nl. Fw70WQMviRFGyeze3MUpfafaAcWIvHRpnq4ZK3lxexrR1p+rLxK5C4qVKU71XYrPYR7XEBxgUG1oyKNOhFOVyx31EjC462dz7Vxn6UDpD1LIwNnD28+oHfS9AFzGKcn4zUZqT+8IvOO1jiS9c3Y8WAkOloN9AwGIIKWU8zAp1n4= ;{id = 53177}")
|
35
|
+
assert_equal("Fw70WQMviRFGyeze3MUpfafaAcWIvHRpnq4ZK3lxexrR1p+rLxK5C4qVKU71XYrPYR7XEBxgUG1oyKNOhFOVyx31EjC462dz7Vxn6UDpD1LIwNnD28+oHfS9AFzGKcn4zUZqT+8IvOO1jiS9c3Y8WAkOloN9AwGIIKWU8zAp1n4=", ([r.signature].pack("m*")).gsub(/\n/,"").chomp)
|
36
|
+
end
|
32
37
|
end
|
data/test/tc_tkey.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dnsruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "1.
|
4
|
+
version: "1.31"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AlexD
|
@@ -9,7 +9,7 @@ autorequire: dnsruby
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-04 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|