dnsruby 1.55 → 1.56.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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +96 -0
  3. data/Rakefile +30 -29
  4. data/demo/axfr.rb +93 -93
  5. data/demo/check_soa.rb +99 -99
  6. data/demo/check_zone.rb +59 -59
  7. data/demo/digdlv.rb +43 -43
  8. data/demo/digroot.rb +34 -34
  9. data/demo/example_recurse.rb +14 -14
  10. data/demo/mresolv.rb +30 -30
  11. data/demo/mx.rb +31 -31
  12. data/demo/rubydig.rb +37 -37
  13. data/demo/to_resolve.txt +3088 -3088
  14. data/demo/trace_dns.rb +46 -46
  15. data/lib/dnsruby.rb +161 -526
  16. data/lib/dnsruby/DNS.rb +305 -0
  17. data/lib/{Dnsruby/Cache.rb → dnsruby/cache.rb} +152 -152
  18. data/lib/{Dnsruby → dnsruby}/code_mapper.rb +48 -52
  19. data/lib/dnsruby/code_mappers.rb +295 -0
  20. data/lib/{Dnsruby/Config.rb → dnsruby/config.rb} +454 -454
  21. data/lib/{Dnsruby → dnsruby}/dnssec.rb +91 -91
  22. data/lib/{Dnsruby/Hosts.rb → dnsruby/hosts.rb} +125 -125
  23. data/lib/{Dnsruby → dnsruby}/ipv4.rb +26 -26
  24. data/lib/{Dnsruby → dnsruby}/ipv6.rb +42 -42
  25. data/lib/{Dnsruby → dnsruby}/key_cache.rb +29 -29
  26. data/lib/dnsruby/message/decoder.rb +164 -0
  27. data/lib/dnsruby/message/encoder.rb +75 -0
  28. data/lib/dnsruby/message/header.rb +249 -0
  29. data/lib/dnsruby/message/message.rb +629 -0
  30. data/lib/dnsruby/message/question.rb +86 -0
  31. data/lib/dnsruby/message/section.rb +96 -0
  32. data/lib/{Dnsruby → dnsruby}/name.rb +141 -141
  33. data/lib/dnsruby/packet_sender.rb +661 -0
  34. data/lib/{Dnsruby/Recursor.rb → dnsruby/recursor.rb} +235 -233
  35. data/lib/dnsruby/resolv.rb +113 -0
  36. data/lib/dnsruby/resolver.rb +1192 -0
  37. data/lib/dnsruby/resource/A.rb +56 -0
  38. data/lib/dnsruby/resource/AAAA.rb +54 -0
  39. data/lib/{Dnsruby → dnsruby}/resource/AFSDB.rb +68 -68
  40. data/lib/{Dnsruby → dnsruby}/resource/CERT.rb +105 -105
  41. data/lib/{Dnsruby → dnsruby}/resource/DHCID.rb +54 -54
  42. data/lib/dnsruby/resource/DLV.rb +27 -0
  43. data/lib/{Dnsruby → dnsruby}/resource/DNSKEY.rb +372 -372
  44. data/lib/{Dnsruby → dnsruby}/resource/DS.rb +255 -255
  45. data/lib/{Dnsruby → dnsruby}/resource/HINFO.rb +71 -71
  46. data/lib/{Dnsruby → dnsruby}/resource/HIP.rb +29 -29
  47. data/lib/{Dnsruby → dnsruby}/resource/IN.rb +30 -30
  48. data/lib/{Dnsruby → dnsruby}/resource/IPSECKEY.rb +31 -31
  49. data/lib/{Dnsruby → dnsruby}/resource/ISDN.rb +62 -62
  50. data/lib/{Dnsruby → dnsruby}/resource/KX.rb +65 -65
  51. data/lib/{Dnsruby → dnsruby}/resource/LOC.rb +263 -263
  52. data/lib/{Dnsruby → dnsruby}/resource/MINFO.rb +69 -69
  53. data/lib/{Dnsruby → dnsruby}/resource/MX.rb +65 -65
  54. data/lib/{Dnsruby → dnsruby}/resource/NAPTR.rb +98 -98
  55. data/lib/{Dnsruby → dnsruby}/resource/NSAP.rb +171 -171
  56. data/lib/dnsruby/resource/NSEC.rb +275 -0
  57. data/lib/dnsruby/resource/NSEC3.rb +332 -0
  58. data/lib/dnsruby/resource/NSEC3PARAM.rb +135 -0
  59. data/lib/dnsruby/resource/OPT.rb +272 -0
  60. data/lib/{Dnsruby → dnsruby}/resource/PX.rb +70 -70
  61. data/lib/{Dnsruby → dnsruby}/resource/RP.rb +75 -75
  62. data/lib/dnsruby/resource/RR.rb +421 -0
  63. data/lib/dnsruby/resource/RRSIG.rb +275 -0
  64. data/lib/dnsruby/resource/RRSet.rb +190 -0
  65. data/lib/{Dnsruby → dnsruby}/resource/RT.rb +67 -67
  66. data/lib/{Dnsruby → dnsruby}/resource/SOA.rb +94 -94
  67. data/lib/dnsruby/resource/SPF.rb +29 -0
  68. data/lib/dnsruby/resource/SRV.rb +112 -0
  69. data/lib/{Dnsruby → dnsruby}/resource/SSHFP.rb +14 -14
  70. data/lib/dnsruby/resource/TKEY.rb +163 -0
  71. data/lib/dnsruby/resource/TSIG.rb +593 -0
  72. data/lib/{Dnsruby → dnsruby}/resource/TXT.rb +191 -191
  73. data/lib/dnsruby/resource/X25.rb +55 -0
  74. data/lib/{Dnsruby → dnsruby}/resource/domain_name.rb +25 -25
  75. data/lib/{Dnsruby → dnsruby}/resource/generic.rb +80 -80
  76. data/lib/dnsruby/resource/resource.rb +25 -0
  77. data/lib/{Dnsruby → dnsruby}/select_thread.rb +148 -148
  78. data/lib/{Dnsruby/SingleResolver.rb → dnsruby/single_resolver.rb} +60 -60
  79. data/lib/{Dnsruby → dnsruby}/single_verifier.rb +344 -344
  80. data/lib/dnsruby/the_log.rb +44 -0
  81. data/lib/dnsruby/update.rb +278 -0
  82. data/lib/dnsruby/validator_thread.rb +124 -0
  83. data/lib/dnsruby/version.rb +3 -0
  84. data/lib/{Dnsruby → dnsruby}/zone_reader.rb +93 -93
  85. data/lib/{Dnsruby → dnsruby}/zone_transfer.rb +377 -377
  86. data/test/spec_helper.rb +16 -0
  87. data/test/tc_axfr.rb +31 -34
  88. data/test/tc_cache.rb +32 -32
  89. data/test/tc_dlv.rb +28 -28
  90. data/test/tc_dns.rb +73 -76
  91. data/test/tc_dnskey.rb +31 -32
  92. data/test/tc_dnsruby.rb +50 -44
  93. data/test/tc_ds.rb +36 -36
  94. data/test/tc_escapedchars.rb +252 -255
  95. data/test/tc_hash.rb +17 -21
  96. data/test/tc_header.rb +48 -57
  97. data/test/tc_hip.rb +19 -22
  98. data/test/tc_ipseckey.rb +18 -21
  99. data/test/tc_keith.rb +300 -0
  100. data/test/tc_message.rb +87 -0
  101. data/test/tc_misc.rb +83 -87
  102. data/test/tc_name.rb +81 -84
  103. data/test/tc_naptr.rb +18 -21
  104. data/test/tc_nsec.rb +55 -55
  105. data/test/tc_nsec3.rb +23 -24
  106. data/test/tc_nsec3param.rb +20 -21
  107. data/test/tc_packet.rb +90 -93
  108. data/test/tc_packet_unique_push.rb +48 -51
  109. data/test/tc_question.rb +30 -33
  110. data/test/tc_queue.rb +16 -17
  111. data/test/tc_recur.rb +16 -17
  112. data/test/tc_res_config.rb +38 -41
  113. data/test/tc_res_env.rb +29 -32
  114. data/test/tc_res_file.rb +26 -29
  115. data/test/tc_res_opt.rb +62 -65
  116. data/test/tc_resolver.rb +287 -242
  117. data/test/tc_rr-opt.rb +70 -63
  118. data/test/tc_rr-txt.rb +68 -71
  119. data/test/tc_rr-unknown.rb +45 -48
  120. data/test/tc_rr.rb +76 -70
  121. data/test/tc_rrset.rb +21 -22
  122. data/test/tc_rrsig.rb +19 -20
  123. data/test/tc_single_resolver.rb +294 -297
  124. data/test/tc_soak.rb +199 -202
  125. data/test/tc_soak_base.rb +29 -34
  126. data/test/tc_sshfp.rb +20 -23
  127. data/test/tc_tcp.rb +32 -35
  128. data/test/tc_tkey.rb +41 -44
  129. data/test/tc_tsig.rb +81 -84
  130. data/test/tc_update.rb +108 -111
  131. data/test/tc_validator.rb +29 -29
  132. data/test/tc_verifier.rb +81 -82
  133. data/test/ts_dnsruby.rb +16 -15
  134. data/test/ts_offline.rb +62 -63
  135. data/test/ts_online.rb +115 -115
  136. metadata +155 -90
  137. data/README +0 -59
  138. data/lib/Dnsruby/DNS.rb +0 -305
  139. data/lib/Dnsruby/PacketSender.rb +0 -656
  140. data/lib/Dnsruby/Resolver.rb +0 -1189
  141. data/lib/Dnsruby/TheLog.rb +0 -44
  142. data/lib/Dnsruby/message.rb +0 -1230
  143. data/lib/Dnsruby/resource/A.rb +0 -56
  144. data/lib/Dnsruby/resource/AAAA.rb +0 -54
  145. data/lib/Dnsruby/resource/DLV.rb +0 -27
  146. data/lib/Dnsruby/resource/NSEC.rb +0 -298
  147. data/lib/Dnsruby/resource/NSEC3.rb +0 -340
  148. data/lib/Dnsruby/resource/NSEC3PARAM.rb +0 -135
  149. data/lib/Dnsruby/resource/OPT.rb +0 -213
  150. data/lib/Dnsruby/resource/RRSIG.rb +0 -275
  151. data/lib/Dnsruby/resource/SPF.rb +0 -29
  152. data/lib/Dnsruby/resource/SRV.rb +0 -112
  153. data/lib/Dnsruby/resource/TKEY.rb +0 -163
  154. data/lib/Dnsruby/resource/TSIG.rb +0 -593
  155. data/lib/Dnsruby/resource/X25.rb +0 -55
  156. data/lib/Dnsruby/resource/resource.rb +0 -678
  157. data/lib/Dnsruby/update.rb +0 -278
  158. data/lib/Dnsruby/validator_thread.rb +0 -124
@@ -1,455 +1,455 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- module Dnsruby
17
- #== Description
18
- # The Config class determines the system configuration for DNS.
19
- # In particular, it determines the nameserver to target queries to.
20
- #
21
- #
22
- # It also specifies whether and how the search list and default
23
- # domain should be applied to queries, according to the following
24
- # algorithm :
25
- #
26
- #* If the name is absolute, then it is used as is.
27
- #
28
- #* If the name is not absolute, then :
29
- #
30
- # If apply_domain is true, and ndots is greater than the number
31
- # of labels in the name, then the default domain is added to the name.
32
- #
33
- # If apply_search_list is true, then each member of the search list
34
- # is appended to the name.
35
- #
36
- # The Config class has now been modified for lazy loading. Previously, the config
37
- # was loaded when a Resolver was instantiated. Now, the config is only loaded if
38
- # a query is performed (or a config parameter requested on) a Resolver which has
39
- # not yet been configured.
40
- class Config
41
- #--
42
- #@TODO@ Switches for :
43
- #
44
- # -- single socket for all packets
45
- # -- single new socket for individual client queries (including retries and multiple nameservers)
46
- #++
47
-
48
- # The list of nameservers to query
49
- def nameserver
50
- if (!@configured)
51
- parse_config
52
- end
53
- return @nameserver
54
- end
55
- # Should the search list be applied?
56
- attr_accessor :apply_search_list
57
- # Should the default domain be applied?
58
- attr_accessor :apply_domain
59
- # The minimum number of labels in the query name (if it is not absolute) before it is considered complete
60
- def ndots
61
- if (!@configured)
62
- parse_config
63
- end
64
- return @ndots
65
- end
66
-
67
- # Set the config. Parameter can be :
68
- #
69
- # * A String containing the name of the config file to load
70
- # e.g. /etc/resolv.conf
71
- #
72
- # * A hash with the following elements :
73
- # nameserver (String)
74
- # domain (String)
75
- # search (String)
76
- # ndots (Fixnum)
77
- #
78
- # This method should not normally be called by client code.
79
- def set_config_info(config_info)
80
- parse_config(config_info)
81
- end
82
-
83
- # Create a new Config with system default values
84
- def initialize()
85
- @mutex = Mutex.new
86
- @configured = false
87
- # parse_config
88
- end
89
- # Reset the config to default values
90
- def Config.reset
91
- c = Config.new
92
- @configured = false
93
- # c.parse_config
94
- end
95
-
96
- def parse_config(config_info=nil) #:nodoc: all
97
- @mutex.synchronize {
98
- ns = []
99
- @nameserver = []
100
- @domain, s, @search = nil
101
- dom=""
102
- nd = 1
103
- @ndots = 1
104
- @apply_search_list = true
105
- @apply_domain = true
106
- config_hash = Config.default_config_hash
107
- case config_info
108
- when nil
109
- when String
110
- config_hash.merge!(Config.parse_resolv_conf(config_info))
111
- when Hash
112
- config_hash.merge!(config_info.dup)
113
- if String === config_hash[:nameserver]
114
- config_hash[:nameserver] = [config_hash[:nameserver]]
115
- end
116
- if String === config_hash[:search]
117
- config_hash[:search] = [config_hash[:search]]
118
- end
119
- else
120
- raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
121
- end
122
- ns = config_hash[:nameserver] if config_hash.include? :nameserver
123
- s = config_hash[:search] if config_hash.include? :search
124
- nd = config_hash[:ndots] if config_hash.include? :ndots
125
- @apply_search_list = config_hash[:apply_search_list] if config_hash.include? :apply_search_list
126
- @apply_domain= config_hash[:apply_domain] if config_hash.include? :apply_domain
127
- dom = config_hash[:domain] if config_hash.include? :domain
128
-
129
- if (!@configured)
130
- send("nameserver=",ns)
131
- end
132
- @configured = true
133
- send("search=",s)
134
- send("ndots=",nd)
135
- send("domain=",dom)
136
- }
137
- Dnsruby.log.info{to_s}
138
- end
139
-
140
- # Set the default domain
141
- def domain=(dom)
142
- # @configured = true
143
- if (dom)
144
- if !dom.kind_of?(String)
145
- raise ArgumentError.new("invalid domain config: #{@domain.inspect}")
146
- end
147
- @domain = Name::split(dom)
148
- else
149
- @domain=nil
150
- end
151
- end
152
-
153
- # Set ndots
154
- def ndots=(nd)
155
- @configured = true
156
- @ndots=nd
157
- if !@ndots.kind_of?(Integer)
158
- raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
159
- end
160
- end
161
-
162
- # Set the default search path
163
- def search=(s)
164
- @configured = true
165
- @search=s
166
- if @search
167
- if @search.class == Array
168
- @search = @search.map {|arg| Name::split(arg) }
169
- else
170
- raise ArgumentError.new("invalid search config: search must be an array!")
171
- end
172
- else
173
- hostname = Socket.gethostname
174
- if /\./ =~ hostname
175
- @search = [Name.split($')]
176
- else
177
- @search = [[]]
178
- end
179
- end
180
-
181
- if !@search.kind_of?(Array) ||
182
- # !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
183
- !@search.all? {|ls| ls.all? {|l| Name::Label === l } }
184
- raise ArgumentError.new("invalid search config: #{@search.inspect}")
185
- end
186
- end
187
-
188
- def check_ns(ns) #:nodoc: all
189
- if !ns.kind_of?(Array) ||
190
- !ns.all? {|n| (Name === n || String === n || IPv4 === n || IPv6 === n)}
191
- raise ArgumentError.new("invalid nameserver config: #{ns.inspect}")
192
- end
193
- ns.each {|n|
194
- if (String ===n)
195
- # Make sure we can make a Name or an address from it
196
- begin
197
- a = IPv4.create(n)
198
- rescue ArgumentError
199
- begin
200
- a = IPv6.create(n)
201
- rescue ArgumentError
202
- begin
203
- a = Name.create(n)
204
- rescue ArgumentError
205
- raise ArgumentError.new("Can't interpret #{n} as IPv4, IPv6 or Name")
206
- end
207
- end
208
- end
209
- end
210
- }
211
- end
212
-
213
- # Add a nameserver to the list of nameservers.
214
- #
215
- # Can take either a single String or an array of Strings.
216
- # The new nameservers are added at a higher priority.
217
- def add_nameserver(ns)
218
- @configured = true
219
- if (ns.kind_of?String)
220
- ns=[ns]
221
- end
222
- check_ns(ns)
223
- ns.reverse_each do |n|
224
- if (!@nameserver.include?(n))
225
- self.nameserver=[n]+@nameserver
226
- end
227
- end
228
- end
229
-
230
- # Set the config to point to a single nameserver
231
- def nameserver=(ns)
232
- @configured = true
233
- check_ns(ns)
234
- # @nameserver = ['0.0.0.0'] if (@nameserver.class != Array || @nameserver.empty?)
235
- # Now go through and ensure that all ns point to IP addresses, not domain names
236
- @nameserver=ns
237
- Dnsruby.log.debug{"Nameservers = #{@nameserver.join(", ")}"}
238
- end
239
-
240
- def Config.resolve_server(ns) #:nodoc: all
241
- # Sanity check server
242
- # If it's an IP address, then use that for server
243
- # If it's a name, then we'll need to resolve it first
244
- server=ns
245
- if (Name === ns)
246
- ns = ns.to_s
247
- end
248
- begin
249
- addr = IPv4.create(ns)
250
- server = ns
251
- rescue Exception
252
- begin
253
- addr=IPv6.create(ns)
254
- server = ns
255
- rescue Exception
256
- begin
257
- # try to resolve server to address
258
- if ns == "localhost"
259
- server = "127.0.0.1"
260
- else
261
- # Use Dnsruby to resolve the servers
262
- # First, try the default resolvers
263
- resolver = Resolver.new
264
- found = false
265
- begin
266
- ret = resolver.query(ns)
267
- ret.answer.each {|rr|
268
- if ([Types::A, Types::AAAA].include?rr.type)
269
- addr = rr.address.to_s
270
- server = addr
271
- found = true
272
- end
273
- }
274
- rescue Exception
275
- end
276
- if (!found)
277
- # That didn't work - try recursing from the root
278
- recursor = Recursor.new
279
- ret = recursor.query(ns)
280
- ret.answer.each {|rr|
281
- if ([Types::A, Types::AAAA].include?rr.type)
282
- addr = rr.address.to_s
283
- server = addr
284
- end
285
- }
286
- if (!found)
287
- raise ArgumentError.new("Recursor can't locate #{server}")
288
- end
289
- end
290
- end
291
- rescue Exception => e
292
- Dnsruby.log.error{"Can't make sense of nameserver : #{server}, exception : #{e}"}
293
- # raise ArgumentError.new("Can't make sense of nameserver : #{server}, exception : #{e}")
294
- return nil
295
- end
296
- end
297
- end
298
- return server
299
- end
300
-
301
- def Config.parse_resolv_conf(filename) #:nodoc: all
302
- nameserver = []
303
- search = nil
304
- domain = nil
305
- ndots = 1
306
- open(filename) {|f|
307
- f.each {|line|
308
- line.sub!(/[#;].*/, '')
309
- keyword, *args = line.split(/\s+/)
310
- args.each { |arg|
311
- arg.untaint
312
- }
313
- next unless keyword
314
- case keyword
315
- when 'nameserver'
316
- nameserver += args
317
- when 'domain'
318
- next if args.empty?
319
- domain = args[0]
320
- # if search == nil
321
- # search = []
322
- # end
323
- # search.push(args[0])
324
- when 'search'
325
- next if args.empty?
326
- if search == nil
327
- search = []
328
- end
329
- args.each {|a| search.push(a)}
330
- when 'options'
331
- args.each {|arg|
332
- case arg
333
- when /\Andots:(\d+)\z/
334
- ndots = $1.to_i
335
- end
336
- }
337
- end
338
- }
339
- }
340
- return { :nameserver => nameserver, :domain => domain, :search => search, :ndots => ndots }
341
- end
342
-
343
- def inspect #:nodoc: all
344
- to_s
345
- end
346
-
347
- def to_s
348
- if (!@configured)
349
- parse_config
350
- end
351
- ret = "Config - nameservers : "
352
- @nameserver.each {|n| ret += n.to_s + ", "}
353
- domain_string="empty"
354
- if (@domain!=nil)
355
- domain_string=@domain.to_s
356
- end
357
- ret += " domain : #{domain_string}, search : "
358
- search.each {|s| ret += s + ", " }
359
- ret += " ndots : #{@ndots}"
360
- return ret
361
- end
362
-
363
- def Config.default_config_hash(filename="/etc/resolv.conf") #:nodoc: all
364
- config_hash={}
365
- if File.exist? filename
366
- config_hash = Config.parse_resolv_conf(filename)
367
- else
368
- if (/java/ =~ RUBY_PLATFORM && !(filename=~/:/))
369
- # Problem with paths and Windows on JRuby - see if we can munge the drive...
370
- wd = Dir.getwd
371
- drive = wd.split(':')[0]
372
- if (drive.length==1)
373
- file = drive << ":" << filename
374
- if File.exist? file
375
- config_hash = Config.parse_resolv_conf(file)
376
- end
377
- end
378
- elsif /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
379
- # @TODO@ Need to get windows domain sorted
380
- search, nameserver = Win32::Resolv.get_resolv_info
381
- # config_hash[:domain] = domain if domain
382
- config_hash[:nameserver] = nameserver if nameserver
383
- config_hash[:search] = [search].flatten if search
384
- end
385
- end
386
- config_hash
387
- end
388
-
389
- # Return the search path
390
- def search
391
- if (!@configured)
392
- parse_config
393
- end
394
- search = []
395
- @search.each do |s|
396
- search.push(Name.new(s).to_s)
397
- end
398
- return search
399
- end
400
-
401
- # Return the default domain
402
- def domain
403
- if (!@configured)
404
- parse_config
405
- end
406
- if (@domain==nil)
407
- return nil
408
- end
409
- return Name.create(@domain).to_s
410
- end
411
-
412
- def single? #:nodoc: all
413
- if @nameserver.length == 1
414
- return @nameserver[0]
415
- else
416
- return nil
417
- end
418
- end
419
-
420
- def get_ready
421
- if (!@configured)
422
- parse_config
423
- end
424
- end
425
-
426
- def generate_candidates(name) #:nodoc: all
427
- if !@configured
428
- parse_config
429
- end
430
- candidates = []
431
- name = Name.create(name)
432
- if name.absolute?
433
- candidates = [name]
434
- else
435
- if (@apply_domain)
436
- if @ndots > name.length - 1
437
- candidates.push(Name.create(name.to_a+@domain))
438
- end
439
- end
440
- if (!@apply_search_list)
441
- candidates.push(Name.create(name.to_a))
442
- else
443
- if @ndots <= name.length - 1
444
- candidates.push(Name.create(name.to_a))
445
- end
446
- candidates.concat(@search.map {|domain| Name.create(name.to_a + domain)})
447
- if (name.length == 1)
448
- candidates.concat([Name.create(name.to_a)])
449
- end
450
- end
451
- end
452
- return candidates
453
- end
454
- end
1
+ # --
2
+ # Copyright 2007 Nominet UK
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+ module Dnsruby
17
+ # == Description
18
+ # The Config class determines the system configuration for DNS.
19
+ # In particular, it determines the nameserver to target queries to.
20
+ #
21
+ #
22
+ # It also specifies whether and how the search list and default
23
+ # domain should be applied to queries, according to the following
24
+ # algorithm :
25
+ #
26
+ # * If the name is absolute, then it is used as is.
27
+ #
28
+ # * If the name is not absolute, then :
29
+ #
30
+ # If apply_domain is true, and ndots is greater than the number
31
+ # of labels in the name, then the default domain is added to the name.
32
+ #
33
+ # If apply_search_list is true, then each member of the search list
34
+ # is appended to the name.
35
+ #
36
+ # The Config class has now been modified for lazy loading. Previously, the config
37
+ # was loaded when a Resolver was instantiated. Now, the config is only loaded if
38
+ # a query is performed (or a config parameter requested on) a Resolver which has
39
+ # not yet been configured.
40
+ class Config
41
+ # --
42
+ # @TODO@ Switches for :
43
+ #
44
+ # -- single socket for all packets
45
+ # -- single new socket for individual client queries (including retries and multiple nameservers)
46
+ # ++
47
+
48
+ # The list of nameservers to query
49
+ def nameserver
50
+ if (!@configured)
51
+ parse_config
52
+ end
53
+ return @nameserver
54
+ end
55
+ # Should the search list be applied?
56
+ attr_accessor :apply_search_list
57
+ # Should the default domain be applied?
58
+ attr_accessor :apply_domain
59
+ # The minimum number of labels in the query name (if it is not absolute) before it is considered complete
60
+ def ndots
61
+ if (!@configured)
62
+ parse_config
63
+ end
64
+ return @ndots
65
+ end
66
+
67
+ # Set the config. Parameter can be :
68
+ #
69
+ # * A String containing the name of the config file to load
70
+ # e.g. /etc/resolv.conf
71
+ #
72
+ # * A hash with the following elements :
73
+ # nameserver (String)
74
+ # domain (String)
75
+ # search (String)
76
+ # ndots (Fixnum)
77
+ #
78
+ # This method should not normally be called by client code.
79
+ def set_config_info(config_info)
80
+ parse_config(config_info)
81
+ end
82
+
83
+ # Create a new Config with system default values
84
+ def initialize()
85
+ @mutex = Mutex.new
86
+ @configured = false
87
+ # parse_config
88
+ end
89
+ # Reset the config to default values
90
+ def Config.reset
91
+ c = Config.new
92
+ @configured = false
93
+ # c.parse_config
94
+ end
95
+
96
+ def parse_config(config_info=nil) #:nodoc: all
97
+ @mutex.synchronize {
98
+ ns = []
99
+ @nameserver = []
100
+ @domain, s, @search = nil
101
+ dom=""
102
+ nd = 1
103
+ @ndots = 1
104
+ @apply_search_list = true
105
+ @apply_domain = true
106
+ config_hash = Config.default_config_hash
107
+ case config_info
108
+ when nil
109
+ when String
110
+ config_hash.merge!(Config.parse_resolv_conf(config_info))
111
+ when Hash
112
+ config_hash.merge!(config_info.dup)
113
+ if String === config_hash[:nameserver]
114
+ config_hash[:nameserver] = [config_hash[:nameserver]]
115
+ end
116
+ if String === config_hash[:search]
117
+ config_hash[:search] = [config_hash[:search]]
118
+ end
119
+ else
120
+ raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
121
+ end
122
+ ns = config_hash[:nameserver] if config_hash.include? :nameserver
123
+ s = config_hash[:search] if config_hash.include? :search
124
+ nd = config_hash[:ndots] if config_hash.include? :ndots
125
+ @apply_search_list = config_hash[:apply_search_list] if config_hash.include? :apply_search_list
126
+ @apply_domain= config_hash[:apply_domain] if config_hash.include? :apply_domain
127
+ dom = config_hash[:domain] if config_hash.include? :domain
128
+
129
+ if (!@configured)
130
+ send("nameserver=",ns)
131
+ end
132
+ @configured = true
133
+ send("search=",s)
134
+ send("ndots=",nd)
135
+ send("domain=",dom)
136
+ }
137
+ Dnsruby.log.info{to_s}
138
+ end
139
+
140
+ # Set the default domain
141
+ def domain=(dom)
142
+ # @configured = true
143
+ if (dom)
144
+ if !dom.kind_of?(String)
145
+ raise ArgumentError.new("invalid domain config: #{@domain.inspect}")
146
+ end
147
+ @domain = Name::split(dom)
148
+ else
149
+ @domain=nil
150
+ end
151
+ end
152
+
153
+ # Set ndots
154
+ def ndots=(nd)
155
+ @configured = true
156
+ @ndots=nd
157
+ if !@ndots.kind_of?(Integer)
158
+ raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
159
+ end
160
+ end
161
+
162
+ # Set the default search path
163
+ def search=(s)
164
+ @configured = true
165
+ @search=s
166
+ if @search
167
+ if @search.class == Array
168
+ @search = @search.map {|arg| Name::split(arg) }
169
+ else
170
+ raise ArgumentError.new("invalid search config: search must be an array!")
171
+ end
172
+ else
173
+ hostname = Socket.gethostname
174
+ if /\./ =~ hostname
175
+ @search = [Name.split($')]
176
+ else
177
+ @search = [[]]
178
+ end
179
+ end
180
+
181
+ if !@search.kind_of?(Array) ||
182
+ # !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
183
+ !@search.all? {|ls| ls.all? {|l| Name::Label === l } }
184
+ raise ArgumentError.new("invalid search config: #{@search.inspect}")
185
+ end
186
+ end
187
+
188
+ def check_ns(ns) #:nodoc: all
189
+ if !ns.kind_of?(Array) ||
190
+ !ns.all? {|n| (Name === n || String === n || IPv4 === n || IPv6 === n)}
191
+ raise ArgumentError.new("invalid nameserver config: #{ns.inspect}")
192
+ end
193
+ ns.each {|n|
194
+ if (String ===n)
195
+ # Make sure we can make a Name or an address from it
196
+ begin
197
+ a = IPv4.create(n)
198
+ rescue ArgumentError
199
+ begin
200
+ a = IPv6.create(n)
201
+ rescue ArgumentError
202
+ begin
203
+ a = Name.create(n)
204
+ rescue ArgumentError
205
+ raise ArgumentError.new("Can't interpret #{n} as IPv4, IPv6 or Name")
206
+ end
207
+ end
208
+ end
209
+ end
210
+ }
211
+ end
212
+
213
+ # Add a nameserver to the list of nameservers.
214
+ #
215
+ # Can take either a single String or an array of Strings.
216
+ # The new nameservers are added at a higher priority.
217
+ def add_nameserver(ns)
218
+ @configured = true
219
+ if (ns.kind_of?String)
220
+ ns=[ns]
221
+ end
222
+ check_ns(ns)
223
+ ns.reverse_each do |n|
224
+ if (!@nameserver.include?(n))
225
+ self.nameserver=[n]+@nameserver
226
+ end
227
+ end
228
+ end
229
+
230
+ # Set the config to point to a single nameserver
231
+ def nameserver=(ns)
232
+ @configured = true
233
+ check_ns(ns)
234
+ # @nameserver = ['0.0.0.0'] if (@nameserver.class != Array || @nameserver.empty?)
235
+ # Now go through and ensure that all ns point to IP addresses, not domain names
236
+ @nameserver=ns
237
+ Dnsruby.log.debug{"Nameservers = #{@nameserver.join(", ")}"}
238
+ end
239
+
240
+ def Config.resolve_server(ns) #:nodoc: all
241
+ # Sanity check server
242
+ # If it's an IP address, then use that for server
243
+ # If it's a name, then we'll need to resolve it first
244
+ server=ns
245
+ if (Name === ns)
246
+ ns = ns.to_s
247
+ end
248
+ begin
249
+ addr = IPv4.create(ns)
250
+ server = ns
251
+ rescue Exception
252
+ begin
253
+ addr=IPv6.create(ns)
254
+ server = ns
255
+ rescue Exception
256
+ begin
257
+ # try to resolve server to address
258
+ if ns == "localhost"
259
+ server = "127.0.0.1"
260
+ else
261
+ # Use Dnsruby to resolve the servers
262
+ # First, try the default resolvers
263
+ resolver = Resolver.new
264
+ found = false
265
+ begin
266
+ ret = resolver.query(ns)
267
+ ret.answer.each {|rr|
268
+ if ([Types::A, Types::AAAA].include?rr.type)
269
+ addr = rr.address.to_s
270
+ server = addr
271
+ found = true
272
+ end
273
+ }
274
+ rescue Exception
275
+ end
276
+ if (!found)
277
+ # That didn't work - try recursing from the root
278
+ recursor = Recursor.new
279
+ ret = recursor.query(ns)
280
+ ret.answer.each {|rr|
281
+ if ([Types::A, Types::AAAA].include?rr.type)
282
+ addr = rr.address.to_s
283
+ server = addr
284
+ end
285
+ }
286
+ if (!found)
287
+ raise ArgumentError.new("Recursor can't locate #{server}")
288
+ end
289
+ end
290
+ end
291
+ rescue Exception => e
292
+ Dnsruby.log.error{"Can't make sense of nameserver : #{server}, exception : #{e}"}
293
+ # raise ArgumentError.new("Can't make sense of nameserver : #{server}, exception : #{e}")
294
+ return nil
295
+ end
296
+ end
297
+ end
298
+ return server
299
+ end
300
+
301
+ def Config.parse_resolv_conf(filename) #:nodoc: all
302
+ nameserver = []
303
+ search = nil
304
+ domain = nil
305
+ ndots = 1
306
+ open(filename) {|f|
307
+ f.each {|line|
308
+ line.sub!(/[#;].*/, '')
309
+ keyword, *args = line.split(/\s+/)
310
+ args.each { |arg|
311
+ arg.untaint
312
+ }
313
+ next unless keyword
314
+ case keyword
315
+ when 'nameserver'
316
+ nameserver += args
317
+ when 'domain'
318
+ next if args.empty?
319
+ domain = args[0]
320
+ # if search == nil
321
+ # search = []
322
+ # end
323
+ # search.push(args[0])
324
+ when 'search'
325
+ next if args.empty?
326
+ if search == nil
327
+ search = []
328
+ end
329
+ args.each {|a| search.push(a)}
330
+ when 'options'
331
+ args.each {|arg|
332
+ case arg
333
+ when /\Andots:(\d+)\z/
334
+ ndots = $1.to_i
335
+ end
336
+ }
337
+ end
338
+ }
339
+ }
340
+ return { :nameserver => nameserver, :domain => domain, :search => search, :ndots => ndots }
341
+ end
342
+
343
+ def inspect #:nodoc: all
344
+ to_s
345
+ end
346
+
347
+ def to_s
348
+ if (!@configured)
349
+ parse_config
350
+ end
351
+ ret = "Config - nameservers : "
352
+ @nameserver.each {|n| ret += n.to_s + ", "}
353
+ domain_string="empty"
354
+ if (@domain!=nil)
355
+ domain_string=@domain.to_s
356
+ end
357
+ ret += " domain : #{domain_string}, search : "
358
+ search.each {|s| ret += s + ", " }
359
+ ret += " ndots : #{@ndots}"
360
+ return ret
361
+ end
362
+
363
+ def Config.default_config_hash(filename="/etc/resolv.conf") #:nodoc: all
364
+ config_hash={}
365
+ if File.exist? filename
366
+ config_hash = Config.parse_resolv_conf(filename)
367
+ else
368
+ if (/java/ =~ RUBY_PLATFORM && !(filename=~/:/))
369
+ # Problem with paths and Windows on JRuby - see if we can munge the drive...
370
+ wd = Dir.getwd
371
+ drive = wd.split(':')[0]
372
+ if (drive.length==1)
373
+ file = drive << ":" << filename
374
+ if File.exist? file
375
+ config_hash = Config.parse_resolv_conf(file)
376
+ end
377
+ end
378
+ elsif /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
379
+ # @TODO@ Need to get windows domain sorted
380
+ search, nameserver = Win32::Resolv.get_resolv_info
381
+ # config_hash[:domain] = domain if domain
382
+ config_hash[:nameserver] = nameserver if nameserver
383
+ config_hash[:search] = [search].flatten if search
384
+ end
385
+ end
386
+ config_hash
387
+ end
388
+
389
+ # Return the search path
390
+ def search
391
+ if (!@configured)
392
+ parse_config
393
+ end
394
+ search = []
395
+ @search.each do |s|
396
+ search.push(Name.new(s).to_s)
397
+ end
398
+ return search
399
+ end
400
+
401
+ # Return the default domain
402
+ def domain
403
+ if (!@configured)
404
+ parse_config
405
+ end
406
+ if (@domain==nil)
407
+ return nil
408
+ end
409
+ return Name.create(@domain).to_s
410
+ end
411
+
412
+ def single? #:nodoc: all
413
+ if @nameserver.length == 1
414
+ return @nameserver[0]
415
+ else
416
+ return nil
417
+ end
418
+ end
419
+
420
+ def get_ready
421
+ if (!@configured)
422
+ parse_config
423
+ end
424
+ end
425
+
426
+ def generate_candidates(name) #:nodoc: all
427
+ if !@configured
428
+ parse_config
429
+ end
430
+ candidates = []
431
+ name = Name.create(name)
432
+ if name.absolute?
433
+ candidates = [name]
434
+ else
435
+ if (@apply_domain)
436
+ if @ndots > name.length - 1
437
+ candidates.push(Name.create(name.to_a+@domain))
438
+ end
439
+ end
440
+ if (!@apply_search_list)
441
+ candidates.push(Name.create(name.to_a))
442
+ else
443
+ if @ndots <= name.length - 1
444
+ candidates.push(Name.create(name.to_a))
445
+ end
446
+ candidates.concat(@search.map {|domain| Name.create(name.to_a + domain)})
447
+ if (name.length == 1)
448
+ candidates.concat([Name.create(name.to_a)])
449
+ end
450
+ end
451
+ end
452
+ return candidates
453
+ end
454
+ end
455
455
  end