dnsruby 1.47 → 1.48

Sign up to get free protection for your applications and to get access to all the features.
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