net-dns 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/.gitignore +8 -6
  2. data/.travis.yml +14 -0
  3. data/CHANGELOG.md +79 -0
  4. data/Gemfile +4 -0
  5. data/Rakefile +56 -66
  6. data/demo/check_soa.rb +1 -1
  7. data/demo/threads.rb +1 -1
  8. data/lib/net/dns.rb +24 -22
  9. data/lib/net/dns/header.rb +77 -103
  10. data/lib/net/dns/{names/names.rb → names.rb} +19 -20
  11. data/lib/net/dns/packet.rb +231 -256
  12. data/lib/net/dns/question.rb +11 -40
  13. data/lib/net/dns/resolver.rb +248 -250
  14. data/lib/net/dns/resolver/socks.rb +6 -6
  15. data/lib/net/dns/resolver/timeouts.rb +1 -1
  16. data/lib/net/dns/rr.rb +112 -117
  17. data/lib/net/dns/rr/a.rb +98 -89
  18. data/lib/net/dns/rr/aaaa.rb +84 -68
  19. data/lib/net/dns/rr/classes.rb +91 -106
  20. data/lib/net/dns/rr/cname.rb +64 -45
  21. data/lib/net/dns/rr/hinfo.rb +90 -50
  22. data/lib/net/dns/rr/mr.rb +61 -44
  23. data/lib/net/dns/rr/mx.rb +73 -48
  24. data/lib/net/dns/rr/ns.rb +60 -46
  25. data/lib/net/dns/rr/null.rb +11 -12
  26. data/lib/net/dns/rr/ptr.rb +47 -34
  27. data/lib/net/dns/rr/soa.rb +5 -6
  28. data/lib/net/dns/rr/srv.rb +1 -4
  29. data/lib/net/dns/rr/txt.rb +14 -14
  30. data/lib/net/dns/rr/types.rb +13 -13
  31. data/lib/net/dns/version.rb +8 -14
  32. data/net-dns.gemspec +35 -0
  33. data/setup.rb +3 -2
  34. data/test/header_test.rb +18 -18
  35. data/test/names_test.rb +21 -0
  36. data/test/packet_test.rb +38 -31
  37. data/test/question_test.rb +23 -24
  38. data/test/resolver/timeouts_test.rb +13 -13
  39. data/test/resolver_test.rb +28 -20
  40. data/test/rr/a_test.rb +70 -23
  41. data/test/rr/aaaa_test.rb +109 -0
  42. data/test/rr/classes_test.rb +61 -49
  43. data/test/rr/cname_test.rb +97 -0
  44. data/test/rr/hinfo_test.rb +117 -0
  45. data/test/rr/mr_test.rb +105 -0
  46. data/test/rr/mx_test.rb +112 -0
  47. data/test/rr/ns_test.rb +34 -12
  48. data/test/rr/types_test.rb +4 -4
  49. data/test/rr_test.rb +1 -1
  50. metadata +77 -52
  51. data/AUTHORS.rdoc +0 -7
  52. data/CHANGELOG.rdoc +0 -46
  53. data/VERSION.yml +0 -5
@@ -1,23 +1,19 @@
1
- module Net
2
- module DNS
3
-
1
+ module Net # :nodoc:
2
+ module DNS
3
+
4
4
  module Names
5
-
6
- # Argument Error for class Net::DNS::Names.
7
- class ArgumentError < ArgumentError
8
- end
9
-
5
+
10
6
  # Base error class.
11
7
  class Error < StandardError
12
8
  end
13
-
9
+
14
10
  # Generic Names Error.
15
11
  class ExpandError < Error
16
12
  end
17
-
18
-
13
+
14
+
19
15
  INT16SZ = 2
20
-
16
+
21
17
  # Expand a compressed name in a DNS Packet object. Please
22
18
  # see RFC1025 for an explanation of how the compression
23
19
  # in DNS packets works, how may it be useful and how should
@@ -33,7 +29,7 @@ module Net
33
29
  while true
34
30
  raise ExpandError, "Offset is greater than packet lenght!" if packetlen < (offset+1)
35
31
  len = packet.unpack("@#{offset} C")[0]
36
-
32
+
37
33
  if len == 0
38
34
  offset += 1
39
35
  break
@@ -54,16 +50,19 @@ module Net
54
50
  offset += len
55
51
  end
56
52
  end
57
- return [name,offset] # name.chomp(".") if trailing dot has to be omitted
53
+ [name, offset] # name.chomp(".") if trailing dot has to be omitted
58
54
  end
59
-
55
+
60
56
  def pack_name(name)
61
- if name.size > 63
62
- raise ArgumentError, "Label data cannot exceed 63 chars"
57
+ if name.size > 255
58
+ raise ArgumentError, "Name may not exceed 255 chars"
63
59
  end
64
60
  arr = name.split(".")
65
61
  str = ""
66
62
  arr.each do |elem|
63
+ if elem.size > 63
64
+ raise ArgumentError, "Label may not exceed 63 chars"
65
+ end
67
66
  str += [elem.size,elem].pack("Ca*")
68
67
  end
69
68
  str += [0].pack("C")
@@ -105,7 +104,7 @@ module Net
105
104
  end
106
105
  return str,offset,names
107
106
  end
108
-
107
+
109
108
  def valid?(name)
110
109
  if name =~ /^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/i
111
110
  return name
@@ -113,7 +112,7 @@ module Net
113
112
  raise ArgumentError, "Invalid FQDN: #{name}"
114
113
  end
115
114
  end
116
-
115
+
117
116
  end
118
117
  end
119
- end
118
+ end
@@ -1,36 +1,28 @@
1
1
  require 'logger'
2
- require 'net/dns/names/names'
3
- require 'net/dns'
2
+ require 'net/dns/names'
4
3
  require 'net/dns/header'
5
4
  require 'net/dns/question'
6
5
  require 'net/dns/rr'
7
6
 
8
- module Net # :nodoc:
9
- module DNS
10
-
11
- # =Name
12
- #
13
- # Net::DNS::Packet - DNS packet object class
7
+ module Net
8
+ module DNS
9
+
14
10
  #
15
- # =Synopsis
16
- #
17
- # require 'net/dns/packet'
11
+ # = Net::DNS::Packet
18
12
  #
19
- # =Description
20
- #
21
13
  # The Net::DNS::Packet class represents an entire DNS packet,
22
- # divided in his main section:
23
- #
14
+ # divided in his main section:
15
+ #
24
16
  # * Header (instance of Net::DNS::Header)
25
17
  # * Question (array of Net::DNS::Question objects)
26
- # * Answer, Authority, Additional (each formed by an array of Net::DNS::RR
18
+ # * Answer, Authority, Additional (each formed by an array of Net::DNS::RR
27
19
  # objects)
28
20
  #
29
21
  # You can use this class whenever you need to create a DNS packet, whether
30
22
  # in an user application, in a resolver instance (have a look, for instance,
31
- # at the Net::DNS::Resolver#send method) or for a nameserver.
23
+ # at the <tt>Net::DNS::Resolver#send</tt> method) or for a nameserver.
32
24
  #
33
- # Some example:
25
+ # For example:
34
26
  #
35
27
  # # Create a packet
36
28
  # packet = Net::DNS::Packet.new("www.example.com")
@@ -39,7 +31,7 @@ module Net # :nodoc:
39
31
  # # Getting packet binary data, suitable for network transmission
40
32
  # data = packet.data
41
33
  #
42
- # A packet object can be created from binary data too, like an
34
+ # A packet object can be created from binary data too, like an
43
35
  # answer packet just received from a network stream:
44
36
  #
45
37
  # packet = Net::DNS::Packet::parse(data)
@@ -48,13 +40,13 @@ module Net # :nodoc:
48
40
  #
49
41
  # header = packet.header # Instance of Net::DNS::Header class
50
42
  # question = packet.question # Instance of Net::DNS::Question class
51
- #
43
+ #
52
44
  # # Iterate over additional RRs
53
45
  # packet.additional.each do |rr|
54
46
  # puts "Got an #{rr.type} record"
55
47
  # end
56
48
  #
57
- # Some iterators have been written to easy the access of those RRs,
49
+ # Some iterators have been written to easy the access of those RRs,
58
50
  # which are often the most important. So instead of doing:
59
51
  #
60
52
  # packet.answer.each do |rr|
@@ -71,10 +63,10 @@ module Net # :nodoc:
71
63
  #
72
64
  # Be sure you don't miss all the iterators in the class documentation.
73
65
  #
74
- # =Logging facility
75
- #
66
+ # == Logging facility
67
+ #
76
68
  # As Net::DNS::Resolver class, Net::DNS::Packet class has its own logging
77
- # facility too. It work in the same way the other one do, so you can
69
+ # facility too. It work in the same way the other one do, so you can
78
70
  # maybe want to override it or change the file descriptor.
79
71
  #
80
72
  # packet = Net::DNS::Packet.new("www.example.com")
@@ -83,49 +75,29 @@ module Net # :nodoc:
83
75
  # # or even
84
76
  # packet.logger = Logger.new("/tmp/packet.log")
85
77
  #
86
- # If the Net::DNS::Packet class is directly instantiated by the Net::DNS::Resolver
78
+ # If the <tt>Net::DNS::Packet</tt> class is directly instantiated by the <tt>Net::DNS::Resolver</tt>
87
79
  # class, like the great majority of the time, it will use the same logger facility.
88
80
  #
89
- # Logger level will be set to Logger::Debug if $DEBUG variable is set.
90
- #
91
- # =Error classes
92
- #
93
- # Some error classes has been defined for the Net::DNS::Packet class,
94
- # which are listed here to keep a light and browsable main documentation.
95
- # We have:
96
- #
97
- # ArgumentError:: Argument Error for class Net::DNS::Packet
98
- # PacketError:: Generic Packet Error
99
- #
100
- # =Copyright
101
- #
102
- # Copyright (c) 2006 Marco Ceresa
103
- #
104
- # All rights reserved. This program is free software; you may redistribute
105
- # it and/or modify it under the same terms as Ruby itself.
81
+ # Logger level will be set to <tt>Logger::Debug</tt> if <tt>$DEBUG</tt> variable is set.
106
82
  #
107
83
  class Packet
108
84
  include Names
109
-
110
- # Argument Error for class Net::DNS::Packet.
111
- class ArgumentError < ArgumentError
112
- end
113
-
85
+
114
86
  # Base error class.
115
87
  class Error < StandardError
116
88
  end
117
-
89
+
118
90
  # Generic Packet Error.
119
91
  class PacketError < Error
120
92
  end
121
-
122
-
93
+
94
+
123
95
  attr_reader :header, :question, :answer, :authority, :additional
124
96
  attr_reader :answerfrom, :answersize
125
-
126
- # Create a new instance of Net::DNS::Packet class. Arguments are the
127
- # canonical name of the resourse, an optional type field and an optional
128
- # class field. The record type and class can be omitted; they default
97
+
98
+ # Creates a new instance of <tt>Net::DNS::Packet</tt> class. Arguments are the
99
+ # canonical name of the resource, an optional type field and an optional
100
+ # class field. The record type and class can be omitted; they default
129
101
  # to +A+ and +IN+.
130
102
  #
131
103
  # packet = Net::DNS::Packet.new("www.example.com")
@@ -133,8 +105,7 @@ module Net # :nodoc:
133
105
  # packet = Net::DNS::Packet.new("example.com", Net::DNS::TXT, Net::DNS::CH)
134
106
  #
135
107
  # This class no longer instantiate object from binary data coming from
136
- # network streams. Please use Net::DNS::Packet.new_from_data instead.
137
- #
108
+ # network streams. Please use <tt>Net::DNS::Packet.parse</tt> instead.
138
109
  def initialize(name, type = Net::DNS::A, cls = Net::DNS::IN)
139
110
  @header = Net::DNS::Header.new(:qdCount => 1)
140
111
  @question = [Net::DNS::Question.new(name, type, cls)]
@@ -145,33 +116,13 @@ module Net # :nodoc:
145
116
  @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
146
117
  end
147
118
 
148
- # Create a new instance of Net::DNS::Packet class from binary data, taken
149
- # out by a network stream. For example:
150
- #
151
- # # udp_socket is an UDPSocket waiting for a response
152
- # ans = udp_socket.recvfrom(1500)
153
- # packet = Net::DNS::Packet::parse(ans)
154
- #
155
- # An optional +from+ argument can be used to specify the information
156
- # of the sender. If data is passed as is from a Socket#recvfrom call,
157
- # the method will accept it.
158
- #
159
- # Be sure that your network data is clean from any UDP/TCP header,
160
- # expecially when using RAW sockets.
161
- #
162
- def Packet.parse(*args)
163
- o = allocate
164
- o.send(:new_from_data, *args)
165
- o
166
- end
167
-
168
119
 
169
120
  # Checks if the packet is a QUERY packet
170
121
  def query?
171
122
  @header.opCode == Net::DNS::Header::QUERY
172
123
  end
173
124
 
174
- # Return the packet object in binary data, suitable
125
+ # Returns the packet object in binary data, suitable
175
126
  # for sending across a network stream.
176
127
  #
177
128
  # packet_data = packet.data
@@ -181,7 +132,7 @@ module Net # :nodoc:
181
132
  qdcount=ancount=nscount=arcount=0
182
133
  data = @header.data
183
134
  headerlength = data.length
184
-
135
+
185
136
  @question.each do |question|
186
137
  data += question.data
187
138
  qdcount += 1
@@ -198,7 +149,7 @@ module Net # :nodoc:
198
149
  data += rr.data#(data.length)
199
150
  arcount += 1
200
151
  end
201
-
152
+
202
153
  @header.qdCount = qdcount
203
154
  @header.anCount = ancount
204
155
  @header.nsCount = nscount
@@ -207,13 +158,13 @@ module Net # :nodoc:
207
158
  @header.data + data[Net::DNS::HFIXEDSZ..data.size]
208
159
  end
209
160
 
210
- # Same as Net::DNS::Packet#data, but implements name compression
161
+ # Same as <tt>Net::DNS::Packet#data</tt>, but implements name compression
211
162
  # (see RFC1025) for a considerable save of bytes.
212
163
  #
213
164
  # packet = Net::DNS::Packet.new("www.example.com")
214
165
  # puts "Size normal is #{packet.data.size} bytes"
215
166
  # puts "Size compressed is #{packet.data_comp.size} bytes"
216
- #
167
+ #
217
168
  def data_comp
218
169
  offset = 0
219
170
  compnames = {}
@@ -227,46 +178,47 @@ module Net # :nodoc:
227
178
  compnames.update(names)
228
179
  qdcount += 1
229
180
  end
230
-
181
+
231
182
  @answer.each do |rr|
232
183
  str,offset,names = rr.data(offset,compnames)
233
184
  data += str
234
185
  compnames.update(names)
235
186
  ancount += 1
236
187
  end
237
-
188
+
238
189
  @authority.each do |rr|
239
190
  str,offset,names = rr.data(offset,compnames)
240
191
  data += str
241
192
  compnames.update(names)
242
193
  nscount += 1
243
194
  end
244
-
195
+
245
196
  @additional.each do |rr|
246
197
  str,offset,names = rr.data(offset,compnames)
247
198
  data += str
248
199
  compnames.update(names)
249
200
  arcount += 1
250
201
  end
251
-
202
+
252
203
  @header.qdCount = qdcount
253
204
  @header.anCount = ancount
254
205
  @header.nsCount = nscount
255
206
  @header.arCount = arcount
256
-
207
+
257
208
  @header.data + data[Net::DNS::HFIXEDSZ..data.size]
258
209
  end
259
-
260
- # Inspect method
210
+
211
+ # Returns a string containing a human-readable representation
212
+ # of this <tt>Net::DNS::Packet</tt> instance.
261
213
  def inspect
262
214
  retval = ""
263
215
  if @answerfrom != "0.0.0.0:0" and @answerfrom
264
216
  retval += ";; Answer received from #@answerfrom (#{@answersize} bytes)\n;;\n"
265
217
  end
266
-
218
+
267
219
  retval += ";; HEADER SECTION\n"
268
220
  retval += @header.inspect
269
-
221
+
270
222
  retval += "\n"
271
223
  section = (@header.opCode == "UPDATE") ? "ZONE" : "QUESTION"
272
224
  retval += ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '' : 's'}):\n"
@@ -291,7 +243,7 @@ module Net # :nodoc:
291
243
  retval += rr.inspect + "\n"
292
244
  end
293
245
  end
294
-
246
+
295
247
  unless @additional.size == 0
296
248
  retval += "\n"
297
249
  retval += ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '' : 's'}):\n"
@@ -299,20 +251,18 @@ module Net # :nodoc:
299
251
  retval += rr.inspect + "\n"
300
252
  end
301
253
  end
302
-
254
+
303
255
  retval
304
256
  end
305
- alias_method :to_s, :inspect
306
-
307
- # Wrapper to Header#truncated?
308
- #
257
+ alias_method :to_s, :inspect
258
+
259
+ # Delegates to <tt>Net::DNS::Header#truncated?</tt>.
309
260
  def truncated?
310
261
  @header.truncated?
311
262
  end
312
-
313
- # Assing a Net::DNS::Header object to a Net::DNS::Packet
314
- # instance.
315
- #
263
+
264
+ # Assigns a <tt>Net::DNS::Header</tt> <tt>object</tt>
265
+ # to this <tt>Net::DNS::Packet</tt> instance.
316
266
  def header=(object)
317
267
  if object.kind_of? Net::DNS::Header
318
268
  @header = object
@@ -320,10 +270,9 @@ module Net # :nodoc:
320
270
  raise ArgumentError, "Argument must be a Net::DNS::Header object"
321
271
  end
322
272
  end
323
-
324
- # Assign a Net::DNS::Question object, or an array of
325
- # Questions objects, to a Net::DNS::Packet instance.
326
- #
273
+
274
+ # Assigns a <tt>Net::DNS::Question</tt> <tt>object</tt>
275
+ # to this <tt>Net::DNS::Packet</tt> instance.
327
276
  def question=(object)
328
277
  case object
329
278
  when Array
@@ -339,250 +288,276 @@ module Net # :nodoc:
339
288
  end
340
289
  end
341
290
 
342
- # Assign a Net::DNS::RR object, or an array of
343
- # RR objects, to a Net::DNS::Packet instance answer
344
- # section.
345
- #
291
+ # Assigns one or an array of <tt>Net::DNS::RR</tt> <tt>object</tt>s
292
+ # to the answer section of this <tt>Net::DNS::Packet</tt> instance.
346
293
  def answer=(object)
347
294
  case object
348
- when Array
349
- if object.all? {|x| x.kind_of? Net::DNS::RR}
350
- @answer = object
295
+ when Array
296
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
297
+ @answer = object
298
+ else
299
+ raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
300
+ end
301
+ when Net::DNS::RR
302
+ @answer = [object]
351
303
  else
352
- raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
353
- end
354
- when Net::DNS::RR
355
- @answer = [object]
356
- else
357
- raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
304
+ raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
358
305
  end
359
306
  end
360
307
 
361
- # Assign a Net::DNS::RR object, or an array of
362
- # RR objects, to a Net::DNS::Packet instance additional
363
- # section.
364
- #
308
+ # Assigns one or an array of <tt>Net::DNS::RR</tt> <tt>object</tt>s
309
+ # to the additional section of this <tt>Net::DNS::Packet</tt> instance.
365
310
  def additional=(object)
366
311
  case object
367
- when Array
368
- if object.all? {|x| x.kind_of? Net::DNS::RR}
369
- @additional = object
312
+ when Array
313
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
314
+ @additional = object
315
+ else
316
+ raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
317
+ end
318
+ when Net::DNS::RR
319
+ @additional = [object]
370
320
  else
371
- raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
372
- end
373
- when Net::DNS::RR
374
- @additional = [object]
375
- else
376
- raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
321
+ raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
377
322
  end
378
323
  end
379
324
 
380
- # Assign a Net::DNS::RR object, or an array of
381
- # RR objects, to a Net::DNS::Packet instance authority
382
- # section.
383
- #
325
+ # Assigns one or an array of <tt>Net::DNS::RR</tt> <tt>object</tt>s
326
+ # to the authority section of this <tt>Net::DNS::Packet</tt> instance.
384
327
  def authority=(object)
385
328
  case object
386
- when Array
387
- if object.all? {|x| x.kind_of? Net::DNS::RR}
388
- @authority = object
329
+ when Array
330
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
331
+ @authority = object
332
+ else
333
+ raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
334
+ end
335
+ when Net::DNS::RR
336
+ @authority = [object]
389
337
  else
390
- raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
391
- end
392
- when Net::DNS::RR
393
- @authority = [object]
394
- else
395
- raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
338
+ raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
396
339
  end
397
340
  end
398
-
399
- # Iterate for every address in the +answer+ section of a
400
- # Net::DNS::Packet object.
341
+
342
+ # Iterates every address in the +answer+ section
343
+ # of this <tt>Net::DNS::Packet</tt> instance.
401
344
  #
402
345
  # packet.each_address do |ip|
403
346
  # ping ip.to_s
404
347
  # end
405
348
  #
406
- # As you can see in the documentation for Net::DNS::RR::A class,
407
- # the address returned is an instance of IPAddr class.
408
- #
409
- def each_address
349
+ # As you can see in the documentation for the <tt>Net::DNS::RR::A</tt> class,
350
+ # the address returned is an instance of <tt>IPAddr</tt> class.
351
+ def each_address(&block)
410
352
  @answer.each do |elem|
411
353
  next unless elem.class == Net::DNS::RR::A
412
354
  yield elem.address
413
355
  end
414
356
  end
415
-
416
- # Iterate for every nameserver in the +answer+ section of a
417
- # Net::DNS::Packet object.
357
+
358
+ # Iterates every nameserver in the +answer+ section
359
+ # of this <tt>Net::DNS::Packet</tt> instance.
418
360
  #
419
361
  # packet.each_nameserver do |ns|
420
362
  # puts "Nameserver found: #{ns}"
421
363
  # end
422
364
  #
423
- def each_nameserver
365
+ def each_nameserver(&block)
424
366
  @answer.each do |elem|
425
367
  next unless elem.class == Net::DNS::RR::NS
426
368
  yield elem.nsdname
427
369
  end
428
370
  end
429
-
430
- # Iterate for every exchange record in the +answer+ section
431
- # of a Net::DNS::Packet object.
371
+
372
+ # Iterates every exchange record in the +answer+ section
373
+ # of this <tt>Net::DNS::Packet</tt> instance.
432
374
  #
433
375
  # packet.each_mx do |pref,name|
434
376
  # puts "Mail exchange #{name} has preference #{pref}"
435
377
  # end
436
378
  #
437
- def each_mx
379
+ def each_mx(&block)
438
380
  @answer.each do |elem|
439
381
  next unless elem.class == Net::DNS::RR::MX
440
- yield elem.preference,elem.exchange
382
+ yield elem.preference, elem.exchange
441
383
  end
442
384
  end
443
-
444
- # Iterate for every canonical name in the +answer+ section
445
- # of a Net::DNS::Packet object.
385
+
386
+ # Iterates every canonical name in the +answer+ section
387
+ # of this <tt>Net::DNS::Packet</tt> instance.
446
388
  #
447
389
  # packet.each_cname do |cname|
448
390
  # puts "Canonical name: #{cname}"
449
391
  # end
450
392
  #
451
- def each_cname
393
+ def each_cname(&block)
452
394
  @answer.each do |elem|
453
395
  next unless elem.class == Net::DNS::RR::CNAME
454
396
  yield elem.cname
455
397
  end
456
398
  end
457
-
458
- # Iterate for every pointer in the +answer+ section of a
459
- # Net::DNS::Packet object.
399
+
400
+ # Iterates every pointer in the +answer+ section
401
+ # of this <tt>Net::DNS::Packet</tt> instance.
460
402
  #
461
403
  # packet.each_ptr do |ptr|
462
404
  # puts "Pointer for resource: #{ptr}"
463
405
  # end
464
406
  #
465
- def each_ptr
407
+ def each_ptr(&block)
466
408
  @answer.each do |elem|
467
409
  next unless elem.class == Net::DNS::RR::PTR
468
410
  yield elem.ptrdname
469
411
  end
470
412
  end
471
413
 
472
- # Returns the packet size in bytes
414
+ # Returns the packet size in bytes.
473
415
  #
474
- # Resolver("www.google.com") do |packet|
416
+ # Resolver("www.google.com") do |packet|
475
417
  # puts packet.size + " bytes"}
476
418
  # end
477
- # #=> 484 bytes
419
+ # # => 484 bytes
478
420
  #
479
421
  def size
480
422
  data.size
481
423
  end
482
424
 
483
- # Checks whether a query has returned a NXDOMAIN error,
484
- # meaning the domain name queried doesn't exists.
425
+ # Checks whether the query returned a NXDOMAIN error,
426
+ # meaning the queried domain name doesn't exist.
485
427
  #
486
428
  # %w[a.com google.com ibm.com d.com].each do |domain|
487
429
  # response = Net::DNS::Resolver.new.send(domain)
488
430
  # puts "#{domain} doesn't exist" if response.nxdomain?
489
431
  # end
490
- # #=> a.com doesn't exist
491
- # #=> d.com doesn't exist
432
+ # # => a.com doesn't exist
433
+ # # => d.com doesn't exist
492
434
  #
493
435
  def nxdomain?
494
436
  header.rCode.code == Net::DNS::Header::RCode::NAME
495
437
  end
496
-
438
+
439
+
440
+ # Creates a new instance of <tt>Net::DNS::Packet</tt> class from binary data,
441
+ # taken out from a network stream. For example:
442
+ #
443
+ # # udp_socket is an UDPSocket waiting for a response
444
+ # ans = udp_socket.recvfrom(1500)
445
+ # packet = Net::DNS::Packet::parse(ans)
446
+ #
447
+ # An optional +from+ argument can be used to specify the information
448
+ # of the sender. If data is passed as is from a Socket#recvfrom call,
449
+ # the method will accept it.
450
+ #
451
+ # Be sure that your network data is clean from any UDP/TCP header,
452
+ # especially when using RAW sockets.
453
+ #
454
+ def self.parse(*args)
455
+ o = allocate
456
+ o.send(:new_from_data, *args)
457
+ o
458
+ end
459
+
497
460
  private
498
461
 
499
- # New packet from binary data
500
- def new_from_data(data, from = nil)
501
- unless from
502
- if data.kind_of? Array
503
- data,from = data
504
- else
505
- from = [0,0,"0.0.0.0","unknown"]
462
+ # New packet from binary data
463
+ def new_from_data(data, from = nil)
464
+ unless from
465
+ if data.kind_of? Array
466
+ data, from = data
467
+ else
468
+ from = [0, 0, "0.0.0.0", "unknown"]
469
+ end
506
470
  end
507
- end
508
-
509
- @answerfrom = from[2] + ":" + from[1].to_s
510
- @answersize = data.size
511
- @logger = Logger.new $stdout
512
- @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
513
-
514
- #------------------------------------------------------------
515
- # Header section
516
- #------------------------------------------------------------
517
- offset = Net::DNS::HFIXEDSZ
518
- @header = Net::DNS::Header.parse(data[0..offset-1])
519
-
520
- @logger.debug ";; HEADER SECTION"
521
- @logger.debug @header.inspect
522
-
523
- #------------------------------------------------------------
524
- # Question section
525
- #------------------------------------------------------------
526
- section = @header.opCode == "UPDATE" ? "ZONE" : "QUESTION"
527
- @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
528
-
529
- @question = []
530
- @header.qdCount.times do
531
- qobj,offset = parse_question(data,offset)
532
- @question << qobj
533
- @logger.debug ";; #{qobj.inspect}"
534
- end
535
471
 
536
- #------------------------------------------------------------
537
- # Answer/prerequisite section
538
- #------------------------------------------------------------
539
- section = @header.opCode == "UPDATE" ? "PREREQUISITE" : "ANSWER"
540
- @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
541
-
542
- @answer = []
543
- @header.anCount.times do
544
- rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
545
- @answer << rrobj
546
- @logger.debug rrobj.inspect
547
- end
472
+ @answerfrom = from[2] + ":" + from[1].to_s
473
+ @answersize = data.size
474
+ @logger = Logger.new $stdout
475
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
476
+
477
+ #------------------------------------------------------------
478
+ # Header section
479
+ #------------------------------------------------------------
480
+ offset = Net::DNS::HFIXEDSZ
481
+ @header = Net::DNS::Header.parse(data[0..offset-1])
482
+
483
+ @logger.debug ";; HEADER SECTION"
484
+ @logger.debug @header.inspect
485
+
486
+ #------------------------------------------------------------
487
+ # Question section
488
+ #------------------------------------------------------------
489
+ section = @header.opCode == "UPDATE" ? "ZONE" : "QUESTION"
490
+ @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
491
+
492
+ @question = []
493
+ @header.qdCount.times do
494
+ qobj,offset = parse_question(data,offset)
495
+ @question << qobj
496
+ @logger.debug ";; #{qobj.inspect}"
497
+ end
498
+
499
+ #------------------------------------------------------------
500
+ # Answer/prerequisite section
501
+ #------------------------------------------------------------
502
+ section = @header.opCode == "UPDATE" ? "PREREQUISITE" : "ANSWER"
503
+ @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
504
+
505
+ @answer = []
506
+ @header.anCount.times do
507
+ begin
508
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
509
+ @answer << rrobj
510
+ @logger.debug rrobj.inspect
511
+ rescue NameError => e
512
+ warn "Net::DNS unsupported record type: #{e.message}"
513
+ end
514
+ end
515
+
516
+ #------------------------------------------------------------
517
+ # Authority/update section
518
+ #------------------------------------------------------------
519
+ section = @header.opCode == "UPDATE" ? "UPDATE" : "AUTHORITY"
520
+ @logger.debug ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '': 's'})"
521
+
522
+ @authority = []
523
+ @header.nsCount.times do
524
+ begin
525
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
526
+ @authority << rrobj
527
+ @logger.debug rrobj.inspect
528
+ rescue NameError => e
529
+ warn "Net::DNS unsupported record type: #{e.message}"
530
+ end
531
+ end
532
+
533
+ #------------------------------------------------------------
534
+ # Additional section
535
+ #------------------------------------------------------------
536
+ @logger.debug ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '': 's'})"
537
+
538
+ @additional = []
539
+ @header.arCount.times do
540
+ begin
541
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
542
+ @additional << rrobj
543
+ @logger.debug rrobj.inspect
544
+ rescue NameError => e
545
+ warn "Net::DNS supported record type: #{e.message}"
546
+ end
547
+ end
548
548
 
549
- #------------------------------------------------------------
550
- # Authority/update section
551
- #------------------------------------------------------------
552
- section = @header.opCode == "UPDATE" ? "UPDATE" : "AUTHORITY"
553
- @logger.debug ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '': 's'})"
554
-
555
- @authority = []
556
- @header.nsCount.times do
557
- rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
558
- @authority << rrobj
559
- @logger.debug rrobj.inspect
560
549
  end
561
-
562
- #------------------------------------------------------------
563
- # Additional section
564
- #------------------------------------------------------------
565
- @logger.debug ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '': 's'})"
566
-
567
- @additional = []
568
- @header.arCount.times do
569
- rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
570
- @additional << rrobj
571
- @logger.debug rrobj.inspect
550
+
551
+
552
+ # Parse question section
553
+ def parse_question(data,offset)
554
+ size = (dn_expand(data, offset)[1] - offset) + (2 * Net::DNS::INT16SZ)
555
+ return [Net::DNS::Question.parse(data[offset, size]), offset + size]
556
+ rescue StandardError => e
557
+ raise PacketError, "Caught exception, maybe packet malformed => #{e.message}"
572
558
  end
573
-
574
- end # new_from_data
575
-
576
-
577
- # Parse question section
578
- def parse_question(data,offset)
579
- size = (dn_expand(data,offset)[1]-offset) + 2*Net::DNS::INT16SZ
580
- return [Net::DNS::Question.parse(data[offset,size]), offset+size]
581
- rescue StandardError => e
582
- raise PacketError, "Caught exception, maybe packet malformed => #{e.message}"
583
- end
584
559
 
585
560
  end
586
-
561
+
587
562
  end
588
563
  end