Re: Changing Resolv::DNS

From: "Daniel Hobe" <daniel@...>
Date: 2004-05-05 20:41:21 UTC
List: ruby-core #2847
I like this.  Creates a more unified Resolv class.

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


-- 
Daniel Hobe <daniel@nightrunner.com>

In This Thread