bluemonk-net-dns 0.5.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.
@@ -0,0 +1,109 @@
1
+ module Net # :nodoc:
2
+ module DNS
3
+
4
+ module Names # :nodoc: all
5
+
6
+ INT16SZ = 2
7
+
8
+ # Expand a compressed name in a DNS Packet object. Please
9
+ # see RFC1025 for an explanation of how the compression
10
+ # in DNS packets works, how may it be useful and how should
11
+ # be handled.
12
+ #
13
+ # This method accept two parameters: a raw packet data and an
14
+ # offset, which indicates the point in the packet in which the
15
+ # parsing has arrived.
16
+ #
17
+ def dn_expand(packet,offset)
18
+ name = ""
19
+ packetlen = packet.size
20
+ while true
21
+ raise ExpandError, "offset is greater than packet lenght!" if packetlen < (offset+1)
22
+ len = packet.unpack("@#{offset} C")[0]
23
+
24
+ if len == 0
25
+ offset += 1
26
+ break
27
+ elsif (len & 0xC0) == 0xC0
28
+ raise ExpandError, "Packet ended before offset expand" if packetlen < (offset+INT16SZ)
29
+ ptr = packet.unpack("@#{offset} n")[0]
30
+ ptr &= 0x3FFF
31
+ name2 = dn_expand(packet,ptr)[0]
32
+ raise ExpandError, "Packet is malformed!" if name2 == nil
33
+ name += name2
34
+ offset += INT16SZ
35
+ break
36
+ else
37
+ offset += 1
38
+ raise ExpandError, "No expansion found" if packetlen < (offset+len)
39
+ elem = packet[offset..offset+len-1]
40
+ name += "#{elem}."
41
+ offset += len
42
+ end
43
+ end
44
+ return [name,offset] # name.chomp(".") if trailing dot has to be omitted
45
+ end
46
+
47
+ def pack_name(name)
48
+ if name.size > 63
49
+ raise ArgumentError, "Label data cannot exceed 63 chars"
50
+ end
51
+ arr = name.split(".")
52
+ str = ""
53
+ arr.each do |elem|
54
+ str += [elem.size,elem].pack("Ca*")
55
+ end
56
+ str += [0].pack("C")
57
+ str
58
+ end
59
+
60
+ def names_array(name)
61
+ arr = name.split(".")
62
+ ar = []
63
+ string = ""
64
+ arr.size.times do |i|
65
+ x = i+1
66
+ elem = arr[-x]
67
+ len = elem.size
68
+ string = ((string.reverse)+([len,elem].pack("Ca*")).reverse).reverse
69
+ ar.unshift(string)
70
+ end
71
+ return ar
72
+ end
73
+
74
+ def dn_comp(name,offset,compnames)
75
+ names = {}
76
+ ptr = 0
77
+ str = ""
78
+ arr = names_array(name)
79
+ arr.each do |entry|
80
+ if compnames.has_key?(entry)
81
+ ptr = 0xC000 | compnames[entry]
82
+ str += [ptr].pack("n")
83
+ offset += INT16SZ
84
+ break
85
+ else
86
+ len = entry.unpack("C")[0]
87
+ elem = entry[1..len]
88
+ str += [len,elem].pack("Ca*")
89
+ names.update({"#{entry}" => offset})
90
+ offset += len
91
+ end
92
+ end
93
+ return str,offset,names
94
+ end
95
+
96
+ def valid?(name)
97
+ 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
98
+ return name
99
+ else
100
+ raise ArgumentError, "Invalid FQDN: #{name}"
101
+ end
102
+ end
103
+
104
+ end # module Names
105
+ end # module DNS
106
+ end # module Net
107
+
108
+ class ExpandError < StandardError # :nodoc:
109
+ end
@@ -0,0 +1,581 @@
1
+ require 'logger'
2
+ require 'net/dns/names/names'
3
+ require 'net/dns/dns'
4
+ require 'net/dns/header'
5
+ require 'net/dns/question'
6
+ require 'net/dns/rr'
7
+
8
+ module Net # :nodoc:
9
+ module DNS
10
+
11
+ # =Name
12
+ #
13
+ # Net::DNS::Packet - DNS packet object class
14
+ #
15
+ # =Synopsis
16
+ #
17
+ # require 'net/dns/packet'
18
+ #
19
+ # =Description
20
+ #
21
+ # The Net::DNS::Packet class represents an entire DNS packet,
22
+ # divided in his main section:
23
+ #
24
+ # * Header (instance of Net::DNS::Header)
25
+ # * Question (array of Net::DNS::Question objects)
26
+ # * Answer, Authority, Additional (each formed by an array of Net::DNS::RR
27
+ # objects)
28
+ #
29
+ # You can use this class whenever you need to create a DNS packet, whether
30
+ # 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.
32
+ #
33
+ # Some example:
34
+ #
35
+ # # Create a packet
36
+ # packet = Net::DNS::Packet.new("www.example.com")
37
+ # mx = Net::DNS::Packet.new("example.com", Net::DNS::MX)
38
+ #
39
+ # # Getting packet binary data, suitable for network transmission
40
+ # data = packet.data
41
+ #
42
+ # A packet object can be created from binary data too, like an
43
+ # answer packet just received from a network stream:
44
+ #
45
+ # packet = Net::DNS::Packet::parse(data)
46
+ #
47
+ # Each part of a packet can be gotten by the right accessors:
48
+ #
49
+ # header = packet.header # Instance of Net::DNS::Header class
50
+ # question = packet.question # Instance of Net::DNS::Question class
51
+ #
52
+ # # Iterate over additional RRs
53
+ # packet.additional.each do |rr|
54
+ # puts "Got an #{rr.type} record"
55
+ # end
56
+ #
57
+ # Some iterators have been written to easy the access of those RRs,
58
+ # which are often the most important. So instead of doing:
59
+ #
60
+ # packet.answer.each do |rr|
61
+ # if rr.type == Net::DNS::RR::Types::A
62
+ # # do something with +rr.address+
63
+ # end
64
+ # end
65
+ #
66
+ # we can do:
67
+ #
68
+ # packet.each_address do |ip|
69
+ # # do something with +ip+
70
+ # end
71
+ #
72
+ # Be sure you don't miss all the iterators in the class documentation.
73
+ #
74
+ # =Logging facility
75
+ #
76
+ # 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
78
+ # maybe want to override it or change the file descriptor.
79
+ #
80
+ # packet = Net::DNS::Packet.new("www.example.com")
81
+ # packet.logger = $stderr
82
+ #
83
+ # # or even
84
+ # packet.logger = Logger.new("/tmp/packet.log")
85
+ #
86
+ # If the Net::DNS::Packet class is directly instantiated by the Net::DNS::Resolver
87
+ # class, like the great majority of the time, it will use the same logger facility.
88
+ #
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
+ # * PacketArgumentError: Generic 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.
106
+ #
107
+ class Packet
108
+
109
+ include Names
110
+
111
+ attr_reader :header, :question, :answer, :authority, :additional
112
+ attr_reader :answerfrom, :answersize
113
+
114
+ # Create a new instance of Net::DNS::Packet class. Arguments are the
115
+ # canonical name of the resourse, an optional type field and an optional
116
+ # class field. The record type and class can be omitted; they default
117
+ # to +A+ and +IN+.
118
+ #
119
+ # packet = Net::DNS::Packet.new("www.example.com")
120
+ # packet = Net::DNS::Packet.new("example.com", Net::DNS::MX)
121
+ # packet = Net::DNS::Packet.new("example.com",Net::DNS::TXT,Net::DNS::CH)
122
+ #
123
+ # This class no longer instantiate object from binary data coming from
124
+ # network streams. Please use Net::DNS::Packet.new_from_data instead.
125
+ #
126
+ def initialize(name,type=Net::DNS::A,cls=Net::DNS::IN)
127
+ @header = Net::DNS::Header.new(:qdCount => 1)
128
+ @question = [Net::DNS::Question.new(name,type,cls)]
129
+ @answer = []
130
+ @authority = []
131
+ @additional = []
132
+ @logger = Logger.new $stdout
133
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
134
+ end
135
+
136
+ # Create a new instance of Net::DNS::Packet class from binary data, taken
137
+ # out by a network stream. For example:
138
+ #
139
+ # # udp_socket is an UDPSocket waiting for a response
140
+ # ans = udp_socket.recvfrom(1500)
141
+ # packet = Net::DNS::Packet::parse(ans)
142
+ #
143
+ # An optional +from+ argument can be used to specify the information
144
+ # of the sender. If data is passed as is from a Socket#recvfrom call,
145
+ # the method will accept it.
146
+ #
147
+ # Be sure that your network data is clean from any UDP/TCP header,
148
+ # expecially when using RAW sockets.
149
+ #
150
+ def Packet.parse(*args)
151
+ o = allocate
152
+ o.send(:new_from_data, *args)
153
+ o
154
+ end
155
+
156
+
157
+ # Checks if the packet is a QUERY packet
158
+ def query?
159
+ @header.opCode == Net::DNS::Header::QUERY
160
+ end
161
+
162
+ # Return the packet object in binary data, suitable
163
+ # for sending across a network stream.
164
+ #
165
+ # packet_data = packet.data
166
+ # puts "Packet is #{packet_data.size} bytes long"
167
+ #
168
+ def data
169
+ qdcount=ancount=nscount=arcount=0
170
+ data = @header.data
171
+ headerlength = data.length
172
+
173
+ @question.each do |question|
174
+ data += question.data
175
+ qdcount += 1
176
+ end
177
+ @answer.each do |rr|
178
+ data += rr.data#(data.length)
179
+ ancount += 1
180
+ end
181
+ @authority.each do |rr|
182
+ data += rr.data#(data.length)
183
+ nscount += 1
184
+ end
185
+ @additional.each do |rr|
186
+ data += rr.data#(data.length)
187
+ arcount += 1
188
+ end
189
+
190
+ @header.qdCount = qdcount
191
+ @header.anCount = ancount
192
+ @header.nsCount = nscount
193
+ @header.arCount = arcount
194
+
195
+ @header.data + data[Net::DNS::HFIXEDSZ..data.size]
196
+ end
197
+
198
+ # Same as Net::DNS::Packet#data, but implements name compression
199
+ # (see RFC1025) for a considerable save of bytes.
200
+ #
201
+ # packet = Net::DNS::Packet.new("www.example.com")
202
+ # puts "Size normal is #{packet.data.size} bytes"
203
+ # puts "Size compressed is #{packet.data_comp.size} bytes"
204
+ #
205
+ def data_comp
206
+ offset = 0
207
+ compnames = {}
208
+ qdcount=ancount=nscount=arcount=0
209
+ data = @header.data
210
+ headerlength = data.length
211
+
212
+ @question.each do |question|
213
+ str,offset,names = question.data
214
+ data += str
215
+ compnames.update(names)
216
+ qdcount += 1
217
+ end
218
+
219
+ @answer.each do |rr|
220
+ str,offset,names = rr.data(offset,compnames)
221
+ data += str
222
+ compnames.update(names)
223
+ ancount += 1
224
+ end
225
+
226
+ @authority.each do |rr|
227
+ str,offset,names = rr.data(offset,compnames)
228
+ data += str
229
+ compnames.update(names)
230
+ nscount += 1
231
+ end
232
+
233
+ @additional.each do |rr|
234
+ str,offset,names = rr.data(offset,compnames)
235
+ data += str
236
+ compnames.update(names)
237
+ arcount += 1
238
+ end
239
+
240
+ @header.qdCount = qdcount
241
+ @header.anCount = ancount
242
+ @header.nsCount = nscount
243
+ @header.arCount = arcount
244
+
245
+ @header.data + data[Net::DNS::HFIXEDSZ..data.size]
246
+ end
247
+
248
+ # Inspect method
249
+ def inspect
250
+ retval = ""
251
+ if @answerfrom != "0.0.0.0:0" and @answerfrom
252
+ retval += ";; Answer received from #@answerfrom (#{@answersize} bytes)\n;;\n"
253
+ end
254
+
255
+ retval += ";; HEADER SECTION\n"
256
+ retval += @header.inspect
257
+
258
+ retval += "\n"
259
+ section = (@header.opCode == "UPDATE") ? "ZONE" : "QUESTION"
260
+ retval += ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '' : 's'}):\n"
261
+ @question.each do |qr|
262
+ retval += ";; " + qr.inspect + "\n"
263
+ end
264
+
265
+ unless @answer.size == 0
266
+ retval += "\n"
267
+ section = (@header.opCode == "UPDATE") ? "PREREQUISITE" : "ANSWER"
268
+ retval += ";; #{section} SECTION (#{@header.anCount} record#{@header.anCount == 1 ? '' : 's'}):\n"
269
+ @answer.each do |rr|
270
+ retval += rr.inspect + "\n"
271
+ end
272
+ end
273
+
274
+ unless @authority.size == 0
275
+ retval += "\n"
276
+ section = (@header.opCode == "UPDATE") ? "UPDATE" : "AUTHORITY"
277
+ retval += ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '' : 's'}):\n"
278
+ @authority.each do |rr|
279
+ retval += rr.inspect + "\n"
280
+ end
281
+ end
282
+
283
+ unless @additional.size == 0
284
+ retval += "\n"
285
+ retval += ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '' : 's'}):\n"
286
+ @additional.each do |rr|
287
+ retval += rr.inspect + "\n"
288
+ end
289
+ end
290
+
291
+ retval
292
+ end
293
+
294
+
295
+ # Wrapper to Header#truncated?
296
+ #
297
+ def truncated?
298
+ @header.truncated?
299
+ end
300
+
301
+ # Assing a Net::DNS::Header object to a Net::DNS::Packet
302
+ # instance.
303
+ #
304
+ def header=(object)
305
+ if object.kind_of? Net::DNS::Header
306
+ @header = object
307
+ else
308
+ raise PacketArgumentError, "Argument must be a Net::DNS::Header object"
309
+ end
310
+ end
311
+
312
+ # Assign a Net::DNS::Question object, or an array of
313
+ # Questions objects, to a Net::DNS::Packet instance.
314
+ #
315
+ def question=(object)
316
+ case object
317
+ when Array
318
+ if object.all? {|x| x.kind_of? Net::DNS::Question}
319
+ @question = object
320
+ else
321
+ raise PacketArgumentError, "Some of the elements is not an Net::DNS::Question object"
322
+ end
323
+ when Net::DNS::Question
324
+ @question = [object]
325
+ else
326
+ raise PacketArgumentError, "Invalid argument, not a Question object nor an array of objects"
327
+ end
328
+ end
329
+
330
+ # Assign a Net::DNS::RR object, or an array of
331
+ # RR objects, to a Net::DNS::Packet instance answer
332
+ # section.
333
+ #
334
+ def answer=(object)
335
+ case object
336
+ when Array
337
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
338
+ @answer = object
339
+ else
340
+ raise PacketArgumentError, "Some of the elements is not an Net::DNS::RR object"
341
+ end
342
+ when Net::DNS::RR
343
+ @answer = [object]
344
+ else
345
+ raise PacketArgumentError, "Invalid argument, not a RR object nor an array of objects"
346
+ end
347
+ end
348
+
349
+ # Assign a Net::DNS::RR object, or an array of
350
+ # RR objects, to a Net::DNS::Packet instance additional
351
+ # section.
352
+ #
353
+ def additional=(object)
354
+ case object
355
+ when Array
356
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
357
+ @additional = object
358
+ else
359
+ raise PacketArgumentError, "Some of the elements is not an Net::DNS::RR object"
360
+ end
361
+ when Net::DNS::RR
362
+ @additional = [object]
363
+ else
364
+ raise PacketArgumentError, "Invalid argument, not a RR object nor an array of objects"
365
+ end
366
+ end
367
+
368
+ # Assign a Net::DNS::RR object, or an array of
369
+ # RR objects, to a Net::DNS::Packet instance authority
370
+ # section.
371
+ #
372
+ def authority=(object)
373
+ case object
374
+ when Array
375
+ if object.all? {|x| x.kind_of? Net::DNS::RR}
376
+ @authority = object
377
+ else
378
+ raise PacketArgumentError, "Some of the elements is not an Net::DNS::RR object"
379
+ end
380
+ when Net::DNS::RR
381
+ @authority = [object]
382
+ else
383
+ raise PacketArgumentError, "Invalid argument, not a RR object nor an array of objects"
384
+ end
385
+ end
386
+
387
+ # Iterate for every address in the +answer+ section of a
388
+ # Net::DNS::Packet object.
389
+ #
390
+ # packet.each_address do |ip|
391
+ # ping ip.to_s
392
+ # end
393
+ #
394
+ # As you can see in the documentation for Net::DNS::RR::A class,
395
+ # the address returned is an instance of IPAddr class.
396
+ #
397
+ def each_address
398
+ @answer.each do |elem|
399
+ next unless elem.class == Net::DNS::RR::A
400
+ yield elem.address
401
+ end
402
+ end
403
+
404
+ # Iterate for every nameserver in the +answer+ section of a
405
+ # Net::DNS::Packet object.
406
+ #
407
+ # packet.each_nameserver do |ns|
408
+ # puts "Nameserver found: #{ns}"
409
+ # end
410
+ #
411
+ def each_nameserver
412
+ @answer.each do |elem|
413
+ next unless elem.class == Net::DNS::RR::NS
414
+ yield elem.nsdname
415
+ end
416
+ end
417
+
418
+ # Iterate for every exchange record in the +answer+ section
419
+ # of a Net::DNS::Packet object.
420
+ #
421
+ # packet.each_mx do |pref,name|
422
+ # puts "Mail exchange #{name} has preference #{pref}"
423
+ # end
424
+ #
425
+ def each_mx
426
+ @answer.each do |elem|
427
+ next unless elem.class == Net::DNS::RR::MX
428
+ yield elem.preference,elem.exchange
429
+ end
430
+ end
431
+
432
+ # Iterate for every canonical name in the +answer+ section
433
+ # of a Net::DNS::Packet object.
434
+ #
435
+ # packet.each_cname do |cname|
436
+ # puts "Canonical name: #{cname}"
437
+ # end
438
+ #
439
+ def each_cname
440
+ @answer.each do |elem|
441
+ next unless elem.class == Net::DNS::RR::CNAME
442
+ yield elem.cname
443
+ end
444
+ end
445
+
446
+ # Iterate for every pointer in the +answer+ section of a
447
+ # Net::DNS::Packet object.
448
+ #
449
+ # packet.each_ptr do |ptr|
450
+ # puts "Pointer for resource: #{ptr}"
451
+ # end
452
+ #
453
+ def each_ptr
454
+ @answer.each do |elem|
455
+ next unless elem.class == Net::DNS::RR::PTR
456
+ yield elem.ptrdname
457
+ end
458
+ end
459
+
460
+ # Returns the packet size in bytes
461
+ #
462
+ # Resolver("www.google.com") do |packet|
463
+ # puts packet.size + " bytes"}
464
+ # end
465
+ # #=> 484 bytes
466
+ #
467
+ def size
468
+ data.size
469
+ end
470
+
471
+ # Chacks whether a query has returned a NXDOMAIN error,
472
+ # meaning the domain name queried doesn't exists.
473
+ #
474
+ # %w[a.com google.com ibm.com d.com].each do |domain|
475
+ # response = Net::DNS::Resolver.new.send(domain)
476
+ # puts "#{domain} doesn't exist" if response.nxdomain?
477
+ # end
478
+ # #=> a.com doesn't exist
479
+ # #=> d.com doesn't exist
480
+ #
481
+ def nxdomain?
482
+ header.rCode == Net::DNS::Header::NAME
483
+ end
484
+
485
+ private
486
+
487
+ # New packet from binary data
488
+ def new_from_data(data, from = nil)
489
+ unless from
490
+ if data.kind_of? Array
491
+ data,from = data
492
+ else
493
+ from = [0,0,"0.0.0.0","unknown"]
494
+ end
495
+ end
496
+
497
+ @answerfrom = from[2] + ":" + from[1].to_s
498
+ @answersize = data.size
499
+ @logger = Logger.new $stdout
500
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
501
+
502
+ #------------------------------------------------------------
503
+ # Header section
504
+ #------------------------------------------------------------
505
+ offset = Net::DNS::HFIXEDSZ
506
+ @header = Net::DNS::Header.parse(data[0..offset-1])
507
+
508
+ @logger.debug ";; HEADER SECTION"
509
+ @logger.debug @header.inspect
510
+
511
+ #------------------------------------------------------------
512
+ # Question section
513
+ #------------------------------------------------------------
514
+ section = @header.opCode == "UPDATE" ? "ZONE" : "QUESTION"
515
+ @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
516
+
517
+ @question = []
518
+ @header.qdCount.times do
519
+ qobj,offset = parse_question(data,offset)
520
+ @question << qobj
521
+ @logger.debug ";; #{qobj.inspect}"
522
+ end
523
+
524
+ #------------------------------------------------------------
525
+ # Answer/prerequisite section
526
+ #------------------------------------------------------------
527
+ section = @header.opCode == "UPDATE" ? "PREREQUISITE" : "ANSWER"
528
+ @logger.debug ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '': 's'})"
529
+
530
+ @answer = []
531
+ @header.anCount.times do
532
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
533
+ @answer << rrobj
534
+ @logger.debug rrobj.inspect
535
+ end
536
+
537
+ #------------------------------------------------------------
538
+ # Authority/update section
539
+ #------------------------------------------------------------
540
+ section = @header.opCode == "UPDATE" ? "UPDATE" : "AUTHORITY"
541
+ @logger.debug ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '': 's'})"
542
+
543
+ @authority = []
544
+ @header.nsCount.times do
545
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
546
+ @authority << rrobj
547
+ @logger.debug rrobj.inspect
548
+ end
549
+
550
+ #------------------------------------------------------------
551
+ # Additional section
552
+ #------------------------------------------------------------
553
+ @logger.debug ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '': 's'})"
554
+
555
+ @additional = []
556
+ @header.arCount.times do
557
+ rrobj,offset = Net::DNS::RR.parse_packet(data,offset)
558
+ @additional << rrobj
559
+ @logger.debug rrobj.inspect
560
+ end
561
+
562
+ end # new_from_data
563
+
564
+
565
+ # Parse question section
566
+ def parse_question(data,offset)
567
+ size = (dn_expand(data,offset)[1]-offset) + 2*Net::DNS::INT16SZ
568
+ return [Net::DNS::Question.parse(data[offset,size]), offset+size]
569
+ rescue StandardError => err
570
+ raise PacketError, "Caught exception, maybe packet malformed => #{err}"
571
+ end
572
+
573
+ end # class Packet
574
+
575
+ end # module DNS
576
+ end # module Net
577
+
578
+ class PacketError < StandardError # :nodoc:
579
+ end
580
+ class PacketArgumentError < ArgumentError # :nodoc:
581
+ end