net-dns2 0.8.1

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. 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