Re: Changing Resolv::DNS

From: Tanaka Akira <akr@...17n.org>
Date: 2004-05-04 07:30:32 UTC
List: ruby-core #2842
In article <200405011554.53670.daniel@nightrunner.com>,
  Daniel Hobe <daniel@nightrunner.com> writes:

> Resolv::DNS.new('/etc/foo')
> -or-
> Resolv::DNS.new({nameserver=>['192.168.10.1','192.168.10.2'],
>                  search=>['ruby-lang.org','ruby-doc.org'],
>                  ndots => 2})

I feel this initialization style is good enough.

However I'd like to just change Config instead of defining a subclass.

Index: lib/resolv.rb
===================================================================
RCS file: /src/ruby/lib/resolv.rb,v
retrieving revision 1.19
diff -u -r1.19 resolv.rb
--- lib/resolv.rb	23 Apr 2004 05:22:24 -0000	1.19
+++ lib/resolv.rb	4 May 2004 07:26:35 -0000
@@ -10,9 +10,10 @@
   Resolv.getaddress("www.ruby-lang.org")
   Resolv.getname("210.251.121.214")
 
-  dns = Resolv::DNS.new
-  dns.getresources("www.ruby-lang.org", Resolv::DNS::Resource::IN::A).collect {|r| r.address}
-  dns.getresources("ruby-lang.org", Resolv::DNS::Resource::IN::MX).collect {|r| [r.exchange.to_s, r.preference]}
+  Resolv::DNS.open {|dns|
+    dns.getresources("www.ruby-lang.org", Resolv::DNS::Resource::IN::A).collect {|r| r.address}
+    dns.getresources("ruby-lang.org", Resolv::DNS::Resource::IN::MX).collect {|r| [r.exchange.to_s, r.preference]}
+  }
 
 == Resolv class
 
@@ -57,10 +58,17 @@
 DNS stub resolver.
 
 === class methods
---- Resolv::DNS.new(resolv_conf='/etc/resolv.conf')
+--- Resolv::DNS.new(config_info=nil)
 
---- Resolv::DNS.open(resolv_conf='/etc/resolv.conf')
---- Resolv::DNS.open(resolv_conf='/etc/resolv.conf') {|dns| ...}
+    ((|config_info|)) should be nil, a string or a hash.
+    If nil is given, /etc/resolv.conf and platform specific information is used.
+    If a string is given, it should be a filename which format is same as /etc/resolv.conf.
+    If a hash is given, it may contains information for nameserver, search and ndots as follows.
+
+      Resolv::DNS.new({:nameserver=>["210.251.121.21"], :search=>["ruby-lang.org"], :ndots=>1})
+
+--- Resolv::DNS.open(config_info=nil)
+--- Resolv::DNS.open(config_info=nil) {|dns| ...}
 
 === methods
 --- Resolv::DNS#close
@@ -369,9 +377,9 @@
       end
     end
 
-    def initialize(config="/etc/resolv.conf")
+    def initialize(config_info=nil)
       @mutex = Mutex.new
-      @config = Config.new(config)
+      @config = Config.new(config_info)
       @initialized = nil
     end
 
@@ -704,47 +712,81 @@
     end
 
     class Config
-      def initialize(filename="/etc/resolv.conf")
+      def initialize(config_info=nil)
         @mutex = Mutex.new
-        @filename = filename
+        @config_info = config_info
         @initialized = nil
       end
 
+      def Config.parse_resolv_conf(filename)
+        nameserver = []
+        search = nil
+        ndots = 1
+        open(filename) {|f|
+          f.each {|line|
+            line.sub!(/[#;].*/, '')
+            keyword, *args = line.split(/\s+/)
+            args.each { |arg|
+              arg.untaint
+            }
+            next unless keyword
+            case keyword
+            when 'nameserver'
+              nameserver += args
+            when 'domain'
+              search = [args[0]]
+            when 'search'
+              search = args
+            end
+          }
+        }
+        return { :nameserver => nameserver, :search => search, :ndots => ndots }
+      end
+
+      def Config.default_config_hash(filename="/etc/resolv.conf")
+        if File.exist? filename
+          config_hash = Config.parse_resolv_conf(filename)
+        else
+          if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
+            search, nameserver = Win32::Resolv.get_resolv_info
+            config_hash = {}
+            config_hash[:nameserver] = nameserver if nameserver
+            config_hash[:search] = [search] if search
+          end
+        end
+        config_hash
+      end
+
       def lazy_initialize
         @mutex.synchronize {
           unless @initialized
             @nameserver = []
             @search = nil
             @ndots = 1
-            begin
-              open(@filename) {|f|
-                f.each {|line|
-                  line.sub!(/[#;].*/, '')
-                  keyword, *args = line.split(/\s+/)
-                  args.each { |arg|
-                    arg.untaint
-                  }
-                  next unless keyword
-                  case keyword
-                  when 'nameserver'
-                    @nameserver += args
-                  when 'domain'
-                    @search = [Label.split(args[0])]
-                  when 'search'
-                    @search = args.map {|arg| Label.split(arg)}
-                  end
-                }
-              }
-            rescue Errno::ENOENT
-              if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
-                search, nameserver = Win32::Resolv.get_resolv_info
-                @search = [search] if search
-                @nameserver = nameserver if nameserver
+            case @config_info
+            when nil
+              config_hash = Config.default_config_hash
+            when String
+              config_hash = Config.parse_resolv_conf(@config_info)
+            when Hash
+              config_hash = @config_info.dup
+              if String === config_hash[:nameserver]
+                config_hash[:nameserver] = [config_hash[:nameserver]]
               end
+              if String === config_hash[:search]
+                config_hash[:search] = [config_hash[:search]]
+              end
+            else
+              raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
             end
+            @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
+            @search = config_hash[:search] if config_hash.include? :search
+            @ndots = config_hash[:ndots] if config_hash.include? :ndots
 
             @nameserver = ['0.0.0.0'] if @nameserver.empty?
-            unless @search
+            if @search
+              @search = @search.map {|arg| Label.split(arg) }
+            else
               hostname = Socket.gethostname
               if /\./ =~ hostname
                 @search = [Label.split($')]
@@ -752,6 +794,21 @@
                 @search = [[]]
               end
             end
+
+            if !@nameserver.kind_of?(Array) ||
+               !@nameserver.all? {|ns| String === ns }
+              raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
+            end
+
+            if !@search.kind_of?(Array) ||
+               !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
+              raise ArgumentError.new("invalid search config: #{@search.inspect}")
+            end
+
+            if !@ndots.kind_of?(Integer)
+              raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
+            end
+
             @initialized = true
           end
         }
-- 
Tanaka Akira

In This Thread