PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/Dnsruby-1.0/Dnsruby/Config.rb

https://github.com/adamwiggins/whatswrong
Ruby | 363 lines | 275 code | 16 blank | 72 comment | 38 complexity | 1f6452325257c3466a2288fc81d59d2c MD5 | raw file
  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. class Config
  37. #--
  38. #@TODO@ Switches for :
  39. #
  40. # -- single socket for all packets
  41. # -- single new socket for individual client queries (including retries and multiple nameservers)
  42. #++
  43. # The list of nameservers to query
  44. attr_reader :nameserver
  45. # Should the search list be applied?
  46. attr_accessor :apply_search_list
  47. # Should the default domain be applied?
  48. attr_accessor :apply_domain
  49. # The minimum number of labels in the query name (if it is not absolute) before it is considered complete
  50. attr_reader :ndots
  51. # Set the config. Parameter can be :
  52. #
  53. # * A String containing the name of the config file to load
  54. # e.g. /etc/resolv.conf
  55. #
  56. # * A hash with the following elements :
  57. # nameserver (String)
  58. # domain (String)
  59. # search (String)
  60. # ndots (Fixnum)
  61. #
  62. # This method should not normally be called by client code.
  63. def set_config_info(config_info)
  64. parse_config(config_info)
  65. end
  66. # Create a new Config with system default values
  67. def initialize()
  68. @mutex = Mutex.new
  69. parse_config
  70. end
  71. # Reset the config to default values
  72. def Config.reset
  73. c = Config.new
  74. c.parse_config
  75. end
  76. def parse_config(config_info=nil) #:nodoc: all
  77. @mutex.synchronize {
  78. ns = []
  79. @nameserver = []
  80. @domain, s, @search = nil
  81. dom=""
  82. nd = 1
  83. @ndots = 1
  84. @apply_search_list = true
  85. @apply_domain = true
  86. config_hash = Config.default_config_hash
  87. case config_info
  88. when nil
  89. when String
  90. config_hash.merge!(Config.parse_resolv_conf(config_info))
  91. when Hash
  92. config_hash.merge!(config_info.dup)
  93. if String === config_hash[:nameserver]
  94. config_hash[:nameserver] = [config_hash[:nameserver]]
  95. end
  96. if String === config_hash[:search]
  97. config_hash[:search] = [config_hash[:search]]
  98. end
  99. else
  100. raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
  101. end
  102. ns = config_hash[:nameserver] if config_hash.include? :nameserver
  103. s = config_hash[:search] if config_hash.include? :search
  104. nd = config_hash[:ndots] if config_hash.include? :ndots
  105. @apply_search_list = config_hash[:apply_search_list] if config_hash.include? :apply_search_list
  106. @apply_domain= config_hash[:apply_domain] if config_hash.include? :apply_domain
  107. dom = config_hash[:domain] if config_hash.include? :domain
  108. send("nameserver=",ns)
  109. send("search=",s)
  110. send("ndots=",nd)
  111. send("domain=",dom)
  112. }
  113. TheLog.info(to_s)
  114. end
  115. # Set the default domain
  116. def domain=(dom)
  117. if (dom)
  118. if !dom.kind_of?(String)
  119. raise ArgumentError.new("invalid domain config: #{@domain.inspect}")
  120. end
  121. @domain = Name::Label.split(dom)
  122. else
  123. @domain=nil
  124. end
  125. end
  126. # Set ndots
  127. def ndots=(nd)
  128. @ndots=nd
  129. if !@ndots.kind_of?(Integer)
  130. raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
  131. end
  132. end
  133. # Set the default search path
  134. def search=(s)
  135. @search=s
  136. if @search
  137. if @search.class == Array
  138. @search = @search.map {|arg| Name::Label.split(arg) }
  139. else
  140. raise ArgumentError.new("invalid search config: search must be an array!")
  141. end
  142. else
  143. hostname = Socket.gethostname
  144. if /\./ =~ hostname
  145. @search = [Name::Label.split($')]
  146. else
  147. @search = [[]]
  148. end
  149. end
  150. if !@search.kind_of?(Array) ||
  151. # !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
  152. !@search.all? {|ls| ls.all? {|l| Name::Label === l } }
  153. raise ArgumentError.new("invalid search config: #{@search.inspect}")
  154. end
  155. end
  156. def check_ns(ns) #:nodoc: all
  157. if !ns.kind_of?(Array) ||
  158. !ns.all? {|n| (String === n || IPv4 === n || IPv6 === n)}
  159. raise ArgumentError.new("invalid nameserver config: #{ns.inspect}")
  160. end
  161. ns.each_index do |i|
  162. ns[i]=Config.resolve_server(ns[i])
  163. end
  164. end
  165. # Add a nameserver to the list of nameservers.
  166. #
  167. # Can take either a single String or an array of Strings.
  168. # The new nameservers are added at a higher priority.
  169. def add_nameserver(ns)
  170. if (ns.kind_of?String)
  171. ns=[ns]
  172. end
  173. check_ns(ns)
  174. ns.reverse_each do |n|
  175. if (!@nameserver.include?(n))
  176. self.nameserver=[n]+@nameserver
  177. end
  178. end
  179. end
  180. # Set the config to point to a single nameserver
  181. def nameserver=(ns)
  182. check_ns(ns)
  183. # @nameserver = ['0.0.0.0'] if (@nameserver.class != Array || @nameserver.empty?)
  184. # Now go through and ensure that all ns point to IP addresses, not domain names
  185. @nameserver=ns
  186. TheLog.debug("Nameservers = #{@nameserver.join(", ")}")
  187. end
  188. def Config.resolve_server(ns) #:nodoc: all
  189. # Sanity check server
  190. # If it's an IP address, then use that for server
  191. # If it's a name, then we'll need to resolve it first
  192. server=ns
  193. begin
  194. addr = IPv4.create(ns)
  195. server = ns
  196. rescue Exception
  197. begin
  198. addr=IPv6.create(ns)
  199. server = ns
  200. rescue Exception
  201. begin
  202. # try to resolve server to address
  203. addr = TCPSocket.gethostbyname(ns)[3] # @TODO@ Replace this with Dnsruby call when lookups work
  204. server = addr
  205. rescue Exception => e
  206. TheLog.error("Can't make sense of nameserver : #{server}, exception : #{e}")
  207. raise ArgumentError.new("Can't make sense of nameserver : #{server}, exception : #{e}")
  208. end
  209. end
  210. end
  211. return server
  212. end
  213. def Config.parse_resolv_conf(filename) #:nodoc: all
  214. nameserver = []
  215. search = nil
  216. domain = nil
  217. ndots = 1
  218. open(filename) {|f|
  219. f.each {|line|
  220. line.sub!(/[#;].*/, '')
  221. keyword, *args = line.split(/\s+/)
  222. args.each { |arg|
  223. arg.untaint
  224. }
  225. next unless keyword
  226. case keyword
  227. when 'nameserver'
  228. nameserver += args
  229. when 'domain'
  230. next if args.empty?
  231. domain = args[0]
  232. # if search == nil
  233. # search = []
  234. # end
  235. # search.push(args[0])
  236. when 'search'
  237. next if args.empty?
  238. if search == nil
  239. search = []
  240. end
  241. args.each {|a| search.push(a)}
  242. when 'options'
  243. args.each {|arg|
  244. case arg
  245. when /\Andots:(\d+)\z/
  246. ndots = $1.to_i
  247. end
  248. }
  249. end
  250. }
  251. }
  252. return { :nameserver => nameserver, :domain => domain, :search => search, :ndots => ndots }
  253. end
  254. def inspect #:nodoc: all
  255. to_s
  256. end
  257. def to_s
  258. ret = "Config - nameservers : "
  259. @nameserver.each {|n| ret += n.to_s + ", "}
  260. domain_string="empty"
  261. if (@domain!=nil)
  262. domain_string=@domain.to_s
  263. end
  264. ret += " domain : #{domain_string}, search : "
  265. search.each {|s| ret += s + ", " }
  266. ret += " ndots : #{@ndots}"
  267. return ret
  268. end
  269. def Config.default_config_hash(filename="/etc/resolv.conf") #:nodoc: all
  270. config_hash={}
  271. if File.exist? filename
  272. config_hash = Config.parse_resolv_conf(filename)
  273. else
  274. if (/java/ =~ RUBY_PLATFORM && !(filename=~/:/))
  275. # Problem with paths and Windows on JRuby - see if we can munge the drive...
  276. wd = Dir.getwd
  277. drive = wd.split(':')[0]
  278. if (drive.length==1)
  279. file = drive << ":" << filename
  280. if File.exist? file
  281. config_hash = Config.parse_resolv_conf(file)
  282. end
  283. end
  284. elsif /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
  285. # @TODO@ Need to get windows domain sorted
  286. search, nameserver = Win32::Resolv.get_resolv_info
  287. # config_hash[:domain] = domain if domain
  288. config_hash[:nameserver] = nameserver if nameserver
  289. config_hash[:search] = [search].flatten if search
  290. end
  291. end
  292. config_hash
  293. end
  294. # Return the search path
  295. def search
  296. search = []
  297. @search.each do |s|
  298. search.push(Name.new(s).to_s)
  299. end
  300. return search
  301. end
  302. # Return the default domain
  303. def domain
  304. if (@domain==nil)
  305. return nil
  306. end
  307. return Name.create(@domain).to_s
  308. end
  309. def single? #:nodoc: all
  310. if @nameserver.length == 1
  311. return @nameserver[0]
  312. else
  313. return nil
  314. end
  315. end
  316. def generate_candidates(name) #:nodoc: all
  317. candidates = []
  318. name = Name.create(name)
  319. if name.absolute?
  320. candidates = [name]
  321. else
  322. if (@apply_domain)
  323. if @ndots > name.length - 1
  324. candidates.push(Name.create(name.to_a+@domain))
  325. end
  326. end
  327. if (!@apply_search_list)
  328. candidates.push(Name.create(name.to_a))
  329. else
  330. if @ndots <= name.length - 1
  331. candidates.push(Name.create(name.to_a))
  332. end
  333. candidates.concat(@search.map {|domain| Name.create(name.to_a + domain)})
  334. if (name.length == 1)
  335. candidates.concat([Name.create(name.to_a)])
  336. end
  337. end
  338. end
  339. return candidates
  340. end
  341. end
  342. end