dnsruby 1.60.2 → 1.61.5

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