dnsruby 1.47 → 1.48

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 CHANGED
@@ -92,25 +92,6 @@ Dnsruby::Dnssec.clear_trust_anchors
92
92
  Dnsruby::PacketSender.clear_caches
93
93
  Dnsruby::Recursor.clear_caches
94
94
 
95
- # Load the IANA TAR and query some signed zones
96
- Dnssec.load_itar
97
- res = Recursor.new
98
- ret = res.query("frobbit.se", "NS")
99
- print "Security level for signed zone from ITAR : #{ret.security_level}\n"
100
-
101
- # Query a name with no validation to be performed
102
- res = Dnsruby::Resolver.new
103
- m = Message.new("frobbit.se", "MX")
104
- m.do_validation = false
105
- ret = res.send_message(m)
106
- print "Security level of secure domain with no validation : #{ret.security_level}\n"
107
-
108
- # Clear the keys and caches
109
- Dnsruby::Dnssec.clear_trusted_keys
110
- Dnsruby::Dnssec.clear_trust_anchors
111
- Dnsruby::PacketSender.clear_caches
112
- Dnsruby::Recursor.clear_caches
113
-
114
95
  # Load a specific trust anchor and query some signed zones
115
96
  trusted_key = Dnsruby::RR.create({:name => "uk-dnssec.nic.uk.",
116
97
  :type => Dnsruby::Types.DNSKEY,
@@ -21,18 +21,14 @@
21
21
  #
22
22
  #= SYNOPSIS
23
23
  #
24
- #digitar name [ type [ class ] ]
24
+ #digroot name [ type [ class ] ]
25
25
  #
26
26
  #= DESCRIPTION
27
27
  #
28
28
  #Performs a DNS query on the given name. The record type
29
29
  #and class can also be specified; if left blank they default
30
30
  #to A and IN. The program firstly performs the requested DNS
31
- # query. The response is then validated
32
- #- the ITAR is searched for the keys of the closest ancestor
33
- #of the query name, and the chain of trust is followed to prove
34
- #that the DNSSEC records are correct, or that we do not expect the
35
- #response to be signed.
31
+ # query. The response is then validated from the signed root.
36
32
  #
37
33
  #= AUTHOR
38
34
  #
@@ -48,30 +44,16 @@ include Dnsruby
48
44
 
49
45
  raise RuntimeError, "Usage: #{$0} name [ type [ class ] ]\n" unless (ARGV.length >= 1) && (ARGV.length <= 3)
50
46
 
51
- Dnssec.load_itar
52
- res = Dnsruby::Recursor.new
53
- zt=Dnsruby::ZoneTransfer.new
54
-
55
-
47
+ resolver = Dnsruby::Resolver.new()
48
+ resolver.do_validation = true
49
+ res = Dnsruby::Recursor.new(resolver)
50
+
56
51
  # Dnsruby::TheLog.level=Logger::DEBUG
57
52
 
58
53
  name, type, klass = ARGV
59
54
  type ||= "A"
60
55
  klass ||= "IN"
61
56
 
62
- if (type.upcase == "AXFR")
63
- rrs = zt.transfer(name) # , klass)
64
-
65
- if (rrs)
66
- rrs.each do |rr|
67
- print rr.to_s + "\n"
68
- end
69
- else
70
- raise RuntimeError, "zone transfer failed: ", res.errorstring, "\n"
71
- end
72
-
73
- else
74
-
75
57
  begin
76
58
  answer = nil
77
59
  answer = res.query(name, type, klass)
@@ -79,4 +61,3 @@ else
79
61
  rescue Exception => e
80
62
  print "query failed: #{e}\n"
81
63
  end
82
- end
@@ -303,8 +303,8 @@ module Dnsruby
303
303
  #This method is much like the normal query() method except it disables
304
304
  #the recurse flag in the packet and explicitly performs the recursion.
305
305
  #
306
- # packet = res.query_dorecursion( "www.netscape.com.", "A")
307
- # packet = res.query_dorecursion( "www.netscape.com.", "A", "IN", true) # no validation
306
+ # packet = res.query( "www.netscape.com.", "A")
307
+ # packet = res.query( "www.netscape.com.", "A", "IN", true) # no validation
308
308
  #
309
309
  #The Recursor maintains a cache of known nameservers.
310
310
  #DNSSEC validation is performed unless true is passed as the fourth parameter.
@@ -525,7 +525,9 @@ module Dnsruby
525
525
 
526
526
  nameservers = []
527
527
  ns.each do |nss|
528
- nss.each {|n| nameservers.push(n)}
528
+ nss.each {|n|
529
+ nameservers.push(n.to_s)
530
+ }
529
531
  end
530
532
  resolver = Resolver.new({:nameserver=>nameservers})
531
533
  servers = []
@@ -426,7 +426,6 @@ module Dnsruby
426
426
  :use_tcp=>@use_tcp, :no_tcp=>@no_tcp, :packet_timeout=>@packet_timeout,
427
427
  :tsig => @tsig, :ignore_truncation=>@ignore_truncation,
428
428
  :src_address=>@src_address, :src_port=>@src_port,
429
- :do_caching=>@do_caching,
430
429
  :recurse=>@recurse, :udp_size=>@udp_size})
431
430
  @single_resolvers.push(res) if res
432
431
  end
@@ -453,7 +452,12 @@ module Dnsruby
453
452
  end
454
453
 
455
454
  # Attributes
456
- @do_validation = true
455
+
456
+ # do_validation tells the Resolver whether to try to validate the response
457
+ # with DNSSEC. This should work for NSEC-signed domains, but NSEC3
458
+ # validation is not currently supported. This attribute now defaults to
459
+ # false. Please let me know if you require NSEC3 validation.
460
+ @do_validation = false
457
461
  @query_timeout = DefaultQueryTimeout
458
462
  @retry_delay = DefaultRetryDelay
459
463
  @retry_times = DefaultRetryTimes
@@ -77,11 +77,15 @@ module Dnsruby
77
77
 
78
78
  @@root_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ROOT)
79
79
 
80
+ # #NOTE# You may wish to import these via a secure channel yourself, if
81
+ # using Dnsruby for validation.
82
+ @@root_key = RR.create(". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5")
83
+ @@root_verifier.add_root_ds(@@root_key)
84
+
80
85
  @@dlv_verifier = SingleVerifier.new(SingleVerifier::VerifierType::DLV)
81
86
 
82
87
  # @TODO@ Could add a new one of these for each anchor.
83
88
  @@anchor_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ANCHOR)
84
- # Should we be loading IANA Trust Anchor Repository? - no need - imported by ISC DLV
85
89
 
86
90
 
87
91
  # Add a trusted Key Signing Key for the ISC DLV registry.
@@ -120,6 +124,7 @@ module Dnsruby
120
124
  def self.reset
121
125
  @@validation_policy = ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT
122
126
  @@root_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ROOT)
127
+ @@root_verifier.add_root_ds(@@root_key)
123
128
 
124
129
  @@dlv_verifier = SingleVerifier.new(SingleVerifier::VerifierType::DLV)
125
130
 
@@ -139,37 +144,6 @@ module Dnsruby
139
144
  }
140
145
  return no_keys
141
146
  end
142
- # Load the IANA TAR.
143
- # THIS METHOD IS NOT SECURE!!!
144
- def self.load_itar
145
- # @TODO@ THIS IS VERY INSECURE!! WRITE THIS PROPERLY!!
146
- # Should really check the signatures here to make sure the keys are good!
147
- Net::FTP::open("ftp.iana.org") { |ftp|
148
- ftp.login("anonymous")
149
- ftp.passive = true
150
- ftp.chdir("/itar")
151
- lastname=nil
152
- ftp.gettextfile("anchors.mf") {|line|
153
- next if (line.strip.length == 0)
154
- first = line[0]
155
- if (first.class == String)
156
- first = first.getbyte(0) # Ruby 1.9
157
- end
158
- # print "Reading ITAR : #{line}, first : #{first}\n"
159
- next if (first==59) # ";")
160
- if (line.strip=~(/^DS /) || line.strip=~(/^DNSKEY /))
161
- line = lastname.to_s + ((lastname.absolute?)?".":"") + " " + line
162
- end
163
- ds = RR.create(line)
164
- if ((ds.type == Types::DS) || (ds.type == Types::DNSKEY))
165
- # assert(ds.name.absolute?)
166
- Dnssec.add_trust_anchor(ds)
167
- end
168
- lastname = ds.name
169
- }
170
- }
171
- end
172
-
173
147
 
174
148
  @@do_validation_with_recursor = true # Many nameservers don't handle DNSSEC correctly yet
175
149
  @@default_resolver = Resolver.new
@@ -591,33 +591,41 @@ module Dnsruby
591
591
  #Decode the encoded message
592
592
  def Message.decode(m)
593
593
  o = Message.new()
594
- MessageDecoder.new(m) {|msg|
595
- o.header = Header.new(msg)
596
- o.header.qdcount.times {
597
- question = msg.get_question
598
- o.question << question
599
- }
600
- o.header.ancount.times {
601
- rr = msg.get_rr
602
- o.answer << rr
603
- }
604
- o.header.nscount.times {
605
- rr = msg.get_rr
606
- o.authority << rr
607
- }
608
- o.header.arcount.times { |count|
609
- start = msg.index
610
- rr = msg.get_rr
611
- if (rr.type == Types::TSIG)
612
- if (count!=o.header.arcount-1)
613
- Dnsruby.log.Error("Incoming message has TSIG record before last record")
614
- raise DecodeError.new("TSIG record present before last record")
594
+ begin
595
+ MessageDecoder.new(m) {|msg|
596
+ o.header = Header.new(msg)
597
+ o.header.qdcount.times {
598
+ question = msg.get_question
599
+ o.question << question
600
+ }
601
+ o.header.ancount.times {
602
+ rr = msg.get_rr
603
+ o.answer << rr
604
+ }
605
+ o.header.nscount.times {
606
+ rr = msg.get_rr
607
+ o.authority << rr
608
+ }
609
+ o.header.arcount.times { |count|
610
+ start = msg.index
611
+ rr = msg.get_rr
612
+ if (rr.type == Types::TSIG)
613
+ if (count!=o.header.arcount-1)
614
+ Dnsruby.log.Error("Incoming message has TSIG record before last record")
615
+ raise DecodeError.new("TSIG record present before last record")
616
+ end
617
+ o.tsigstart = start # needed for TSIG verification
615
618
  end
616
- o.tsigstart = start # needed for TSIG verification
617
- end
618
- o.additional << rr
619
+ o.additional << rr
620
+ }
619
621
  }
620
- }
622
+ rescue DecodeError => e
623
+ # So we got a decode error
624
+ # However, we might have been able to fill in many parts of the message
625
+ # So let's raise the DecodeError, but add the partially completed message
626
+ e.partial_message = o
627
+ raise e
628
+ end
621
629
  return o
622
630
  end
623
631
 
@@ -92,7 +92,7 @@ module Dnsruby
92
92
 
93
93
  def algorithm=(a)
94
94
  if (a.instance_of?String)
95
- if (a.length == 1)
95
+ if (a.length < 3)
96
96
  a = a.to_i
97
97
  end
98
98
  end
@@ -30,7 +30,15 @@ module Dnsruby
30
30
  end
31
31
 
32
32
  def from_string(input) #:nodoc: all
33
- cpu, os = input.split(" ")
33
+ strings = TXT.parse(input)
34
+ cpu = ""
35
+ os = ""
36
+ if (strings.length == 1)
37
+ cpu, os = input.split(" ")
38
+ else
39
+ cpu = strings[0]
40
+ os = strings[1]
41
+ end
34
42
  cpu.sub!(/^\"/, "")
35
43
  @cpu = cpu.sub(/\"$/, "")
36
44
  os.sub!(/^\"/, "")
@@ -38,7 +46,15 @@ module Dnsruby
38
46
  end
39
47
 
40
48
  def rdata_to_string #:nodoc: all
41
- return "#{@cpu} #{@os}"
49
+ if (defined?@cpu)
50
+ temp = []
51
+ [@cpu, @os].each {|str|
52
+ output = TXT.display(str)
53
+ temp.push("\"#{output}\"")
54
+ }
55
+ return temp.join(' ')
56
+ end
57
+ return ''
42
58
  end
43
59
 
44
60
  def encode_rdata(msg, canonical=false) #:nodoc: all
@@ -89,7 +89,7 @@ module Dnsruby
89
89
  def dms2latlon(deg, min, sec, hem)
90
90
  retval=0
91
91
 
92
- retval = (deg * CONV_DEG) + (min * CONV_MIN) + (sec * CONV_SEC);
92
+ retval = (deg * CONV_DEG) + (min * CONV_MIN) + (sec * CONV_SEC).round;
93
93
  retval = -retval if ((hem != nil) && ((hem == "S") || (hem == "W")));
94
94
  retval += REFERENCE_LATLON;
95
95
  return retval;
@@ -138,23 +138,28 @@ module Dnsruby
138
138
  (\s+ ([\d.]+) m?)? # size
139
139
  (\s+ ([\d.]+) m?)? # horiz precision
140
140
  (\s+ ([\d.]+) m?)? # vert precision
141
- /ix) #
141
+ /ix) #
142
+
143
+ size = DEFAULT_SIZE
142
144
 
143
145
  # What to do for other versions?
144
146
  version = 0;
145
147
 
146
148
  horiz_pre = DEFAULT_HORIZ_PRE
147
149
  vert_pre = DEFAULT_VERT_PRE
148
- latdeg, latmin, latsec, lathem = $1.to_i, $3.to_i, $5.to_i, $6;
149
- londeg, lonmin, lonsec, lonhem = $7.to_i, $9.to_i, $11.to_i, $12
150
- alt, size = $13.to_i, $15.to_i
150
+ latdeg, latmin, latsec, lathem = $1.to_i, $3.to_i, $5.to_f, $6;
151
+ londeg, lonmin, lonsec, lonhem = $7.to_i, $9.to_i, $11.to_f, $12
152
+ alt = $13.to_i
153
+ if ($15)
154
+ size = $15.to_f
155
+ end
151
156
  if ($17)
152
- horiz_pre = $17.to_i
157
+ horiz_pre = $17.to_f
153
158
  end
154
159
  if ($19)
155
- vert_pre = $19.to_i
160
+ vert_pre = $19.to_f
156
161
  end
157
-
162
+
158
163
  latmin = DEFAULT_MIN unless latmin;
159
164
  latsec = DEFAULT_SEC unless latsec;
160
165
  lathem = lathem.upcase;
@@ -163,8 +168,6 @@ module Dnsruby
163
168
  lonsec = DEFAULT_SEC unless lonsec;
164
169
  lonhem = lonhem.upcase
165
170
 
166
- size = DEFAULT_SIZE unless size;
167
-
168
171
  @version = version;
169
172
  @size = size * 100;
170
173
  @horiz_pre = horiz_pre * 100;
@@ -178,7 +181,7 @@ module Dnsruby
178
181
  def from_hash(hash) #:nodoc: all
179
182
  super(hash)
180
183
  if (@size == nil)
181
- @size = DEFAULT_SIZE
184
+ @size = DEFAULT_SIZE * 100
182
185
  end
183
186
  if @horiz_pre == nil
184
187
  @horiz_pre = DEFAULT_HORIZ_PRE * 100
@@ -71,22 +71,25 @@ module Dnsruby
71
71
  end
72
72
 
73
73
  def get_socket_pair
74
+ # Emulate socketpair on platforms which don't support it
75
+ srv = nil
74
76
  begin
75
- pair = Socket::socketpair(Socket::AF_LOCAL, Socket::SOCK_DGRAM, 0)
76
- return pair
77
-
78
- # Emulate socketpair on platforms which don't support it
79
- rescue Exception
80
77
  srv = TCPServer.new('localhost', 0)
81
- rsock = TCPSocket.new(srv.addr[3], srv.addr[1])
82
- lsock = srv.accept
83
- srv.close
84
- return [lsock, rsock]
78
+ rescue Errno::EADDRNOTAVAIL # OSX Snow Leopard issue - need to use explicit IP
79
+ begin
80
+ srv = TCPServer.new('127.0.0.1', 0)
81
+ rescue Error # Try IPv6
82
+ srv = TCPServer.new('::1', 0)
83
+ end
85
84
  end
85
+ rsock = TCPSocket.new(srv.addr[3], srv.addr[1])
86
+ lsock = srv.accept
87
+ srv.close
88
+ return [lsock, rsock]
86
89
  end
87
90
 
88
91
  class QuerySettings
89
- attr_accessor :query_bytes, :query, :ignore_truncation, :client_queue,
92
+ attr_accessor :query_bytes, :query, :ignore_truncation, :client_queue,
90
93
  :client_query_id, :socket, :dest_server, :dest_port, :endtime, :udp_packet_size,
91
94
  :single_resolver
92
95
  # new(query_bytes, query, ignore_truncation, client_queue, client_query_id,
@@ -100,7 +103,7 @@ module Dnsruby
100
103
  @socket = args[5]
101
104
  @dest_server = args[6]
102
105
  @dest_port=args[7]
103
- @endtime = args[8]
106
+ @endtime = args[8]
104
107
  @udp_packet_size = args[9]
105
108
  @single_resolver = args[10]
106
109
  end
@@ -156,8 +159,8 @@ module Dnsruby
156
159
  sockets=[]
157
160
  timeouts=[]
158
161
  has_observer = false
159
- @@mutex.synchronize {
160
- sockets = @@sockets
162
+ @@mutex.synchronize {
163
+ sockets = @@sockets
161
164
  timeouts = @@timeouts.values
162
165
  has_observer = !@@observers.empty?
163
166
  }
@@ -241,7 +244,7 @@ module Dnsruby
241
244
  answeripaddr = IPAddr.new(answerip)
242
245
  dest_server = IPAddr.new("0.0.0.0")
243
246
  begin
244
- destserveripaddr = IPAddr.new(dest_server)
247
+ destserveripaddr = IPAddr.new(dest_server)
245
248
  rescue ArgumentError
246
249
  # Host name not IP address
247
250
  end
@@ -249,7 +252,7 @@ module Dnsruby
249
252
  (answeripaddr != destserveripaddr) &&
250
253
  (answerfrom != dest_server))
251
254
  Dnsruby.log.warn("Unsolicited response received from #{answerip} instead of #{query_settings.dest_server}")
252
- else
255
+ else
253
256
  send_response_to_client(msg, bytes, socket)
254
257
  end
255
258
  end
@@ -308,8 +311,8 @@ module Dnsruby
308
311
  @@mutex.synchronize{
309
312
  socket = @@query_hash[id].socket
310
313
  @@timeouts.delete(id)
311
- @@query_hash.delete(id)
312
- @@socket_hash.delete(socket)
314
+ @@query_hash.delete(id)
315
+ @@socket_hash.delete(socket)
313
316
  @@sockets.delete(socket) # @TODO@ Not if persistent!
314
317
  }
315
318
  Dnsruby.log.debug{"Closing socket #{socket}"}
@@ -348,13 +351,13 @@ module Dnsruby
348
351
  }
349
352
  if (buf.length() < expected_length)
350
353
  begin
351
- input, = socket.recv_nonblock(expected_length-buf.length)
352
- if (input=="")
353
- TheLog.info("Bad response from server - no bytes read - ignoring")
354
- # @TODO@ Should we do anything about this?
355
- return false
356
- end
357
- buf += input
354
+ input, = socket.recv_nonblock(expected_length-buf.length)
355
+ if (input=="")
356
+ TheLog.info("Bad response from server - no bytes read - ignoring")
357
+ # @TODO@ Should we do anything about this?
358
+ return false
359
+ end
360
+ buf += input
358
361
  rescue
359
362
  # Oh well - better luck next time!
360
363
  return false
@@ -421,13 +424,13 @@ module Dnsruby
421
424
  else
422
425
  # recvfrom failed - why?
423
426
  Dnsruby.log.error{"Error - recvfrom failed from #{socket}"}
424
- handle_recvfrom_failure(socket, "")
427
+ handle_recvfrom_failure(socket, "")
425
428
  return
426
- end
429
+ end
427
430
  end
428
431
  rescue Exception => e
429
432
  Dnsruby.log.error{"Error - recvfrom failed from #{socket}, exception : #{e}"}
430
- handle_recvfrom_failure(socket, e)
433
+ handle_recvfrom_failure(socket, e)
431
434
  return
432
435
  end
433
436
  Dnsruby.log.debug{";; answer from #{answerfrom} : #{answersize} bytes\n"}
@@ -435,14 +438,45 @@ module Dnsruby
435
438
  begin
436
439
  ans = Message.decode(buf)
437
440
  rescue Exception => e
438
- # print "DECODE ERROR\n"
439
441
  Dnsruby.log.error{"Decode error! #{e.class}, #{e}\nfor msg (length=#{buf.length}) : #{buf}"}
440
- # @TODO@ Should know this from the socket!
441
442
  client_id=get_client_id_from_answerfrom(socket, answerip, answerport)
442
- if (client_id != nil)
443
- send_exception_to_client(e, socket, client_id)
443
+ if (client_id == nil)
444
+ Dnsruby.log.error{"Decode error from #{answerip} but can't determine packet id"}
445
+ end
446
+ # We should check if the TC bit is set (if we can get that far)
447
+ if ((DecodeError === e) && (e.partial_message.header.tc))
448
+ Dnsruby.log.error{"Decode error (from {answerip})! Header shows truncation, so trying again over TCP"}
449
+ # If it is, then we should retry over TCP
450
+ sent = false
451
+ @@mutex.synchronize{
452
+ client_ids = @@socket_hash[socket]
453
+ # get the queries associated with them
454
+ client_ids.each do |id|
455
+ query_header_id=nil
456
+ query_header_id = @@query_hash[id].query.header.id
457
+ if (query_header_id == e.partial_message.header.id)
458
+ # process the response
459
+ client_queue = nil
460
+ res = nil
461
+ query=nil
462
+ client_queue = @@query_hash[id].client_queue
463
+ res = @@query_hash[id].single_resolver
464
+ query = @@query_hash[id].query
465
+
466
+ # NOW RESEND OVER TCP!
467
+ Thread.new {
468
+ res.send_async(query, client_queue, id, true)
469
+ }
470
+ sent = true
471
+ end
472
+ end
473
+ }
474
+ if !sent
475
+ send_exception_to_client(e, socket, client_id)
476
+ end
477
+
444
478
  else
445
- Dnsruby.log.error{"Decode error from #{answerfrom} but can't determine packet id"}
479
+ send_exception_to_client(e, socket, client_id)
446
480
  end
447
481
  return
448
482
  end
@@ -486,7 +520,6 @@ module Dnsruby
486
520
  query_settings = @@query_hash[id]
487
521
  if (answerip == query_settings.dest_server && answerport == query_settings.dest_port)
488
522
  # We have a match
489
- # - @TODO@ as long as we're not speaking to the same server on two ports!
490
523
  client_id = id
491
524
  break
492
525
  end
@@ -516,7 +549,7 @@ module Dnsruby
516
549
  else
517
550
  @@select_thread = Thread.new {
518
551
  do_select
519
- }
552
+ }
520
553
  end
521
554
  end
522
555
 
@@ -637,7 +670,7 @@ module Dnsruby
637
670
  def add_observer(client_queue, observer)
638
671
  @@mutex.synchronize {
639
672
  @@observers[client_queue]=observer
640
- check_select_thread_synchronized # Is this really necessary? The client should start the thread by sending a query, really...
673
+ check_select_thread_synchronized # Is this really necessary? The client should start the thread by sending a query, really...
641
674
  if (!@@tick_observers.include?observer)
642
675
  @@tick_observers.push(observer)
643
676
  end
@@ -669,7 +702,7 @@ module Dnsruby
669
702
  }
670
703
  if (observer)
671
704
  observer.handle_queue_event(client_queue, client_query_id)
672
- end
705
+ end
673
706
  end
674
707
 
675
708
  def send_tick_to_observers
@@ -31,8 +31,6 @@ module Dnsruby
31
31
  @added_dlv_key = false
32
32
  # The DNSKEY RRs for the signed root (when it exists)
33
33
  @root_anchors = KeyCache.new
34
- # Could add methods for interacting with root anchors - see test/tc_itar.rb
35
- # for example of how to load ITAR trust anchors into dnsruby
36
34
 
37
35
  # The set of trust anchors.
38
36
  # If the root is unsigned, then these must be initialised with at least
@@ -165,6 +163,10 @@ module Dnsruby
165
163
  @trusted_keys.add(k)
166
164
  end
167
165
 
166
+ def add_root_ds(ds)
167
+ @configured_ds_store.push(ds)
168
+ end
169
+
168
170
  # Wipes the cache of trusted keys
169
171
  def clear_trusted_keys
170
172
  @trusted_keys = KeyCache.new
@@ -89,7 +89,7 @@ module Dnsruby
89
89
  # Add the next line until we see a ")"
90
90
  # REMEMBER TO STRIP OFF COMMENTS!!!
91
91
  @continued_line = strip_comments(@continued_line)
92
- line = @continued_line.strip.chomp + " " + line
92
+ line = @continued_line.rstrip.chomp + " " + line
93
93
  if (line.index(")"))
94
94
  # OK
95
95
  @continued_line = false
@@ -104,7 +104,7 @@ require 'Dnsruby/TheLog'
104
104
  module Dnsruby
105
105
 
106
106
  # @TODO@ Remember to update version in dnsruby.gemspec!
107
- VERSION = 1.47
107
+ VERSION = 1.48
108
108
  def Dnsruby.version
109
109
  return VERSION
110
110
  end
@@ -468,6 +468,7 @@ module Dnsruby
468
468
 
469
469
  #Indicates an error in decoding an incoming DNS message
470
470
  class DecodeError < ResolvError
471
+ attr_accessor :partial_message
471
472
  end
472
473
 
473
474
  #Indicates an error encoding a DNS message for transmission
@@ -295,13 +295,22 @@ class TestRR < Test::Unit::TestCase
295
295
  rr = RR.create("all.rr.org. IN LOC 42 21 54 N 71 06 18 W -24m 30m")
296
296
  assert(rr.vert_pre == 1000)
297
297
  assert(rr.horiz_pre == 1000000)
298
- lon = rr.longitude
299
- # rr2 = RR.create("all.rr.org. 1209600 IN LOC 42 21 54.000 N 71 06 18.000 W 4294967272m 30m 10000m 10m")
300
- # print rr2.longitude
301
- # assert(rr2.longitude = lon)
302
- # print rr.to_s + "\n"
303
- # print rr2.to_s + "\n"
304
- # assert(rr.longitude == rr2.longitude)
305
- # assert(rr == rr2)
298
+ assert(rr.to_s.index("21"))
299
+ assert(rr.to_s.index("71"))
300
+ assert(rr.to_s.index("54"))
301
+ assert(rr.to_s.index("71"))
302
+ assert(rr.to_s.index("06"))
303
+ assert(rr.to_s.index("18"))
304
+
305
+ r2 = RR.create("helium IN LOC 51 49 17.9 N 4 39 22.9 E 0m")
306
+ assert(r2.size == 100)
307
+ assert(r2.to_s.index("17.9"))
308
+ assert(r2.to_s.index("22.9"))
309
+ end
310
+
311
+ def test_hinfo
312
+ rr = RR.create('helium IN HINFO "Shuttle-ST61G4 Intel PIV3000" "FreeBSD 7.0-STABLE"')
313
+ assert rr.to_s.index('"Shuttle-ST61G4 Intel PIV3000"')
314
+ assert rr.to_s.index('"FreeBSD 7.0-STABLE"')
306
315
  end
307
316
  end
@@ -29,13 +29,14 @@ class TestTcp < Test::Unit::TestCase
29
29
  end
30
30
  def test_TCP_port
31
31
  # Need a test server so we can tell what port this message was actually sent on!
32
- port = 59125
32
+ port = nil
33
33
  src_port = 57923
34
34
  Dnsruby::PacketSender.clear_caches
35
35
  received_port = nil
36
36
  server_thread = Thread.new {
37
- ts = TCPServer.new(port)
38
- t = ts.accept
37
+ ts = TCPServer.new(0)
38
+ port = ts.addr[1]
39
+ t = ts.accept
39
40
  # Check that the source port was src_port
40
41
  received_port = t.peeraddr()[1]
41
42
  packet = t.recvfrom(2)[0]
@@ -77,5 +78,114 @@ class TestTcp < Test::Unit::TestCase
77
78
  assert(ret.header.tc, "Message should be truncated with no TCP")
78
79
  end
79
80
 
81
+ class HackMessage < Dnsruby::Message
82
+ def wipe_additional
83
+ @additional = Dnsruby::Message::Section.new(self)
84
+ end
85
+
86
+ #Decode the encoded message
87
+ def HackMessage.decode(m)
88
+ o = HackMessage.new()
89
+ begin
90
+ Dnsruby::MessageDecoder.new(m) {|msg|
91
+ o.header = Dnsruby::Header.new(msg)
92
+ o.header.qdcount.times {
93
+ question = msg.get_question
94
+ o.question << question
95
+ }
96
+ o.header.ancount.times {
97
+ rr = msg.get_rr
98
+ o.answer << rr
99
+ }
100
+ o.header.nscount.times {
101
+ rr = msg.get_rr
102
+ o.authority << rr
103
+ }
104
+ o.header.arcount.times { |count|
105
+ start = msg.index
106
+ rr = msg.get_rr
107
+ if (rr.type == Dnsruby::Types::TSIG)
108
+ if (count!=o.header.arcount-1)
109
+ Dnsruby.log.Error("Incoming message has TSIG record before last record")
110
+ raise Dnsruby::DecodeError.new("TSIG record present before last record")
111
+ end
112
+ o.tsigstart = start # needed for TSIG verification
113
+ end
114
+ o.additional << rr
115
+ }
116
+ }
117
+ rescue Dnsruby::DecodeError => e
118
+ # So we got a decode error
119
+ # However, we might have been able to fill in many parts of the message
120
+ # So let's raise the DecodeError, but add the partially completed message
121
+ e.partial_message = o
122
+ raise e
123
+ end
124
+ return o
125
+ end
126
+
127
+ end
128
+
129
+ def test_bad_truncation
130
+ # Some servers don't do truncation properly.
131
+ # Make a UDP server which returns large badly formatted packets (arcount > num_additional), with TC bit set
132
+ # And make a TCP server which returns large well formatted packets
133
+ # Then make sure that Dnsruby recieves response correctly.
134
+ Dnsruby::PacketSender.clear_caches
135
+ socket = UDPSocket.new
136
+ socket.bind("127.0.0.1", 0)
137
+ port = socket.addr[1]
138
+ Thread.new {
139
+ s = socket.recvfrom(65536)
140
+ received_query = s[0]
141
+ socket.connect(s[1][2], s[1][1])
142
+ ans = HackMessage.decode(received_query)
143
+ ans.wipe_additional
144
+ 100.times {|i|
145
+ ans.add_additional(Dnsruby::RR.create("example.com 3600 IN A 1.2.3.#{i}"))
146
+ }
147
+ ans.header.arcount = 110
148
+ ans.header.tc = true
149
+ socket.send(ans.encode,0)
150
+ }
151
+
152
+ server_thread = Thread.new {
153
+ ts = TCPServer.new(port)
154
+ t = ts.accept
155
+ packet = t.recvfrom(2)[0]
156
+
157
+ len = (packet[0]<<8)+packet[1]
158
+ if (RUBY_VERSION >= "1.9")
159
+ len = (packet[0].getbyte(0)<<8)+packet[1].getbyte(0)# Ruby 1.9
160
+ end
161
+ packet = t.recvfrom(len)[0]
162
+ tcpPacket = HackMessage.decode(packet)
163
+ tcpPacket.wipe_additional
164
+ 110.times {|i|
165
+ tcpPacket.add_additional(Dnsruby::RR.create("example.com 3600 IN A 1.2.3.#{i}"))
166
+ }
167
+ lenmsg = [tcpPacket.encode.length].pack('n')
168
+ t.send(lenmsg, 0)
169
+ t.write(tcpPacket.encode)
170
+ t.close
171
+ ts.close
172
+ }
173
+
174
+
175
+
176
+ # Now send query
177
+ res = Dnsruby::Resolver.new("127.0.0.1")
178
+ res.port = port
179
+ res.udp_size = 4096
180
+ assert(res.udp_size == 4096)
181
+ ret = res.query("example.com")
182
+ assert(ret.header.arcount == 110)
183
+ count = 0
184
+ ret.additional.each {|rr| count += 1}
185
+ assert(count == 110)
186
+
187
+
188
+ end
189
+
80
190
  #@TODO@ Check stuff like persistent sockets
81
191
  end
@@ -25,6 +25,7 @@ class TestValidator < Test::Unit::TestCase
25
25
  Dnsruby::Dnssec.clear_trust_anchors
26
26
  res = Dnsruby::Resolver.new("dnssec.nominet.org.uk")
27
27
  res.dnssec=true
28
+ res.do_validation = true
28
29
  Dnsruby::Dnssec.do_validation_with_recursor(false)
29
30
  Dnsruby::Dnssec.default_resolver=(res) # This is a closed zone (not reachable by recursion)
30
31
 
@@ -93,7 +93,6 @@ if (online)
93
93
  puts "Running DNSSEC test - may fail if OpenSSL not complete"
94
94
  puts "------------------------------------------------------"
95
95
  require "test/tc_verifier.rb"
96
- require "test/tc_itar.rb"
97
96
  require "test/tc_dlv.rb"
98
97
  require "test/tc_validator.rb"
99
98
  end
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.47"
4
+ version: "1.48"
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: 2010-05-19 00:00:00 +01:00
12
+ date: 2010-07-23 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -39,7 +39,6 @@ files:
39
39
  - test/tc_header.rb
40
40
  - test/tc_hip.rb
41
41
  - test/tc_ipseckey.rb
42
- - test/tc_itar.rb
43
42
  - test/tc_misc.rb
44
43
  - test/tc_name.rb
45
44
  - test/tc_naptr.rb
@@ -141,7 +140,7 @@ files:
141
140
  - demo/check_soa.rb
142
141
  - demo/check_zone.rb
143
142
  - demo/digdlv.rb
144
- - demo/digitar.rb
143
+ - demo/digroot.rb
145
144
  - demo/example_recurse.rb
146
145
  - demo/mresolv.rb
147
146
  - demo/mx.rb
@@ -1,82 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
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
-
17
- require 'test/unit'
18
- require 'dnsruby'
19
- include Dnsruby
20
-
21
- class TestItar < Test::Unit::TestCase
22
- def test_itar
23
- Dnsruby::Dnssec.reset
24
- Dnsruby::PacketSender.clear_caches
25
- Dnsruby::Recursor.clear_caches
26
- run_test_se(true)
27
- Dnsruby::Dnssec.reset
28
- Dnsruby::Recursor.clear_caches
29
-
30
- # Then try to validate some records in the published zones
31
- Dnsruby::PacketSender.clear_caches
32
- # Download the ITAR - add the DS records to dnssec
33
- Dnssec.load_itar()
34
-
35
- run_test_se(false)
36
- end
37
-
38
- def test_with_no_dlv_anchor
39
- Dnsruby::Dnssec.reset
40
- Dnsruby::PacketSender.clear_caches
41
- Dnsruby::Recursor.clear_caches
42
- # Make sure we don't have any other anchors configured!
43
- res = Dnsruby::Recursor.new
44
- ret = res.query("frobbit.se.", Dnsruby::Types.A)
45
- assert(ret.security_level == Dnsruby::Message::SecurityLevel::INSECURE, "Level = #{ret.security_level.string}")
46
- Dnsruby::Dnssec.reset
47
- Dnsruby::PacketSender.clear_caches
48
- Dnsruby::Recursor.clear_caches
49
- Dnssec.load_itar
50
- res = Dnsruby::Recursor.new
51
- ret = res.query("frobbit.se.", Dnsruby::Types.A)
52
- assert(ret.security_level == Dnsruby::Message::SecurityLevel::SECURE)
53
-
54
- res = Dnsruby::Recursor.new
55
- ret = res.query("ns2.nic.se.", Dnsruby::Types.A)
56
- assert(ret.security_level == Dnsruby::Message::SecurityLevel::SECURE)
57
- end
58
-
59
- def run_test_se(should_fail)
60
- res = Dnsruby::Recursor.new
61
- r = res.query("frobbit.se.", Dnsruby::Types.A)
62
- if (!should_fail)
63
- assert(r.security_level == Dnsruby::Message::SecurityLevel::SECURE)
64
- else
65
- assert(r.security_level != Dnsruby::Message::SecurityLevel::SECURE)
66
- end
67
- # Haven't configured key for this, so should fail
68
- begin
69
- ret = Dnssec.verify(r)
70
- if (should_fail)
71
- fail
72
- end
73
- rescue (Dnsruby::VerifyError)
74
- if (!should_fail)
75
- fail
76
- end
77
- end
78
- # assert(!ret, "Dnssec message verification failed")
79
-
80
- end
81
-
82
- end