net-dns2 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +20 -0
  4. data/CHANGELOG.md +105 -0
  5. data/Gemfile +4 -0
  6. data/README.md +155 -0
  7. data/Rakefile +94 -0
  8. data/THANKS.rdoc +24 -0
  9. data/demo/check_soa.rb +115 -0
  10. data/demo/threads.rb +22 -0
  11. data/lib/net/dns.rb +112 -0
  12. data/lib/net/dns/core_ext.rb +52 -0
  13. data/lib/net/dns/header.rb +713 -0
  14. data/lib/net/dns/names.rb +118 -0
  15. data/lib/net/dns/packet.rb +563 -0
  16. data/lib/net/dns/question.rb +188 -0
  17. data/lib/net/dns/resolver.rb +1313 -0
  18. data/lib/net/dns/resolver/socks.rb +154 -0
  19. data/lib/net/dns/resolver/timeouts.rb +75 -0
  20. data/lib/net/dns/rr.rb +366 -0
  21. data/lib/net/dns/rr/a.rb +124 -0
  22. data/lib/net/dns/rr/aaaa.rb +103 -0
  23. data/lib/net/dns/rr/classes.rb +133 -0
  24. data/lib/net/dns/rr/cname.rb +82 -0
  25. data/lib/net/dns/rr/hinfo.rb +108 -0
  26. data/lib/net/dns/rr/mr.rb +79 -0
  27. data/lib/net/dns/rr/mx.rb +92 -0
  28. data/lib/net/dns/rr/ns.rb +78 -0
  29. data/lib/net/dns/rr/null.rb +53 -0
  30. data/lib/net/dns/rr/ptr.rb +83 -0
  31. data/lib/net/dns/rr/soa.rb +78 -0
  32. data/lib/net/dns/rr/srv.rb +45 -0
  33. data/lib/net/dns/rr/txt.rb +61 -0
  34. data/lib/net/dns/rr/types.rb +193 -0
  35. data/lib/net/dns/version.rb +16 -0
  36. data/net-dns.gemspec +37 -0
  37. data/test/header_test.rb +167 -0
  38. data/test/names_test.rb +21 -0
  39. data/test/packet_test.rb +49 -0
  40. data/test/question_test.rb +83 -0
  41. data/test/resolver_test.rb +117 -0
  42. data/test/rr/a_test.rb +113 -0
  43. data/test/rr/aaaa_test.rb +109 -0
  44. data/test/rr/classes_test.rb +85 -0
  45. data/test/rr/cname_test.rb +97 -0
  46. data/test/rr/hinfo_test.rb +117 -0
  47. data/test/rr/mr_test.rb +105 -0
  48. data/test/rr/mx_test.rb +112 -0
  49. data/test/rr/ns_test.rb +86 -0
  50. data/test/rr/types_test.rb +69 -0
  51. data/test/rr_test.rb +131 -0
  52. data/test/test_helper.rb +4 -0
  53. metadata +158 -0
@@ -0,0 +1,22 @@
1
+ require 'rubygems' if "#{RUBY_VERSION}" < "1.9.0"
2
+ require 'net/dns'
3
+
4
+ a = ["ibm.com", "sun.com", "redhat.com"]
5
+
6
+ threads = []
7
+
8
+ for dom in a
9
+ threads << Thread.new(dom) do |domain|
10
+ res = Net::DNS::Resolver.new
11
+ res.query(domain, Net::DNS::NS).each_nameserver do |ns|
12
+ puts "Domain #{domain} has nameserver #{ns}"
13
+ end
14
+ puts ""
15
+ end
16
+ end
17
+
18
+ threads.each do |t|
19
+ t.join
20
+ end
21
+
22
+
@@ -0,0 +1,112 @@
1
+ require 'net/dns/core_ext'
2
+ require 'net/dns/version'
3
+ require 'net/dns/resolver'
4
+
5
+ module Net
6
+ module DNS
7
+
8
+ # Packet size in bytes
9
+ PACKETSZ = 512
10
+
11
+ # Size of the header
12
+ HFIXEDSZ = 12
13
+
14
+ # Size of the question portion (type and class)
15
+ QFIXEDSZ = 4
16
+
17
+ # Size of an RR portion (type,class,lenght and ttl)
18
+ RRFIXEDSZ = 10
19
+
20
+ # Size of an int 32 bit
21
+ INT32SZ = 4
22
+
23
+ # Size of a short int
24
+ INT16SZ = 2
25
+
26
+
27
+ module QueryTypes
28
+
29
+ SIGZERO = 0
30
+ A = 1
31
+ NS = 2
32
+ MD = 3
33
+ MF = 4
34
+ CNAME = 5
35
+ SOA = 6
36
+ MB = 7
37
+ MG = 8
38
+ MR = 9
39
+ NULL = 10
40
+ WKS = 11
41
+ PTR = 12
42
+ HINFO = 13
43
+ MINFO = 14
44
+ MX = 15
45
+ TXT = 16
46
+ RP = 17
47
+ AFSDB = 18
48
+ X25 = 19
49
+ ISDN = 20
50
+ RT = 21
51
+ NSAP = 22
52
+ NSAPPTR = 23
53
+ SIG = 24
54
+ KEY = 25
55
+ PX = 26
56
+ GPOS = 27
57
+ AAAA = 28
58
+ LOC = 29
59
+ NXT = 30
60
+ EID = 31
61
+ NIMLOC = 32
62
+ SRV = 33
63
+ ATMA = 34
64
+ NAPTR = 35
65
+ KX = 36
66
+ CERT = 37
67
+ DNAME = 39
68
+ OPT = 41
69
+ DS = 43
70
+ SSHFP = 44
71
+ RRSIG = 46
72
+ NSEC = 47
73
+ DNSKEY = 48
74
+ UINFO = 100
75
+ UID = 101
76
+ GID = 102
77
+ UNSPEC = 103
78
+ TKEY = 249
79
+ TSIG = 250
80
+ IXFR = 251
81
+ AXFR = 252
82
+ MAILB = 253
83
+ MAILA = 254
84
+ ANY = 255
85
+
86
+ end
87
+
88
+ module QueryClasses
89
+
90
+ # Internet class
91
+ IN = 1
92
+
93
+ # Chaos class
94
+ CH = 3
95
+
96
+ # Hesiod class
97
+ HS = 4
98
+
99
+ # None class
100
+ NONE = 254
101
+
102
+ # Any class
103
+ ANY = 255
104
+
105
+ end
106
+
107
+ include QueryTypes
108
+ include QueryClasses
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,52 @@
1
+ module Net # :nodoc:
2
+ module DNS
3
+
4
+ module HashKeys # :nodoc:
5
+
6
+ # Returns an hash with all the
7
+ # keys turned into downcase
8
+ #
9
+ # hsh = {"Test" => 1, "FooBar" => 2}
10
+ # hsh.downcase_keys!
11
+ # #=> {"test"=>1,"foobar"=>2}
12
+ #
13
+ def downcase_keys!
14
+ hsh = Hash.new
15
+ self.each do |key,val|
16
+ hsh[key.downcase] = val
17
+ end
18
+ self.replace(hsh)
19
+ end
20
+
21
+ end
22
+
23
+ module HashOperators # :nodoc:
24
+
25
+ # Performs a sort of group difference
26
+ # operation on hashes or arrays
27
+ #
28
+ # a = {:a=>1,:b=>2,:c=>3}
29
+ # b = {:a=>1,:b=>2}
30
+ # c = [:a,:c]
31
+ # a-b #=> {:c=>3}
32
+ # a-c #=> {:b=>2}
33
+ #
34
+ def -(other)
35
+ case other
36
+ when Hash
37
+ delete_if { |k,v| other.has_key?(k) }
38
+ when Array
39
+ delete_if { |k,v| other.include?(k) }
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+
48
+
49
+ class Hash # :nodoc:
50
+ include Net::DNS::HashKeys
51
+ include Net::DNS::HashOperators
52
+ end
@@ -0,0 +1,713 @@
1
+ module Net
2
+ module DNS
3
+
4
+ # DNS packet header class
5
+ #
6
+ # The Net::DNS::Header class represents the header portion of a
7
+ # DNS packet. An Header object is created whenever a new packet
8
+ # is parsed or as user request.
9
+ #
10
+ # header = Net::DNS::Header.new
11
+ # # ;; id = 18123
12
+ # # ;; qr = 0 opCode: 0 aa = 0 tc = 0 rd = 1
13
+ # # ;; ra = 0 ad = 0 cd = 0 rcode = 0
14
+ # # ;; qdCount = 1 anCount = 0 nsCount = 0 arCount = 0
15
+ #
16
+ # header.format
17
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # # | 18123 |
19
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20
+ # # |0| 0 |0|0|1|0|0| 0 | 0 |
21
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
+ # # | 1 |
23
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24
+ # # | 0 |
25
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26
+ # # | 0 |
27
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ # # | 0 |
29
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30
+ #
31
+ # # packet is an instance of Net::DNS::Packet
32
+ # header = packet.header
33
+ # puts "Answer is #{header.auth? ? '' : 'non'} authoritative"
34
+ #
35
+ # A lot of methods were written to keep a compatibility layer with
36
+ # the Perl version of the library, as long as methods name which are
37
+ # more or less the same.
38
+ #
39
+ class Header
40
+
41
+ # A wrong +count+ parameter has been passed.
42
+ class WrongCountError < ArgumentError
43
+ end
44
+
45
+ # A wrong +recursive+ parameter has been passed.
46
+ class WrongRecursiveError < ArgumentError
47
+ end
48
+
49
+ # An invalid +opCode+ has been specified.
50
+ class WrongOpcodeError < ArgumentError
51
+ end
52
+
53
+ # Base error class.
54
+ class Error < StandardError
55
+ end
56
+
57
+
58
+ # DNS Header RCode handling class
59
+ #
60
+ # It should be used internally by Net::DNS::Header class. However, it's still
61
+ # possible to instantiate it directly.
62
+ #
63
+ # require 'net/dns/header'
64
+ # rcode = Net::DNS::Header::RCode.new 0
65
+ #
66
+ # The RCode class represents the RCode field in the Header portion of a
67
+ # DNS packet. This field (called Response Code) is used to get informations
68
+ # about the status of a DNS operation, such as a query or an update. These
69
+ # are the values in the original Mockapetris's standard (RFC1035):
70
+ #
71
+ # * 0 No error condition
72
+ # * 1 Format error - The name server was unable to interpret
73
+ # the query.
74
+ # * 2 Server failure - The name server was
75
+ # unable to process this query due to a
76
+ # problem with the name server.
77
+ # * 3 Name Error - Meaningful only for
78
+ # responses from an authoritative name
79
+ # server, this code means that the
80
+ # domain name referenced in the query does
81
+ # not exist.
82
+ # * 4 Not Implemented - The name server does
83
+ # not support the requested kind of query.
84
+ # * 5 Refused - The name server refuses to
85
+ # perform the specified operation for
86
+ # policy reasons. For example, a name
87
+ # server may not wish to provide the
88
+ # information to the particular requester,
89
+ # or a name server may not wish to perform
90
+ # a particular operation (e.g., zone
91
+ # transfer) for particular data.
92
+ # * 6-15 Reserved for future use.
93
+ #
94
+ # In the next DNS RFCs, codes 6-15 has been assigned to the following
95
+ # errors:
96
+ #
97
+ # * 6 YXDomain
98
+ # * 7 YXRRSet
99
+ # * 8 NXRRSet
100
+ # * 9 NotAuth
101
+ # * 10 NotZone
102
+ #
103
+ # More RCodes has to come for TSIGs and other operations.
104
+ #
105
+ class RCode
106
+
107
+ # Constant for +rcode+ Response Code No Error
108
+ NOERROR = 0
109
+ # Constant for +rcode+ Response Code Format Error
110
+ FORMAT = 1
111
+ # Constant for +rcode+ Response Code Server Format Error
112
+ SERVER = 2
113
+ # Constant for +rcode+ Response Code Name Error
114
+ NAME = 3
115
+ # Constant for +rcode+ Response Code Not Implemented Error
116
+ NOTIMPLEMENTED = 4
117
+ # Constant for +rcode+ Response Code Refused Error
118
+ REFUSED = 5
119
+
120
+
121
+
122
+ RCodeType = %w[NoError FormErr ServFail NXDomain NotImp
123
+ Refused YXDomain YXRRSet NXRRSet NotAuth NotZone]
124
+
125
+ RCodeErrorString = ["No errors",
126
+ "The name server was unable to interpret the query",
127
+ "The name server was unable to process this query due to problem with the name server",
128
+ "Domain name referenced in the query does not exists",
129
+ "The name server does not support the requested kind of query",
130
+ "The name server refuses to perform the specified operation for policy reasons",
131
+ "",
132
+ "",
133
+ "",
134
+ "",
135
+ ""]
136
+
137
+ attr_reader :code, :type, :explanation
138
+
139
+ def initialize(code)
140
+ if (0..10).include? code
141
+ @code = code
142
+ @type = RCodeType[code]
143
+ @explanation = RCodeErrorString[code]
144
+ else
145
+ raise ArgumentError, "RCode `#{code}' out of range"
146
+ end
147
+ end
148
+
149
+ def to_s
150
+ @code.to_s
151
+ end
152
+ end
153
+
154
+
155
+ # Constant for +opCode+ query
156
+ QUERY = 0
157
+ # Constant for +opCode+ iquery
158
+ IQUERY = 1
159
+ # Constant for +opCode+ status
160
+ STATUS = 2
161
+ # Array with given strings
162
+ OPARR = %w[QUERY IQUERY STATUS]
163
+
164
+ # Reader for +id+ attribute
165
+ attr_reader :id
166
+ # Reader for the operational code
167
+ attr_reader :opCode
168
+ # Reader for the rCode instance
169
+ attr_reader :rCode
170
+ # Reader for question section entries number
171
+ attr_reader :qdCount
172
+ # Reader for answer section entries number
173
+ attr_reader :anCount
174
+ # Reader for authority section entries number
175
+ attr_reader :nsCount
176
+ # Reader for addictional section entries number
177
+ attr_reader :arCount
178
+
179
+ # Creates a new Net::DNS::Header object with the desired values,
180
+ # which can be specified as an Hash argument. When called without
181
+ # arguments, defaults are used. If a data string is passed, values
182
+ # are taken from parsing the string.
183
+ #
184
+ # Examples:
185
+ #
186
+ # # Create a new Net::DNS::Header object
187
+ # header = Net::DNS::Header.new
188
+ #
189
+ # # Create a new Net::DNS::Header object passing values
190
+ # header = Net::DNS::Header.new(:opCode => 1, :rd => 0)
191
+ #
192
+ # # Create a new Net::DNS::Header object with binary data
193
+ # header = Net::DNS::Header.new(data)
194
+ #
195
+ # Default values are:
196
+ #
197
+ # :id => auto generated
198
+ # :qr => 0 # Query response flag
199
+ # :aa => 0 # Authoritative answer flag
200
+ # :tc => 0 # Truncated packet flag
201
+ # :ra => 0 # Recursiond available flag
202
+ # :rCode => 0 # Response code (status of the query)
203
+ # :opCode => 0 # Operational code (purpose of the query)
204
+ # :cd => 0 # Checking disable flag
205
+ # :ad => 0 # Only relevant in DNSSEC context
206
+ # :rd => 1 # Recursion desired flag
207
+ # :qdCount => 1 # Number of questions in the dns packet
208
+ # :anCount => 0 # Number of answer RRs in the dns packet
209
+ # :nsCount => 0 # Number of authoritative RRs in the dns packet
210
+ # :arCount => 0 # Number of additional RRs in the dns packet
211
+ #
212
+ # See also each option for a detailed explanation of usage.
213
+ #
214
+ def initialize(arg = {})
215
+ if arg.kind_of? Hash
216
+ new_from_hash(arg)
217
+ else
218
+ raise ArgumentError, "Wrong argument class `#{arg.class}'"
219
+ end
220
+ end
221
+
222
+ # Creates a new Net::DNS::Header object from binary data, which is
223
+ # passed as a string object as argument.
224
+ # The configurations parameters are taken from parsing the string.
225
+ #
226
+ # Example:
227
+ #
228
+ # # Create a new Net::DNS::Header object with binary data
229
+ # header = Net::DNS::Header.new(data)
230
+ #
231
+ # header.auth?
232
+ # #=> "true" if it comes from authoritative name server
233
+ #
234
+ def self.parse(arg)
235
+ if arg.kind_of? String
236
+ o = allocate
237
+ o.send(:new_from_binary, arg)
238
+ o
239
+ else
240
+ raise ArgumentError, "Wrong argument class `#{arg.class}'"
241
+ end
242
+ end
243
+
244
+ # Inspect method, prints out all the options and relative values.
245
+ #
246
+ # p Net::DNS::Header.new
247
+ # # ;; id = 18123
248
+ # # ;; qr = 0 opCode: 0 aa = 0 tc = 0 rd = 1
249
+ # # ;; ra = 0 ad = 0 cd = 0 rcode = 0
250
+ # # ;; qdCount = 1 anCount = 0 nsCount = 0 arCount = 0
251
+ #
252
+ # This method will maybe be changed in the future to a more pretty
253
+ # way of display output.
254
+ #
255
+ def inspect
256
+ ";; id = #@id\n" +
257
+ if false # @opCode == "UPDATE"
258
+ #do stuff
259
+ else
260
+ ";; qr = #@qr\t" +
261
+ "opCode: #{opCode_str}\t" +
262
+ "aa = #@aa\t" +
263
+ "tc = #@tc\t" +
264
+ "rd = #@rd\n" +
265
+ ";; ra = #@ra\t" +
266
+ "ad = #@ad\t" +
267
+ "cd = #@cd\t" +
268
+ "rcode = #{@rCode.type}\n" +
269
+ ";; qdCount = #@qdCount\t"+
270
+ "anCount = #@anCount\t"+
271
+ "nsCount = #@nsCount\t"+
272
+ "arCount = #@arCount\n"
273
+ end
274
+ end
275
+
276
+ # The Net::DNS::Header#format method prints out the header
277
+ # in a special ascii representation of data, in a way
278
+ # similar to those often found on RFCs.
279
+ #
280
+ # p Net::DNS::Header.new.format
281
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
282
+ # # | 18123 |
283
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284
+ # # |0| 0 |0|0|1|0|0| 0 | 0 |
285
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
286
+ # # | 1 |
287
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
288
+ # # | 0 |
289
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290
+ # # | 0 |
291
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
292
+ # # | 0 |
293
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294
+ #
295
+ # This can be very usefull for didactical purpouses :)
296
+ #
297
+ def format
298
+ del = ("+-" * 16) + "+\n"
299
+ len = del.length
300
+ str = del + "|" + @id.to_s.center(len-3) + "|\n"
301
+ str += del + "|" + @qr.to_s
302
+ str += "|" + @opCode.to_s.center(7)
303
+ str += "|" + @aa.to_s
304
+ str += "|" + @tc.to_s
305
+ str += "|" + @rd.to_s
306
+ str += "|" + @ra.to_s
307
+ str += "|" + @ad.to_s
308
+ str += "|" + @cd.to_s.center(3)
309
+ str += "|" + @rCode.to_s.center(7) + "|\n"
310
+ str += del + "|" + @qdCount.to_s.center(len-3) + "|\n"
311
+ str += del + "|" + @anCount.to_s.center(len-3) + "|\n"
312
+ str += del + "|" + @nsCount.to_s.center(len-3) + "|\n"
313
+ str += del + "|" + @arCount.to_s.center(len-3) + "|\n" + del
314
+ str
315
+ end
316
+
317
+ # Returns the header data in binary format, appropriate
318
+ # for use in a DNS query packet.
319
+ #
320
+ # hdata = header.data
321
+ # puts "Header is #{hdata.size} bytes"
322
+ #
323
+ def data
324
+ arr = []
325
+ arr.push(@id)
326
+ arr.push((@qr<<7)|(@opCode<<3)|(@aa<<2)|(@tc<<1)|@rd)
327
+ arr.push((@ra<<7)|(@ad<<5)|(@cd<<4)|@rCode.code)
328
+ arr.push(@qdCount)
329
+ arr.push(@anCount)
330
+ arr.push(@nsCount)
331
+ arr.push(@arCount)
332
+ arr.pack("n C2 n4")
333
+ end
334
+
335
+ # Set the ID for the current header. Useful when
336
+ # performing security tests.
337
+ #
338
+ def id=(val)
339
+ if (0..65535).include? val
340
+ @id = val
341
+ else
342
+ raise ArgumentError, "ID `#{val}' out of range"
343
+ end
344
+ end
345
+
346
+ # Checks whether the header is a query (+qr+ bit set to 0)
347
+ #
348
+ def query?
349
+ @qr == 0
350
+ end
351
+
352
+ # Set the +qr+ query response flag to be either +true+ or
353
+ # +false+. You can also use the values 0 and 1. This flag
354
+ # indicates if the DNS packet contains a query or an answer,
355
+ # so it should be set to +true+ in DNS answer packets.
356
+ # If +qr+ is +true+, the packet is a response.
357
+ #
358
+ def qr=(val)
359
+ case val
360
+ when true
361
+ @qr = 1
362
+ when false
363
+ @qr = 0
364
+ when 0,1
365
+ @qr = val
366
+ else
367
+ raise ArgumentError, ":qr must be true(or 1) or false(or 0)"
368
+ end
369
+ end
370
+
371
+ # Checks whether the header is a response
372
+ # (+qr+ bit set to 1)
373
+ #
374
+ def response?
375
+ @qr == 1
376
+ end
377
+
378
+ # Returns a string representation of the +opCode+
379
+ #
380
+ # puts "Packet is a #{header.opCode_str}"
381
+ # #=> Packet is a QUERY
382
+ #
383
+ def opCode_str
384
+ OPARR[@opCode]
385
+ end
386
+
387
+ # Set the +opCode+ variable to a new value. This fields indicates
388
+ # the type of the question present in the DNS packet; +val+ can be
389
+ # one of the values QUERY, IQUERY or STATUS.
390
+ #
391
+ # * QUERY is the standard DNS query
392
+ # * IQUERY is the inverse query
393
+ # * STATUS is used to query the nameserver for its status
394
+ #
395
+ # Example:
396
+ #
397
+ # include Net::DNS
398
+ # header = Header.new
399
+ # header.opCode = Header::STATUS
400
+ #
401
+ def opCode=(val)
402
+ if (0..2).include? val
403
+ @opCode = val
404
+ else
405
+ raise WrongOpcodeError, "Wrong opCode value (#{val}), must be QUERY, IQUERY or STATUS"
406
+ end
407
+ end
408
+
409
+ # Checks whether the response is authoritative
410
+ #
411
+ # if header.auth?
412
+ # puts "Response is authoritative"
413
+ # else
414
+ # puts "Answer is NOT authoritative"
415
+ # end
416
+ #
417
+ def auth?
418
+ @aa == 1
419
+ end
420
+
421
+ # Set the +aa+ flag (authoritative answer) to either +true+
422
+ # or +false+. You can also use 0 or 1.
423
+ #
424
+ # This flag indicates whether a DNS answer packet contains
425
+ # authoritative data, meaning that is was generated by a
426
+ # nameserver authoritative for the domain of the question.
427
+ #
428
+ # Must only be set to +true+ in DNS answer packets.
429
+ #
430
+ def aa=(val)
431
+ case val
432
+ when true
433
+ @aa = 1
434
+ when false
435
+ @aa = 0
436
+ when 0,1
437
+ @aa = val
438
+ else
439
+ raise ArgumentError, ":aa must be true(or 1) or false(or 0)"
440
+ end
441
+ end
442
+
443
+ # Checks whether the packet was truncated
444
+ #
445
+ # # Sending packet using UDP
446
+ # if header.truncated?
447
+ # puts "Warning, packet has been truncated!"
448
+ # # Sending packet using TCP
449
+ # end
450
+ # # Do something with the answer
451
+ #
452
+ def truncated?
453
+ @tc == 1
454
+ end
455
+
456
+ # Set the +tc+ flag (truncated packet) to either +true+
457
+ # ot +false+. You can also use 0 or 1.
458
+ #
459
+ # The truncated flag is used in response packets to indicate
460
+ # that the amount of data to be trasmitted exceedes the
461
+ # maximum allowed by the protocol in use, tipically UDP, and
462
+ # that the data present in the packet has been truncated.
463
+ # A different protocol (such has TCP) need to be used to
464
+ # retrieve full data.
465
+ #
466
+ # Must only be set in DNS answer packets.
467
+ #
468
+ def tc=(val)
469
+ case val
470
+ when true
471
+ @tc = 1
472
+ when false
473
+ @tc = 0
474
+ when 0,1
475
+ @tc = val
476
+ else
477
+ raise ArgumentError, ":tc must be true(or 1) or false(or 0)"
478
+ end
479
+ end
480
+
481
+ # Checks whether the packet has a recursion bit
482
+ # set, meaning that recursion is desired
483
+ #
484
+ def recursive?
485
+ @rd == 1
486
+ end
487
+
488
+ # Sets the recursion desidered bit.
489
+ # Remember that recursion query support is
490
+ # optional.
491
+ #
492
+ # header.recursive = true
493
+ # hdata = header.data # suitable for sending
494
+ #
495
+ # Consult RFC1034 and RFC1035 for a detailed explanation
496
+ # of how recursion works.
497
+ #
498
+ def recursive=(val)
499
+ case val
500
+ when true
501
+ @rd = 1
502
+ when false
503
+ @rd = 0
504
+ when 1
505
+ @rd = 1
506
+ when 0
507
+ @rd = 0
508
+ else
509
+ raise WrongRecursiveError, "Wrong value (#{val}), please specify true (1) or false (0)"
510
+ end
511
+ end
512
+
513
+ # Alias for Header#recursive= to keep compatibility
514
+ # with the Perl version.
515
+ #
516
+ def rd=(val)
517
+ self.recursive = val
518
+ end
519
+
520
+ # Checks whether recursion is available.
521
+ # This flag is usually set by nameservers to indicate
522
+ # that they support recursive-type queries.
523
+ #
524
+ def r_available?
525
+ @ra == 1
526
+ end
527
+
528
+ # Set the +ra+ flag (recursion available) to either +true+ or
529
+ # +false+. You can also use 0 and 1.
530
+ #
531
+ # This flag must only be set in DNS answer packets.
532
+ #
533
+ def ra=(val)
534
+ case val
535
+ when true
536
+ @ra = 1
537
+ when false
538
+ @ra = 0
539
+ when 0,1
540
+ @ra = val
541
+ else
542
+ raise ArgumentError, ":ra must be true(or 1) or false(or 0)"
543
+ end
544
+ end
545
+
546
+ # Checks whether checking is enabled or disabled.
547
+ #
548
+ # Checking is enabled by default.
549
+ #
550
+ def checking?
551
+ @cd == 0
552
+ end
553
+
554
+ # Set the +cd+ flag (checking disabled) to either +true+
555
+ # ot +false+. You can also use 0 or 1.
556
+ #
557
+ def cd=(val)
558
+ case val
559
+ when true
560
+ @cd = 1
561
+ when false
562
+ @cd = 0
563
+ when 0,1
564
+ @cd = val
565
+ else
566
+ raise ArgumentError, ":cd must be true(or 1) or false(or 0)"
567
+ end
568
+ end
569
+
570
+ # Checks whether +ad+ flag has been set.
571
+ #
572
+ # This flag is only relevant in DNSSEC context.
573
+ #
574
+ def verified?
575
+ @ad == 1
576
+ end
577
+
578
+ # Set the +ad+ flag to either +true+
579
+ # ot +false+. You can also use 0 or 1.
580
+ #
581
+ # The AD bit is only set on answers where signatures have
582
+ # been cryptographically verified or the server is
583
+ # authoritative for the data and is allowed to set the bit by policy.
584
+ #
585
+ def ad=(val)
586
+ case val
587
+ when true
588
+ @ad = 1
589
+ when false
590
+ @ad = 0
591
+ when 0,1
592
+ @ad = val
593
+ else
594
+ raise ArgumentError, ":ad must be true(or 1) or false(or 0)"
595
+ end
596
+ end
597
+
598
+ # Returns an error array for the header response code, or
599
+ # +nil+ if no error is generated.
600
+ #
601
+ # error, cause = header.rCode_str
602
+ # puts "Error #{error} cause by: #{cause}" if error
603
+ # #=> Error ForErr caused by: The name server
604
+ # #=> was unable to interpret the query
605
+ #
606
+ def rCode_str
607
+ return rCode.type, rCode.explanation
608
+ end
609
+
610
+ # Checks for errors in the DNS packet
611
+ #
612
+ # unless header.error?
613
+ # puts "No errors in DNS answer packet"
614
+ # end
615
+ #
616
+ def error?
617
+ @rCode.code > 0
618
+ end
619
+
620
+ # Set the rCode value. This should only be done in DNS
621
+ # answer packets.
622
+ #
623
+ def rCode=(val)
624
+ @rCode = RCode.new(val)
625
+ end
626
+
627
+ # Sets the number of entries in a question section
628
+ #
629
+ def qdCount=(val)
630
+ if (0..65535).include? val
631
+ @qdCount = val
632
+ else
633
+ raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
634
+ end
635
+ end
636
+
637
+ # Sets the number of RRs in an answer section
638
+ #
639
+ def anCount=(val)
640
+ if (0..65535).include? val
641
+ @anCount = val
642
+ else
643
+ raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
644
+ end
645
+ end
646
+
647
+ # Sets the number of RRs in an authority section
648
+ #
649
+ def nsCount=(val)
650
+ if (0..65535).include? val
651
+ @nsCount = val
652
+ else
653
+ raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
654
+ end
655
+ end
656
+
657
+ # Sets the number of RRs in an addictional section
658
+ #
659
+ def arCount=(val)
660
+ if (0..65535).include? val
661
+ @arCount = val
662
+ else
663
+ raise WrongCountError, "Wrong number of count: `#{val}' must be 0-65535"
664
+ end
665
+ end
666
+
667
+ private
668
+
669
+ def new_from_scratch
670
+ @id = genID # generate ad unique id
671
+ @qr = @aa = @tc = @ra = @ad = @cd = 0
672
+ @rCode = RCode.new(0) # no error
673
+ @anCount = @nsCount = @arCount = 0
674
+ @rd = @qdCount = 1
675
+ @opCode = QUERY # standard query, default message
676
+ end
677
+
678
+ def new_from_binary(str)
679
+ unless str.size == Net::DNS::HFIXEDSZ
680
+ raise ArgumentError, "Header binary data has wrong size: `#{str.size}' bytes"
681
+ end
682
+ arr = str.unpack("n C2 n4")
683
+ @id = arr[0]
684
+ @qr = (arr[1] >> 7) & 0x01
685
+ @opCode = (arr[1] >> 3) & 0x0F
686
+ @aa = (arr[1] >> 2) & 0x01
687
+ @tc = (arr[1] >> 1) & 0x01
688
+ @rd = arr[1] & 0x1
689
+ @ra = (arr[2] >> 7) & 0x01
690
+ @ad = (arr[2] >> 5) & 0x01
691
+ @cd = (arr[2] >> 4) & 0x01
692
+ @rCode = RCode.new(arr[2] & 0xf)
693
+ @qdCount = arr[3]
694
+ @anCount = arr[4]
695
+ @nsCount = arr[5]
696
+ @arCount = arr[6]
697
+ end
698
+
699
+ def new_from_hash(hash)
700
+ new_from_scratch
701
+ hash.each do |key,val|
702
+ eval "self.#{key.to_s} = val"
703
+ end
704
+ end
705
+
706
+ def genID
707
+ rand(65535)
708
+ end
709
+
710
+ end
711
+
712
+ end
713
+ end