net-dns 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1,10 @@
1
+ # $Id: AUTHORS,v 1.2 2005/06/17 10:09:57 bluemonk Exp $
2
+
3
+
4
+ AUTHORS
5
+
6
+ Net::DNS core developement:
7
+ Marco Ceresa <ceresa@ieee.org>
8
+
9
+ Beta testing:
10
+
data/INSTALL ADDED
File without changes
data/README ADDED
@@ -0,0 +1,55 @@
1
+ Net::DNS README
2
+ ============
3
+
4
+ This is a port of the Perl Net::DNS module, written by Michael Fuhr
5
+ and now currently maintained by Olaf Kolkman (www.net-dns.org). It
6
+ keeps the same interfaces and function names, although has a bit
7
+ improved OO and some other stuff.
8
+ It can be used to query DNS servers for various kind of records, perform
9
+ zone transfer and dynamic updates. It has even a class for acting as a
10
+ nameserver.
11
+ This version is quite incomplete. You can use it as a resolver.
12
+
13
+
14
+ Requirements
15
+ ------------
16
+
17
+ * Ruby 1.6
18
+
19
+
20
+ Install
21
+ -------
22
+
23
+ De-compress archive and enter its top directory.
24
+ Then type:
25
+
26
+ ($ su)
27
+ # ruby setup.rb
28
+
29
+ These simple step installs this program under the default
30
+ location of Ruby libraries. You can also install files into
31
+ your favorite directory by supplying setup.rb some options.
32
+ Try "ruby setup.rb --help".
33
+
34
+
35
+ Usage
36
+ -----
37
+
38
+ Have a look on the manual pages.
39
+ In doc/ you will find many useful documents too.
40
+
41
+
42
+ License
43
+ -------
44
+
45
+ Net::DNS is distributed under the same license Ruby is.
46
+
47
+
48
+ Author
49
+ ------
50
+
51
+ See AUTHORS
52
+
53
+
54
+ # $Id: README,v 1.2 2005/06/17 15:11:18 bluemonk Exp $
55
+
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rake/clean'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/contrib/rubyforgepublisher'
5
+ require 'rake/gempackagetask'
6
+
7
+ require 'rubygems'
8
+
9
+ desc "Run the tests"
10
+ Rake::TestTask.new do |t|
11
+ t.libs << "test"
12
+ t.test_files = FileList['test/net/dns/**/test*.rb']
13
+ t.verbose = true
14
+ end
15
+
16
+ desc "Install the library"
17
+ task :install do
18
+ sh "sudo ruby setup.rb"
19
+ end
20
+
21
+ desc "Build documentation"
22
+ Rake::RDocTask.new do |rd|
23
+ rd.rdoc_files.include("lib/net/dns/**/*.rb")
24
+ rd.options << "-S"
25
+ end
26
+
27
+ #
28
+ # Gem specifications
29
+ #
30
+ SPEC = Gem::Specification.new do |s|
31
+ s.name = "net-dns"
32
+ s.version = "0.1"
33
+ s.author = "Marco Ceresa"
34
+ s.email = "ceresa@gmail.com"
35
+ s.homepage = "http://net-dns.rubyforge.org/"
36
+ s.platform = Gem::Platform::RUBY
37
+ s.summary = "Pure Ruby DNS library"
38
+ candidates = Dir.glob("**/*")
39
+ s.files = candidates.delete_if do |item|
40
+ item.include?("CVS") || item.include?("rdoc") || item.include?("pkg")
41
+ end
42
+ s.has_rdoc = true
43
+ s.extra_rdoc_files = ["README"]
44
+ s.description = <<EOF
45
+ A pure Ruby DNS library, similar to the Perl Net::DNS library
46
+ EOF
47
+ end
48
+
49
+ #
50
+ # Build packages
51
+ #
52
+ desc "Build packages"
53
+ Rake::GemPackageTask.new(SPEC) do |pkg|
54
+ pkg.need_zip = true
55
+ pkg.need_tar = true
56
+ end
57
+
58
+ #
59
+ # RubyForge publisher
60
+ #
61
+ desc "Upload project on RubyForge"
62
+ task :upload do
63
+ rubyforge = Rake::RubyForgePublisher.new("net-dns","bluemonk")
64
+ rubyforge.upload
65
+ end
data/THANKS ADDED
File without changes
data/demo/check_soa.rb ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: check_soa.rb,v 1.7 2006/07/30 16:53:57 bluemonk Exp $
4
+
5
+
6
+
7
+ require 'net/dns/resolver'
8
+
9
+ #------------------------------------------------------------------------------
10
+ # Get the domain from the command line.
11
+ #------------------------------------------------------------------------------
12
+
13
+ raise ArgumentError, "Usage: check_soa.rb domain\n" unless ARGV.size == 1
14
+
15
+ domain = ARGV[0]
16
+
17
+ #------------------------------------------------------------------------------
18
+ # Find all the nameservers for the domain.
19
+ #------------------------------------------------------------------------------
20
+
21
+ res = Net::DNS::Resolver.new(:defname => false, :retry => 2)
22
+
23
+ #res.defname=false
24
+ #res.retry=2
25
+
26
+
27
+ ns_req = res.query(domain, Net::DNS::NS);
28
+ raise ArgumentError, "No nameservers found for domain: " + res.errorstring +
29
+ "\n" unless ns_req and ns_req.header.anCount > 0
30
+
31
+
32
+ # Send out non-recursive queries
33
+ res.recurse=false
34
+ # Do not buffer standard out
35
+ #| = 1;
36
+
37
+
38
+ #------------------------------------------------------------------------------
39
+ # Check the SOA record on each nameserver.
40
+ #------------------------------------------------------------------------------
41
+
42
+ ns_req.each_nameserver do |ns|
43
+
44
+ #----------------------------------------------------------------------
45
+ # Set the resolver to query this nameserver.
46
+ #----------------------------------------------------------------------
47
+
48
+ # In order to lookup the IP(s) of the nameserver, we need a Resolver
49
+ # object that is set to our local, recursive nameserver. So we create
50
+ # a new object just to do that.
51
+
52
+ local_res = Net::DNS::Resolver.new
53
+
54
+ a_req = local_res.query(ns, Net::DNS::A)
55
+
56
+
57
+ unless a_req
58
+ puts "Can not find address for ns: " + res.errorstring + "\n"
59
+ next
60
+ end
61
+
62
+
63
+ a_req.each_address do |ip|
64
+
65
+ #----------------------------------------------------------------------
66
+ # Ask this IP.
67
+ #----------------------------------------------------------------------
68
+ res.nameservers=ip
69
+
70
+ print "#{ns} (#{ip}): "
71
+
72
+ #----------------------------------------------------------------------
73
+ # Get the SOA record.
74
+ #----------------------------------------------------------------------
75
+
76
+ soa_req = res.send(domain, Net::DNS::SOA, Net::DNS::IN)
77
+
78
+ if soa_req == nil
79
+ puts res.errorstring, "\n"
80
+ next
81
+ end
82
+
83
+ #----------------------------------------------------------------------
84
+ # Is this nameserver authoritative for the domain?
85
+ #----------------------------------------------------------------------
86
+
87
+ unless soa_req.header.auth?
88
+ print "isn't authoritative for domain\n"
89
+ next
90
+ end
91
+
92
+ #----------------------------------------------------------------------
93
+ # We should have received exactly one answer.
94
+ #----------------------------------------------------------------------
95
+
96
+ unless soa_req.header.anCount == 1
97
+ print "expected 1 answer, got " + soa_req.header.anCount.to_s + "\n"
98
+ next
99
+ end
100
+
101
+ #----------------------------------------------------------------------
102
+ # Did we receive an SOA record?
103
+ #----------------------------------------------------------------------
104
+
105
+ unless soa_req.answer[0].class == Net::DNS::RR::SOA
106
+ print "expected SOA, got " + Net::DNS::RR::RRTypes.to_str(soa_req.answer[0].type) + "\n"
107
+ next
108
+ end
109
+
110
+ #----------------------------------------------------------------------
111
+ # Print the serial number.
112
+ #----------------------------------------------------------------------
113
+
114
+ print "has serial number " + soa_req.answer[0].serial.to_s + "\n"
115
+
116
+ end
117
+ end
118
+
119
+
120
+
data/demo/threads.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'net/dns/resolver'
2
+
3
+ a = ["ibm.com", "sun.com", "redhat.com"]
4
+
5
+ threads = []
6
+
7
+ for dom in a
8
+ threads << Thread.new(dom) do |domain|
9
+ res = Net::DNS::Resolver.new
10
+ res.query(domain, Net::DNS::NS).each_nameserver do |ns|
11
+ puts "Domain #{domain} has nameserver #{ns}"
12
+ end
13
+ puts ""
14
+ end
15
+ end
16
+
17
+ threads.each do |t|
18
+ t.join
19
+ end
20
+
21
+
data/gemspec ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ SPEC = Gem::Specification.new do |s|
3
+ s.name = "net-dns"
4
+ s.version = "0.1"
5
+ s.author = "Marco Ceresa"
6
+ s.email = "ceresa@gmail.com"
7
+ s.homepage = "http://net-dns.rubyforge.org/"
8
+ s.platform = Gem::Platform::RUBY
9
+ s.summary = "Pure Ruby DNS library"
10
+ candidates = Dir.glob("{bin,docs,lib,tests}/**/*")
11
+ s.files = candidates.delete_if do |item|
12
+ item.include?("CVS") || item.include?("rdoc")
13
+ end
14
+ s.has_rdoc = true
15
+ s.extra_rdoc_files = ["README"]
16
+ end
@@ -0,0 +1,117 @@
1
+ ##
2
+ #
3
+ # dns.rb
4
+ #
5
+ # $id$
6
+ #
7
+ ##
8
+
9
+ module Net # :nodoc:
10
+ module DNS
11
+
12
+ # Version of the library
13
+ VERSION = 0.1
14
+
15
+ # Packet size in bytes
16
+ PACKETSZ = 512
17
+
18
+ # Size of the header
19
+ HFIXEDSZ = 12
20
+
21
+ # Size of the question portion (type and class)
22
+ QFIXEDSZ = 4
23
+
24
+ # Size of an RR portion (type,class,lenght and ttl)
25
+ RRFIXEDSZ = 10
26
+
27
+ # Size of an int 32 bit
28
+ INT32SZ = 4
29
+
30
+ # Size of a short int
31
+ INT16SZ = 2
32
+
33
+ module QueryTypes
34
+
35
+ SIGZERO = 0
36
+ A = 1
37
+ NS = 2
38
+ MD = 3
39
+ MF = 4
40
+ CNAME = 5
41
+ SOA = 6
42
+ MB = 7
43
+ MG = 8
44
+ MR = 9
45
+ NULL = 10
46
+ WKS = 11
47
+ PTR = 12
48
+ HINFO = 13
49
+ MINFO = 14
50
+ MX = 15
51
+ TXT = 16
52
+ RP = 17
53
+ AFSDB = 18
54
+ X25 = 19
55
+ ISDN = 20
56
+ RT = 21
57
+ NSAP = 22
58
+ NSAPPTR = 23
59
+ SIG = 24
60
+ KEY = 25
61
+ PX = 26
62
+ GPOS = 27
63
+ AAAA = 28
64
+ LOC = 29
65
+ NXT = 30
66
+ EID = 31
67
+ NIMLOC = 32
68
+ SRV = 33
69
+ ATMA = 34
70
+ NAPTR = 35
71
+ KX = 36
72
+ CERT = 37
73
+ DNAME = 39
74
+ OPT = 41
75
+ DS = 43
76
+ SSHFP = 44
77
+ RRSIG = 46
78
+ NSEC = 47
79
+ DNSKEY = 48
80
+ UINFO = 100
81
+ UID = 101
82
+ GID = 102
83
+ UNSPEC = 103
84
+ TKEY = 249
85
+ TSIG = 250
86
+ IXFR = 251
87
+ AXFR = 252
88
+ MAILB = 253
89
+ MAILA = 254
90
+ ANY = 255
91
+
92
+ end
93
+
94
+ module QueryClasses
95
+
96
+ # Internet class
97
+ IN = 1
98
+
99
+ # Chaos class
100
+ CH = 3
101
+
102
+ # Hesiod class
103
+ HS = 4
104
+
105
+ # None class
106
+ NONE = 254
107
+
108
+ # Any class
109
+ ANY = 255
110
+
111
+ end
112
+
113
+ include QueryTypes
114
+ include QueryClasses
115
+
116
+ end # module DNS
117
+ end # module Net
@@ -0,0 +1,692 @@
1
+ #---
2
+ # $Id: Header.rb,v 1.5 2006/07/30 16:54:28 bluemonk Exp $
3
+ #+++
4
+
5
+ require 'net/dns/dns'
6
+
7
+ module Net # :nodoc:
8
+ module DNS
9
+
10
+ #
11
+ # =Name
12
+ #
13
+ # Net::DNS::Header - DNS packet header class
14
+ #
15
+ # =Synopsis
16
+ #
17
+ # require 'net/dns/header'
18
+ #
19
+ # =Description
20
+ #
21
+ # The Net::DNS::Header class represents the header portion of a
22
+ # DNS packet. An Header object is created whenever a new packet
23
+ # is parsed or as user request.
24
+ #
25
+ # header = Net::DNS::Header.new
26
+ # # ;; id = 18123
27
+ # # ;; qr = 0 opCode: 0 aa = 0 tc = 0 rd = 1
28
+ # # ;; ra = 0 ad = 0 cd = 0 rcode = 0
29
+ # # ;; qdCount = 1 anCount = 0 nsCount = 0 arCount = 0
30
+ #
31
+ # header.format
32
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33
+ # # | 18123 |
34
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35
+ # # |0| 0 |0|0|1|0|0| 0 | 0 |
36
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37
+ # # | 1 |
38
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
+ # # | 0 |
40
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41
+ # # | 0 |
42
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43
+ # # | 0 |
44
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45
+ #
46
+ # # packet is an instance of Net::DNS::Packet
47
+ # header = packet.header
48
+ # puts "Answer is #{header.auth? ? '' : 'non'} authoritative"
49
+ #
50
+ # A lot of methods were written to keep a compatibility layer with
51
+ # the Perl version of the library, as long as methods name which are
52
+ # more or less the same.
53
+ #
54
+ # =Error classes
55
+ #
56
+ # Some error classes has been defined for the Net::DNS::Header class,
57
+ # which are listed here to keep a light and browsable main documentation.
58
+ # We have:
59
+ #
60
+ # * HeaderArgumentError: canonical argument error
61
+ # * HeaderWrongCount: a wrong +count+ parameter has been passed
62
+ # * HeaderWrongRecursive: a wrong +recursive+ parameter has been passed
63
+ # * HeaderWrongOpcode: a not valid +opCode+ has been specified
64
+ # * HeaderDuplicateID: the requested ID is already in use
65
+ #
66
+ # =Copyright
67
+ #
68
+ # Copyright (c) 2006 Marco Ceresa
69
+ #
70
+ # All rights reserved. This program is free software; you may redistribute
71
+ # it and/or modify it under the same terms as Ruby itself.
72
+ #
73
+ class Header
74
+
75
+ # Constant for +opCode+ query
76
+ QUERY = 0
77
+ # Constant for +opCode+ iquery
78
+ IQUERY = 1
79
+ # Constant for +opCode+ status
80
+ STATUS = 2
81
+ # Array with given strings
82
+ OPARR = %w[QUERY IQUERY STATUS]
83
+
84
+ # Constant for +rcode+ Response Code No Error
85
+ NOERROR = 0
86
+ # Constant for +rcode+ Response Code Format Error
87
+ FORMAT = 1
88
+ # Constant for +rcode+ Response Code Server Format Error
89
+ SERVER = 2
90
+ # Constant for +rcode+ Response Code Name Error
91
+ NAME = 3
92
+ # Constant for +rcode+ Response Code Not Implemented Error
93
+ NOTIMPLEMENTED = 4
94
+ # Constant for +rcode+ Response Code Refused Error
95
+ REFUSED = 5
96
+ # Array with given strings
97
+ CODEARR = %w[NOERROR FORMAT SERVER NAME NOTIMPLEMENTED REFUSED]
98
+
99
+ @@id_arr = []
100
+
101
+ # Reader for +id+ attribute
102
+ attr_reader :id
103
+ # Reader for the operational code
104
+ attr_reader :opCode
105
+ # Reader for question section entries number
106
+ attr_reader :qdCount
107
+ # Reader for answer section entries number
108
+ attr_reader :anCount
109
+ # Reader for authority section entries number
110
+ attr_reader :nsCount
111
+ # Reader for addictional section entries number
112
+ attr_reader :arCount
113
+
114
+ # Creates a new Net::DNS::Header object with the desired values,
115
+ # which can be specified as an Hash argument. When called without
116
+ # arguments, defaults are used. If a data string is passed, values
117
+ # are taken from parsing the string.
118
+ #
119
+ # Examples:
120
+ #
121
+ # # Create a new Net::DNS::Header object
122
+ # header = Net::DNS::Header.new
123
+ #
124
+ # # Create a new Net::DNS::Header object passing values
125
+ # header = Net::DNS::Header.new(:opCode => 1, :rd => 0)
126
+ #
127
+ # # Create a new Net::DNS::Header object with binary data
128
+ # header = Net::DNS::Header.new(data)
129
+ #
130
+ # Default values are:
131
+ #
132
+ # :id => auto generated
133
+ # :qr => 0 # Query response flag
134
+ # :aa => 0 # Authoritative answer flag
135
+ # :tc => 0 # Truncated packet flag
136
+ # :ra => 0 # Recursiond available flag
137
+ # :rCode => 0 # Response code (status of the query)
138
+ # :opCode => 0 # Operational code (purpose of the query)
139
+ # :cd => 0 # Checking disable flag
140
+ # :ad => 0 # Only relevant in DNSSEC context
141
+ # :rd => 1 # Recursion desired flag
142
+ # :qdCount => 1 # Number of questions in the dns packet
143
+ # :anCount => 0 # Number of answer RRs in the dns packet
144
+ # :nsCount => 0 # Number of authoritative RRs in the dns packet
145
+ # :arCount => 0 # Number of additional RRs in the dns packet
146
+ #
147
+ # See also each option for a detailed explanation of usage.
148
+ #
149
+ def initialize(arg = {})
150
+ if arg.kind_of? Hash
151
+ new_from_hash(arg)
152
+ else
153
+ raise HeaderArgumentError, "Wrong argument class: #{arg.class}"
154
+ end
155
+ end
156
+
157
+ # Creates a new Net::DNS::Header object from binary data, which is
158
+ # passed as a string object as argument.
159
+ # The configurations parameters are taken from parsing the string.
160
+ #
161
+ # Example:
162
+ #
163
+ # # Create a new Net::DNS::Header object with binary data
164
+ # header = Net::DNS::Header.new(data)
165
+ #
166
+ # header.auth?
167
+ # #=> "true" if it comes from authoritative name server
168
+ #
169
+ def self.parse(arg)
170
+ if arg.kind_of? String
171
+ o = allocate
172
+ o.send(:new_from_binary, arg)
173
+ o
174
+ else
175
+ raise HeaderArgumentError, "Wrong argument class: #{arg.class}"
176
+ end
177
+ end
178
+
179
+
180
+ # Inspect method, prints out all the options and relative values.
181
+ #
182
+ # p Net::DNS::Header.new
183
+ # # ;; id = 18123
184
+ # # ;; qr = 0 opCode: 0 aa = 0 tc = 0 rd = 1
185
+ # # ;; ra = 0 ad = 0 cd = 0 rcode = 0
186
+ # # ;; qdCount = 1 anCount = 0 nsCount = 0 arCount = 0
187
+ #
188
+ # This method will maybe be changed in the future to a more pretty
189
+ # way of display output.
190
+ #
191
+ def inspect
192
+ ";; id = #@id\n" +
193
+ if false # @opCode == "UPDATE"
194
+ #do stuff
195
+ else
196
+ ";; qr = #@qr\t" +
197
+ "opCode: #{opCode_str}\t" +
198
+ "aa = #@aa\t" +
199
+ "tc = #@tc\t" +
200
+ "rd = #@rd\n" +
201
+ ";; ra = #@ra\t" +
202
+ "ad = #@ad\t" +
203
+ "cd = #@cd\t" +
204
+ "rcode = #{rCode_str[0] || "NOERROR"}\n" +
205
+ ";; qdCount = #@qdCount\t"+
206
+ "anCount = #@anCount\t"+
207
+ "nsCount = #@nsCount\t"+
208
+ "arCount = #@arCount\n"
209
+ end
210
+ end
211
+
212
+ # The Net::DNS::Header#format method prints out the header
213
+ # in a special ascii representation of data, in a way
214
+ # similar to those often found on RFCs.
215
+ #
216
+ # p Net::DNS::Header.new.format
217
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
218
+ # # | 18123 |
219
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
220
+ # # |0| 0 |0|0|1|0|0| 0 | 0 |
221
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
222
+ # # | 1 |
223
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
224
+ # # | 0 |
225
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
226
+ # # | 0 |
227
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228
+ # # | 0 |
229
+ # # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230
+ #
231
+ # This can be very usefull for didactical purpouses :)
232
+ #
233
+ def format
234
+ del = ("+-" * 16) + "+\n"
235
+ len = del.length
236
+ str = del + "|" + @id.to_s.center(len-3) + "|\n"
237
+ str += del + "|" + @qr.to_s
238
+ str += "|" + @opCode.to_s.center(7)
239
+ str += "|" + @aa.to_s
240
+ str += "|" + @tc.to_s
241
+ str += "|" + @rd.to_s
242
+ str += "|" + @ra.to_s
243
+ str += "|" + @ad.to_s
244
+ str += "|" + @cd.to_s.center(3)
245
+ str += "|" + @rCode.to_s.center(7) + "|\n"
246
+ str += del + "|" + @qdCount.to_s.center(len-3) + "|\n"
247
+ str += del + "|" + @anCount.to_s.center(len-3) + "|\n"
248
+ str += del + "|" + @nsCount.to_s.center(len-3) + "|\n"
249
+ str += del + "|" + @arCount.to_s.center(len-3) + "|\n" + del
250
+ str
251
+ end
252
+
253
+ # Returns the header data in binary format, appropriate
254
+ # for use in a DNS query packet.
255
+ #
256
+ # hdata = header.data
257
+ # puts "Header is #{hdata.size} bytes"
258
+ #
259
+ def data
260
+ arr = []
261
+ arr.push(@id)
262
+ arr.push((@qr<<7)|(@opCode<<3)|(@aa<<2)|(@tc<<1)|@rd)
263
+ arr.push((@ra<<7)|(@ad<<5)|(@cd<<4)|@rCode)
264
+ arr.push(@qdCount)
265
+ arr.push(@anCount)
266
+ arr.push(@nsCount)
267
+ arr.push(@arCount)
268
+ arr.pack("n C2 n4")
269
+ end
270
+
271
+ # Set the ID for the current header. Useful when
272
+ # performing security tests.
273
+ #
274
+ def id=(val)
275
+ if @@id_arr.include? val
276
+ raise HeaderDuplicateID, "ID #{val} already used"
277
+ end
278
+ if (1..65535).include? val
279
+ @id = val
280
+ @@id_arr.push val
281
+ else
282
+ raise HeaderArgumentError, "ID #{val} out of range"
283
+ end
284
+ end
285
+
286
+ # Checks whether the header is a query (+qr+ bit set to 0)
287
+ #
288
+ def query?
289
+ @qr == 0
290
+ end
291
+
292
+ # Set the +qr+ query response flag to be either +true+ or
293
+ # +false+. You can also use the values 0 and 1. This flag
294
+ # indicates if the DNS packet contains a query or an answer,
295
+ # so it should be set to +true+ in DNS answer packets.
296
+ # If +qr+ is +true+, the packet is a response.
297
+ #
298
+ def qr=(val)
299
+ case val
300
+ when true
301
+ @qr = 1
302
+ when false
303
+ @qr = 0
304
+ when 0,1
305
+ @qr = val
306
+ else
307
+ raise HeaderArgumentError, ":qr must be true(or 1) or false(or 0)"
308
+ end
309
+ end
310
+
311
+ # Checks whether the header is a response
312
+ # (+qr+ bit set to 1)
313
+ #
314
+ def response?
315
+ @qr == 1
316
+ end
317
+
318
+ # Returns a string representation of the +opCode+
319
+ #
320
+ # puts "Packet is a #{header.opCode_str}"
321
+ # #=> Packet is a QUERY
322
+ #
323
+ def opCode_str
324
+ OPARR[@opCode]
325
+ end
326
+
327
+ # Set the +opCode+ variable to a new value. This fields indicates
328
+ # the type of the question present in the DNS packet; +val+ can be
329
+ # one of the values QUERY, IQUERY or STATUS.
330
+ #
331
+ # * QUERY is the standard DNS query
332
+ # * IQUERY is the inverse query
333
+ # * STATUS is used to query the nameserver for its status
334
+ #
335
+ # Example:
336
+ #
337
+ # include Net::DNS
338
+ # header = Header.new
339
+ # header.opCode = Header::STATUS
340
+ #
341
+ def opCode=(val)
342
+ if (0..2).include? val
343
+ @opCode = val
344
+ else
345
+ raise HeaderWrongOpcode, "Wrong opCode value (#{val}), must be QUERY, IQUERY or STATUS"
346
+ end
347
+ end
348
+
349
+ # Checks whether the response is authoritative
350
+ #
351
+ # if header.auth?
352
+ # puts "Response is authoritative"
353
+ # else
354
+ # puts "Answer is NOT authoritative"
355
+ # end
356
+ #
357
+ def auth?
358
+ @aa == 1
359
+ end
360
+
361
+ # Set the +aa+ flag (authoritative answer) to either +true+
362
+ # or +false+. You can also use 0 or 1.
363
+ #
364
+ # This flag indicates whether a DNS answer packet contains
365
+ # authoritative data, meaning that is was generated by a
366
+ # nameserver authoritative for the domain of the question.
367
+ #
368
+ # Must only be set to +true+ in DNS answer packets.
369
+ #
370
+ def aa=(val)
371
+ case val
372
+ when true
373
+ @aa = 1
374
+ when false
375
+ @aa = 0
376
+ when 0,1
377
+ @aa = val
378
+ else
379
+ raise HeaderArgumentError, ":aa must be true(or 1) or false(or 0)"
380
+ end
381
+ end
382
+
383
+ # Checks whether the packet was truncated
384
+ #
385
+ # # Sending packet using UDP
386
+ # if header.truncated?
387
+ # puts "Warning, packet has been truncated!"
388
+ # # Sending packet using TCP
389
+ # end
390
+ # # Do something with the answer
391
+ #
392
+ def truncated?
393
+ @tc == 1
394
+ end
395
+
396
+ # Set the +tc+ flag (truncated packet) to either +true+
397
+ # ot +false+. You can also use 0 or 1.
398
+ #
399
+ # The truncated flag is used in response packets to indicate
400
+ # that the amount of data to be trasmitted exceedes the
401
+ # maximum allowed by the protocol in use, tipically UDP, and
402
+ # that the data present in the packet has been truncated.
403
+ # A different protocol (such has TCP) need to be used to
404
+ # retrieve full data.
405
+ #
406
+ # Must only be set in DNS answer packets.
407
+ #
408
+ def tc=(val)
409
+ case val
410
+ when true
411
+ @tc = 1
412
+ when false
413
+ @tc = 0
414
+ when 0,1
415
+ @tc = val
416
+ else
417
+ raise HeaderArgumentError, ":tc must be true(or 1) or false(or 0)"
418
+ end
419
+ end
420
+
421
+ # Checks whether the packet has a recursion bit
422
+ # set, meaning that recursion is desired
423
+ #
424
+ def recursive?
425
+ @rd == 1
426
+ end
427
+
428
+ # Sets the recursion desidered bit.
429
+ # Remember that recursion query support is
430
+ # optional.
431
+ #
432
+ # header.recursive = true
433
+ # hdata = header.data # suitable for sending
434
+ #
435
+ # Consult RFC1034 and RFC1035 for a detailed explanation
436
+ # of how recursion works.
437
+ #
438
+ def recursive=(val)
439
+ case val
440
+ when true
441
+ @rd = 1
442
+ when false
443
+ @rd = 0
444
+ when 1
445
+ @rd = 1
446
+ when 0
447
+ @rd = 0
448
+ else
449
+ raise HeaderWrongRecursive, "Wrong value (#{val}), please specify true (1) or false (0)"
450
+ end
451
+ end
452
+
453
+ # Alias for Header#recursive= to keep compatibility
454
+ # with the Perl version.
455
+ #
456
+ def rd=(val)
457
+ self.recursive = val
458
+ end
459
+
460
+ # Checks whether recursion is available.
461
+ # This flag is usually set by nameservers to indicate
462
+ # that they support recursive-type queries.
463
+ #
464
+ def r_available?
465
+ @ra == 1
466
+ end
467
+
468
+ # Set the +ra+ flag (recursion available) to either +true+ or
469
+ # +false+. You can also use 0 and 1.
470
+ #
471
+ # This flag must only be set in DNS answer packets.
472
+ #
473
+ def ra=(val)
474
+ case val
475
+ when true
476
+ @ra = 1
477
+ when false
478
+ @ra = 0
479
+ when 0,1
480
+ @ra = val
481
+ else
482
+ raise HeaderArgumentError, ":ra must be true(or 1) or false(or 0)"
483
+ end
484
+ end
485
+
486
+ # Checks whether checking is enabled or disabled.
487
+ #
488
+ # Checking is enabled by default.
489
+ #
490
+ def checking?
491
+ @cd == 0
492
+ end
493
+
494
+ # Set the +cd+ flag (checking disabled) to either +true+
495
+ # ot +false+. You can also use 0 or 1.
496
+ #
497
+ def cd=(val)
498
+ case val
499
+ when true
500
+ @cd = 1
501
+ when false
502
+ @cd = 0
503
+ when 0,1
504
+ @cd = val
505
+ else
506
+ raise HeaderArgumentError, ":cd must be true(or 1) or false(or 0)"
507
+ end
508
+ end
509
+
510
+ # Checks whether +ad+ flag has been set.
511
+ #
512
+ # This flag is only relevant in DNSSEC context.
513
+ #
514
+ def verified?
515
+ @ad == 1
516
+ end
517
+
518
+ # Set the +ad+ flag to either +true+
519
+ # ot +false+. You can also use 0 or 1.
520
+ #
521
+ # The AD bit is only set on answers where signatures have
522
+ # been cryptographically verified or the server is
523
+ # authoritative for the data and is allowed to set the bit by policy.
524
+ #
525
+ def ad=(val)
526
+ case val
527
+ when true
528
+ @ad = 1
529
+ when false
530
+ @ad = 0
531
+ when 0,1
532
+ @ad = val
533
+ else
534
+ raise HeaderArgumentError, ":ad must be true(or 1) or false(or 0)"
535
+ end
536
+ end
537
+
538
+ # Returns an error array for the header response code, or
539
+ # +nil+ if no error is generated.
540
+ #
541
+ # error, cause = header.rcode_str
542
+ # puts "Error #{error} cause by: #{cause}" if error
543
+ # #=> Error Format Error caused by: The name server
544
+ # #=> was unable to interpret the query
545
+ #
546
+ def rCode_str
547
+ case @rCode
548
+ when NOERROR
549
+ return nil,nil
550
+ when FORMAT
551
+ return "Format Error", "The name server was unable to interpret the query"
552
+ when SERVER
553
+ return "Server Failure",
554
+ "The name server was unable to process this query due to problem with the name server"
555
+ when NAME
556
+ return "Name Error", "Domain name referenced in the query does not exists"
557
+ when NOTIMPLEMENTED
558
+ return "Not Implemented",
559
+ "The name server does not support the requested kind of query"
560
+ when REFUSED
561
+ return "Refused",
562
+ "The name server refuses to perform the specified operation for policy reasons"
563
+ end
564
+ end
565
+
566
+ # Return the value of rCode variable
567
+ #
568
+ # if header.rcode == Net::DNS::Header::NOERROR
569
+ # puts "No errors in DNS answer packet"
570
+ # end
571
+ #
572
+ def rCode
573
+ @rCode
574
+ end
575
+
576
+ # Set the rCode value. This should only be done in DNS
577
+ # answer packets.
578
+ #
579
+ def rCode=(val)
580
+ if (0..5).include? val
581
+ @rCode = val
582
+ else
583
+ raise HeaderArgumentError, ":rCode must be one of #{CODEARR.join(" ")}"
584
+ end
585
+ end
586
+
587
+ # Sets the number of entries in a question section
588
+ #
589
+ def qdCount=(val)
590
+ if (0..65535).include? val
591
+ @qdCount = val
592
+ else
593
+ raise HeaderWrongCount, "Wrong number of count (#{val}), must be 0-65535"
594
+ end
595
+ end
596
+
597
+ # Sets the number of RRs in an answer section
598
+ #
599
+ def anCount=(val)
600
+ if (0..65535).include? val
601
+ @anCount = val
602
+ else
603
+ raise HeaderWrongCount, "Wrong number of count (#{val}), must be 0-65535"
604
+ end
605
+ end
606
+
607
+ # Sets the number of RRs in an authority section
608
+ #
609
+ def nsCount=(val)
610
+ if (0..65535).include? val
611
+ @nsCount = val
612
+ else
613
+ raise HeaderWrongCount, "Wrong number of count (#{val}), must be 0-65535"
614
+ end
615
+ end
616
+
617
+ # Sets the number of RRs in an addictional section
618
+ #
619
+ def arCount=(val)
620
+ if (0..65535).include? val
621
+ @arCount = val
622
+ else
623
+ raise HeaderWrongCount, "Wrong number of count (#{val}), must be 0-65535"
624
+ end
625
+ end
626
+
627
+ private
628
+
629
+ def new_from_scratch
630
+ @id = genID # generate ad unique id
631
+ @qr = @aa = @tc = @ra = @ad = @cd = 0
632
+ @rCode = NOERROR
633
+ @anCount = @nsCount = @arCount = 0
634
+ @rd = @qdCount = 1
635
+ @opCode = QUERY # standard query, default message
636
+ end
637
+
638
+ def new_from_binary(str)
639
+ unless str.size == Net::DNS::HFIXEDSZ
640
+ raise HeaderArgumentError, "Header binary data has wrong size: #{str.size} bytes"
641
+ end
642
+ arr = str.unpack("n C2 n4")
643
+ @id = arr[0]
644
+ @qr = (arr[1] >> 7) & 0x01
645
+ @opCode = (arr[1] >> 3) & 0x0F
646
+ @aa = (arr[1] >> 2) & 0x01
647
+ @tc = (arr[1] >> 1) & 0x01
648
+ @rd = arr[1] & 0x1
649
+ @ra = (arr[2] >> 7) & 0x01
650
+ @ad = (arr[2] >> 5) & 0x01
651
+ @cd = (arr[2] >> 4) & 0x01
652
+ @rCode = arr[2] & 0xf
653
+ @qdCount = arr[3]
654
+ @anCount = arr[4]
655
+ @nsCount = arr[5]
656
+ @arCount = arr[6]
657
+ end
658
+
659
+ def new_from_hash(hash)
660
+ new_from_scratch
661
+ hash.each do |key,val|
662
+ eval "self.#{key.to_s} = val"
663
+ end
664
+ end
665
+
666
+ def genID
667
+ while (@@id_arr.include?(q = rand(65535)))
668
+ end
669
+ @@id_arr.push(q)
670
+ q
671
+ end
672
+
673
+ end # class Header
674
+
675
+ end # class DNS
676
+ end # module Net
677
+
678
+
679
+ class HeaderArgumentError < ArgumentError # :nodoc: all
680
+ end
681
+
682
+ class HeaderWrongCount < ArgumentError # :nodoc: all
683
+ end
684
+
685
+ class HeaderWrongRecursive < ArgumentError # :nodoc: all
686
+ end
687
+
688
+ class HeaderWrongOpcode < ArgumentError # :nodoc: all
689
+ end
690
+
691
+ class HeaderDuplicateID < ArgumentError # :nodoc: all
692
+ end