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.
- data/.gitignore +8 -6
- data/.travis.yml +14 -0
- data/CHANGELOG.md +79 -0
- data/Gemfile +4 -0
- data/Rakefile +56 -66
- data/demo/check_soa.rb +1 -1
- data/demo/threads.rb +1 -1
- data/lib/net/dns.rb +24 -22
- data/lib/net/dns/header.rb +77 -103
- data/lib/net/dns/{names/names.rb → names.rb} +19 -20
- data/lib/net/dns/packet.rb +231 -256
- data/lib/net/dns/question.rb +11 -40
- data/lib/net/dns/resolver.rb +248 -250
- data/lib/net/dns/resolver/socks.rb +6 -6
- data/lib/net/dns/resolver/timeouts.rb +1 -1
- data/lib/net/dns/rr.rb +112 -117
- data/lib/net/dns/rr/a.rb +98 -89
- data/lib/net/dns/rr/aaaa.rb +84 -68
- data/lib/net/dns/rr/classes.rb +91 -106
- data/lib/net/dns/rr/cname.rb +64 -45
- data/lib/net/dns/rr/hinfo.rb +90 -50
- data/lib/net/dns/rr/mr.rb +61 -44
- data/lib/net/dns/rr/mx.rb +73 -48
- data/lib/net/dns/rr/ns.rb +60 -46
- data/lib/net/dns/rr/null.rb +11 -12
- data/lib/net/dns/rr/ptr.rb +47 -34
- data/lib/net/dns/rr/soa.rb +5 -6
- data/lib/net/dns/rr/srv.rb +1 -4
- data/lib/net/dns/rr/txt.rb +14 -14
- data/lib/net/dns/rr/types.rb +13 -13
- data/lib/net/dns/version.rb +8 -14
- data/net-dns.gemspec +35 -0
- data/setup.rb +3 -2
- data/test/header_test.rb +18 -18
- data/test/names_test.rb +21 -0
- data/test/packet_test.rb +38 -31
- data/test/question_test.rb +23 -24
- data/test/resolver/timeouts_test.rb +13 -13
- data/test/resolver_test.rb +28 -20
- data/test/rr/a_test.rb +70 -23
- data/test/rr/aaaa_test.rb +109 -0
- data/test/rr/classes_test.rb +61 -49
- data/test/rr/cname_test.rb +97 -0
- data/test/rr/hinfo_test.rb +117 -0
- data/test/rr/mr_test.rb +105 -0
- data/test/rr/mx_test.rb +112 -0
- data/test/rr/ns_test.rb +34 -12
- data/test/rr/types_test.rb +4 -4
- data/test/rr_test.rb +1 -1
- metadata +77 -52
- data/AUTHORS.rdoc +0 -7
- data/CHANGELOG.rdoc +0 -46
- 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
|
-
|
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 >
|
62
|
-
raise ArgumentError, "
|
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
|
data/lib/net/dns/packet.rb
CHANGED
@@ -1,36 +1,28 @@
|
|
1
1
|
require 'logger'
|
2
|
-
require 'net/dns/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
|
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
|
-
# =
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
-
#
|
127
|
-
# canonical name of the
|
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.
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
325
|
-
#
|
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
|
-
#
|
343
|
-
#
|
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
|
-
|
349
|
-
|
350
|
-
|
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, "
|
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
|
-
#
|
362
|
-
#
|
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
|
-
|
368
|
-
|
369
|
-
|
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, "
|
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
|
-
#
|
381
|
-
#
|
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
|
-
|
387
|
-
|
388
|
-
|
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, "
|
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
|
-
#
|
400
|
-
# Net::DNS::Packet
|
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
|
-
#
|
417
|
-
# Net::DNS::Packet
|
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
|
-
#
|
431
|
-
# of
|
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
|
-
#
|
445
|
-
# of
|
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
|
-
#
|
459
|
-
# Net::DNS::Packet
|
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
|
-
#
|
419
|
+
# # => 484 bytes
|
478
420
|
#
|
479
421
|
def size
|
480
422
|
data.size
|
481
423
|
end
|
482
424
|
|
483
|
-
# Checks whether
|
484
|
-
# meaning the domain name
|
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
|
-
#
|
491
|
-
#
|
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
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
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
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
@
|
546
|
-
|
547
|
-
|
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
|
-
#
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
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
|