summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--ext/Win32API/MANIFEST1
-rw-r--r--ext/Win32API/lib/win32/resolv.rb366
-rw-r--r--lib/resolv.rb92
4 files changed, 424 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 9a0fdd1a76..8687b17210 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Jul 24 09:58:32 2003 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/Win32API/lib/win32/resolv.rb: added.
+
+ * lib/resolv.rb: support Win32 platforms.
+
Thu Jul 24 04:05:46 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
* ext/openssl/ssl.h: undef X509_NAME and PKCS7_SIGNER_INFO to
diff --git a/ext/Win32API/MANIFEST b/ext/Win32API/MANIFEST
index 3163f6beec..ff3a399d26 100644
--- a/ext/Win32API/MANIFEST
+++ b/ext/Win32API/MANIFEST
@@ -6,3 +6,4 @@ extconf.rb
getch.rb
point.rb
lib/win32/registry.rb
+lib/win32/resolv.rb
diff --git a/ext/Win32API/lib/win32/resolv.rb b/ext/Win32API/lib/win32/resolv.rb
new file mode 100644
index 0000000000..5a99d04d55
--- /dev/null
+++ b/ext/Win32API/lib/win32/resolv.rb
@@ -0,0 +1,366 @@
+=begin
+= Win32 DNS and DHCP I/F
+
+=end
+
+require 'win32/registry'
+
+module Win32
+ module Resolv
+ API = Registry::API
+
+ def self.get_hosts_path
+ path = get_hosts_dir
+ path = File.join(path.gsub(/\\/, File::SEPARATOR), 'hosts')
+ File.exist?(path) ? path : nil
+ end
+
+ def self.get_resolv_info
+ search, nameserver = get_info
+ if search.empty?
+ search = nil
+ else
+ search.delete("")
+ search.uniq!
+ end
+ if nameserver.empty?
+ nameserver = nil
+ else
+ nameserver.delete("")
+ nameserver.delete("0.0.0.0")
+ nameserver.uniq!
+ end
+ [ search, nameserver ]
+ end
+
+getv = Win32API.new('kernel32.dll', 'GetVersionExA', 'P', 'L')
+info = [ 148, 0, 0, 0, 0 ].pack('V5') + "\0" * 128
+getv.call(info)
+if info.unpack('V5')[4] == 2 # VER_PLATFORM_WIN32_NT
+#====================================================================
+# Windows NT
+#====================================================================
+ module_eval <<-'__EOS__', __FILE__, __LINE__+1
+ TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
+
+ class << self
+ private
+ def get_hosts_dir
+ Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
+ reg.read_s_expand('DataBasePath')
+ end
+ end
+
+ def get_info
+ search = nil
+ nameserver = []
+ Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
+ begin
+ slist = reg.read_s('SearchList')
+ search = slist.split(/,\s*/) unless slist.empty?
+ rescue Registry::Error
+ end
+
+ if add_search = search.nil?
+ search = []
+ begin
+ nvdom = reg.read_s('NV Domain')
+ unless nvdom.empty?
+ @search = [ nvdom ]
+ if reg.read_i('UseDomainNameDevolution') != 0
+ if /^[\w\d]+\./ =~ nvdom
+ devo = $'
+ end
+ end
+ end
+ rescue Registry::Error
+ end
+ end
+
+ reg.open('Interfaces') do |reg|
+ reg.each_key do |iface,|
+ reg.open(iface) do |regif|
+ begin
+ [ 'NameServer', 'DhcpNameServer' ].each do |key|
+ ns = regif.read_s(key)
+ unless ns.empty?
+ nameserver.concat(ns.split(/\s+/))
+ break
+ end
+ end
+ rescue Registry::Error
+ end
+
+ if add_search
+ begin
+ [ 'Domain', 'DhcpDomain' ].each do |key|
+ dom = regif.read_s(key)
+ unless dom.empty?
+ search.concat(dom.split(/,\s*/))
+ break
+ end
+ end
+ rescue Registry::Error
+ end
+ end
+ end
+ end
+ end
+ search << devo if add_search and devo
+ end
+ [ search.uniq, nameserver.uniq ]
+ end
+ end
+ __EOS__
+else
+#====================================================================
+# Windows 9x
+#====================================================================
+ module_eval <<-'__EOS__', __FILE__, __LINE__+1
+ TCPIP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\MSTCP'
+ DHCP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\DHCP'
+ WINDOWS = 'Software\Microsoft\Windows\CurrentVersion'
+
+ class << self
+ # private
+
+ def get_hosts_dir
+ Registry::HKEY_LOCAL_MACHINE.open(WINDOWS) do |reg|
+ reg.read_s_expand('SystemRoot')
+ end
+ end
+
+ def get_info
+ search = []
+ nameserver = []
+ begin
+ Registry::HKEY_LOCAL_MACHINE.open(TCPIP_9X) do |reg|
+ if reg.read_s("EnableDNS") == "1"
+ domain = reg.read_s("Domain")
+ ns = reg.read_s("NameServer")
+ slist = reg.read_s("SearchList")
+ search << domain unless domain.empty?
+ search.concat(slist.split(/,\s*/))
+ nameserver.concat(ns.split(/,\s*/))
+ end
+ end
+ rescue Registry::Error
+ end
+
+ dhcpinfo = get_dhcpinfo
+ search.concat(dhcpinfo[0])
+ nameserver.concat(dhcpinfo[1])
+ [ search, nameserver ]
+ end
+
+ def get_dhcpinfo
+ macaddrs = {}
+ ipaddrs = {}
+ WsControl.get_iflist.each do |index, macaddr, *ipaddr|
+ macaddrs[macaddr] = 1
+ ipaddr.each { |ipaddr| ipaddrs[ipaddr] = 1 }
+ end
+ iflist = [ macaddrs, ipaddrs ]
+
+ search = []
+ nameserver = []
+ version = -1
+ Registry::HKEY_LOCAL_MACHINE.open(DHCP_9X) do |reg|
+ begin
+ version = API.unpackdw(reg.read_bin("Version"))
+ rescue Registry::Error
+ end
+
+ reg.each_key do |key,|
+ catch(:not_used) do
+ reg.open(key) do |regdi|
+ dom, ns = get_dhcpinfo_key(version, regdi, iflist)
+ search << dom if dom
+ nameserver.concat(ns) if ns
+ end
+ end
+ end
+ end
+ [ search, nameserver ]
+ end
+
+ def get_dhcpinfo_95(reg)
+ dhcp = reg.read_bin("DhcpInfo")
+ [
+ API.unpackdw(dhcp[4..7]),
+ API.unpackdw(dhcp[8..11]),
+ 1,
+ dhcp[45..50],
+ reg.read_bin("OptionInfo"),
+ ]
+ end
+
+ def get_dhcpinfo_98(reg)
+ [
+ API.unpackdw(reg.read_bin("DhcpIPAddress")),
+ API.unpackdw(reg.read_bin("DhcpSubnetMask")),
+ API.unpackdw(reg.read_bin("HardwareType")),
+ reg.read_bin("HardwareAddress"),
+ reg.read_bin("OptionInfo"),
+ ]
+ end
+
+ def get_dhcpinfo_key(version, reg, iflist)
+ info = case version
+ when 1
+ get_dhcpinfo_95(reg)
+ when 2
+ get_dhcpinfo_98(reg)
+ else
+ begin
+ get_dhcpinfo_98(reg)
+ rescue Registry::Error
+ get_dhcpinfo_95(reg)
+ end
+ end
+ ipaddr, netmask, hwtype, macaddr, opt = info
+ throw :not_used unless
+ ipaddr and ipaddr != 0 and
+ netmask and netmask != 0 and
+ macaddr and macaddr.size == 6 and
+ hwtype == 1 and
+ iflist[0][macaddr] and iflist[1][ipaddr]
+
+ size = opt.size
+ idx = 0
+ while idx <= size
+ opttype = opt[idx]
+ optsize = opt[idx + 1]
+ optval = opt[idx + 2, optsize]
+ case opttype
+ when 0xFF ## term
+ break
+ when 0x0F ## domain
+ domain = optval.chomp("\0")
+ when 0x06 ## dns
+ nameserver = optval.scan(/..../).collect { |addr|
+ "%d.%d.%d.%d" % addr.unpack('C4')
+ }
+ end
+ idx += optsize + 2
+ end
+ [ domain, nameserver ]
+ rescue Registry::Error
+ throw :not_used
+ end
+ end
+
+ module WsControl
+ WsControl = Win32API.new('wsock32.dll', 'WsControl', 'LLPPPP', 'L')
+ WSAGetLastError = Win32API.new('wsock32.dll', 'WSAGetLastError', 'V', 'L')
+
+ MAX_TDI_ENTITIES = 512
+ IPPROTO_TCP = 6
+ WSCTL_TCP_QUERY_INFORMATION = 0
+ INFO_CLASS_GENERIC = 0x100
+ INFO_CLASS_PROTOCOL = 0x200
+ INFO_TYPE_PROVIDER = 0x100
+ ENTITY_LIST_ID = 0
+ GENERIC_ENTITY = 0
+ CL_NL_ENTITY = 0x301
+ IF_ENTITY = 0x200
+ ENTITY_TYPE_ID = 1
+ CL_NL_IP = 0x303
+ IF_MIB = 0x202
+ IF_MIB_STATS_ID = 1
+ IP_MIB_ADDRTABLE_ENTRY_ID = 0x102
+
+ def self.wsctl(tei_entity, tei_instance,
+ toi_class, toi_type, toi_id,
+ buffsize)
+ reqinfo = [
+ ## TDIEntityID
+ tei_entity, tei_instance,
+ ## TDIObjectID
+ toi_class, toi_type, toi_id,
+ ## TCP_REQUEST_INFORMATION_EX
+ ""
+ ].pack('VVVVVa16')
+ reqsize = API.packdw(reqinfo.size)
+ buff = "\0" * buffsize
+ buffsize = API.packdw(buffsize)
+ result = WsControl.call(
+ IPPROTO_TCP,
+ WSCTL_TCP_QUERY_INFORMATION,
+ reqinfo, reqsize,
+ buff, buffsize)
+ if result != 0
+ raise RuntimeError, "WsControl failed.(#{result})"
+ end
+ [ buff, API.unpackdw(buffsize) ]
+ end
+ private_class_method :wsctl
+
+ def self.get_iflist
+ # Get TDI Entity List
+ entities, size =
+ wsctl(GENERIC_ENTITY, 0,
+ INFO_CLASS_GENERIC,
+ INFO_TYPE_PROVIDER,
+ ENTITY_LIST_ID,
+ MAX_TDI_ENTITIES * 8) # sizeof(TDIEntityID)
+ entities = entities[0, size].
+ scan(/.{8}/).
+ collect { |e| e.unpack('VV') }
+
+ # Get MIB Interface List
+ iflist = []
+ ifcount = 0
+ entities.each do |entity, instance|
+ if( (entity & IF_ENTITY)>0 )
+ ifcount += 1
+ etype, = wsctl(entity, instance,
+ INFO_CLASS_GENERIC,
+ INFO_TYPE_PROVIDER,
+ ENTITY_TYPE_ID,
+ 4)
+ if( (API.unpackdw(etype) & IF_MIB)==IF_MIB )
+ ifentry, = wsctl(entity, instance,
+ INFO_CLASS_PROTOCOL,
+ INFO_TYPE_PROVIDER,
+ IF_MIB_STATS_ID,
+ 21 * 4 + 8 + 130) # sizeof(IFEntry)
+ iflist << [
+ API.unpackdw(ifentry[0,4]),
+ ifentry[20, 6]
+ ]
+ end
+ end
+ end
+
+ # Get IP Addresses
+ entities.each do |entity, instance|
+ if entity == CL_NL_ENTITY
+ etype, = wsctl(entity, instance,
+ INFO_CLASS_GENERIC,
+ INFO_TYPE_PROVIDER,
+ ENTITY_TYPE_ID,
+ 4)
+ if API.unpackdw(etype) == CL_NL_IP
+ ipentries, = wsctl(entity, instance,
+ INFO_CLASS_PROTOCOL,
+ INFO_TYPE_PROVIDER,
+ IP_MIB_ADDRTABLE_ENTRY_ID,
+ 24 * (ifcount+1)) # sizeof(IPAddrEntry)
+ ipentries.scan(/.{24}/) do |ipentry|
+ ipaddr, index = ipentry.unpack('VV')
+ if ifitem = iflist.assoc(index)
+ ifitem << ipaddr
+ end
+ end
+ end
+ end
+ end
+ iflist
+ end
+ end
+ __EOS__
+end
+#====================================================================
+ end
+end
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 23356a2272..6dac504747 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -235,7 +235,7 @@ class Resolv
@resolvers.each {|r|
r.each_address(name) {|address|
yield address.to_s
- yielded = true
+ yielded = true
}
return if yielded
}
@@ -257,7 +257,7 @@ class Resolv
@resolvers.each {|r|
r.each_name(address) {|name|
yield name.to_s
- yielded = true
+ yielded = true
}
return if yielded
}
@@ -270,7 +270,12 @@ class Resolv
end
class Hosts
- DefaultFileName = '/etc/hosts'
+ if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
+ require 'win32/resolv'
+ DefaultFileName = Win32::Resolv.get_hosts_path
+ else
+ DefaultFileName = '/etc/hosts'
+ end
def initialize(filename = DefaultFileName)
@filename = filename
@@ -288,15 +293,15 @@ class Resolv
line.sub!(/#.*/, '')
addr, hostname, *aliases = line.split(/\s+/)
next unless addr
- addr.untaint
- hostname.untaint
+ addr.untaint
+ hostname.untaint
@addr2name[addr] = [] unless @addr2name.include? addr
@addr2name[addr] << hostname
@addr2name[addr] += aliases
@name2addr[hostname] = [] unless @name2addr.include? hostname
@name2addr[hostname] << addr
aliases.each {|n|
- n.untaint
+ n.untaint
@name2addr[n] = [] unless @name2addr.include? n
@name2addr[n] << addr
}
@@ -322,7 +327,7 @@ class Resolv
def each_address(name, &proc)
lazy_initialize
if @name2addr.include?(name)
- @name2addr[name].each(&proc)
+ @name2addr[name].each(&proc)
end
end
@@ -358,9 +363,9 @@ class Resolv
dns = new(*args)
return dns unless block_given?
begin
- yield dns
+ yield dns
ensure
- dns.close
+ dns.close
end
end
@@ -466,7 +471,7 @@ class Resolv
case reply.rcode
when RCode::NoError
extract_resources(reply, reply_name, typeclass, &proc)
- return
+ return
when RCode::NXDomain
raise Config::NXDomain.new(reply_name.to_s)
else
@@ -480,10 +485,10 @@ class Resolv
def extract_resources(msg, name, typeclass)
if typeclass < Resource::ANY
- n0 = Name.create(name)
+ n0 = Name.create(name)
msg.each_answer {|n, ttl, data|
- yield data if n0 == n
- }
+ yield data if n0 == n
+ }
end
yielded = false
n0 = Name.create(name)
@@ -491,8 +496,8 @@ class Resolv
if n0 == n
case data
when typeclass
- yield data
- yielded = true
+ yield data
+ yielded = true
when Resource::CNAME
n0 = data.name
end
@@ -503,7 +508,7 @@ class Resolv
if n0 == n
case data
when typeclass
- yield data
+ yield data
end
end
}
@@ -555,11 +560,11 @@ class Resolv
def initialize
super()
@sock = UDPSocket.new
- @sock.fcntl(Fcntl::F_SETFD, 1)
+ @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
@id = {}
@id.default = -1
@thread = Thread.new {
- DNSThreadGroup.add Thread.current
+ DNSThreadGroup.add Thread.current
loop {
reply, from = @sock.recvfrom(UDPSize)
msg = begin
@@ -608,10 +613,10 @@ class Resolv
@port = port
@sock = UDPSocket.new
@sock.connect(host, port)
- @sock.fcntl(Fcntl::F_SETFD, 1)
+ @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
@id = -1
@thread = Thread.new {
- DNSThreadGroup.add Thread.current
+ DNSThreadGroup.add Thread.current
loop {
reply = @sock.recv(UDPSize)
msg = begin
@@ -653,11 +658,11 @@ class Resolv
@port = port
@sock = TCPSocket.new
@sock.connect(host, port)
- @sock.fcntl(Fcntl::F_SETFD, 1)
+ @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
@id = -1
@senders = {}
@thread = Thread.new {
- DNSThreadGroup.add Thread.current
+ DNSThreadGroup.add Thread.current
loop {
len = @sock.read(2).unpack('n')
reply = @sock.read(len)
@@ -702,7 +707,7 @@ class Resolv
def initialize(filename="/etc/resolv.conf")
@mutex = Mutex.new
@filename = filename
- @initialized = nil
+ @initialized = nil
end
def lazy_initialize
@@ -716,9 +721,9 @@ class Resolv
f.each {|line|
line.sub!(/[#;].*/, '')
keyword, *args = line.split(/\s+/)
- args.each { |arg|
- arg.untaint
- }
+ args.each { |arg|
+ arg.untaint
+ }
next unless keyword
case keyword
when 'nameserver'
@@ -731,6 +736,11 @@ class Resolv
}
}
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
+ end
end
@nameserver = ['0.0.0.0'] if @nameserver.empty?
@@ -758,17 +768,17 @@ class Resolv
def generate_candidates(name)
candidates = nil
- name = Name.create(name)
- if name.absolute?
+ name = Name.create(name)
+ if name.absolute?
candidates = [name]
- else
- if @ndots <= name.length - 1
- candidates = [Name.new(name.to_a)]
- else
- candidates = []
- end
- candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
- end
+ else
+ if @ndots <= name.length - 1
+ candidates = [Name.new(name.to_a)]
+ else
+ candidates = []
+ end
+ candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
+ end
return candidates
end
@@ -866,9 +876,9 @@ class Resolv
return @string
end
- def inspect
- return "#<#{self.class} #{self.to_s}>"
- end
+ def inspect
+ return "#<#{self.class} #{self.to_s}>"
+ end
def ==(other)
return @downcase == other.downcase
@@ -898,7 +908,7 @@ class Resolv
def initialize(labels, absolute=true)
@labels = labels
- @absolute = absolute
+ @absolute = absolute
end
def absolute?
@@ -1585,7 +1595,7 @@ class Resolv
class IPv6
Regex_8Hex = /\A
(?:[0-9A-Fa-f]{1,4}:){7}
- [0-9A-Fa-f]{1,4}
+ [0-9A-Fa-f]{1,4}
\z/x
Regex_CompressedHex = /\A