/tools/Ruby/lib/ruby/1.8/win32/resolv.rb

http://github.com/agross/netopenspace · Ruby · 366 lines · 351 code · 8 blank · 7 comment · 8 complexity · bafc9529f12bbe7e15dacc1e10245806 MD5 · raw file

  1. =begin
  2. = Win32 DNS and DHCP I/F
  3. =end
  4. require 'win32/registry'
  5. module Win32
  6. module Resolv
  7. API = Registry::API
  8. def self.get_hosts_path
  9. path = get_hosts_dir
  10. path = File.expand_path('hosts', path)
  11. File.exist?(path) ? path : nil
  12. end
  13. def self.get_resolv_info
  14. search, nameserver = get_info
  15. if search.empty?
  16. search = nil
  17. else
  18. search.delete("")
  19. search.uniq!
  20. end
  21. if nameserver.empty?
  22. nameserver = nil
  23. else
  24. nameserver.delete("")
  25. nameserver.delete("0.0.0.0")
  26. nameserver.uniq!
  27. end
  28. [ search, nameserver ]
  29. end
  30. getv = Win32API.new('kernel32.dll', 'GetVersionExA', 'P', 'L')
  31. info = [ 148, 0, 0, 0, 0 ].pack('V5') + "\0" * 128
  32. getv.call(info)
  33. if info.unpack('V5')[4] == 2 # VER_PLATFORM_WIN32_NT
  34. #====================================================================
  35. # Windows NT
  36. #====================================================================
  37. module_eval <<-'__EOS__', __FILE__, __LINE__+1
  38. TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
  39. class << self
  40. private
  41. def get_hosts_dir
  42. Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
  43. reg.read_s_expand('DataBasePath')
  44. end
  45. end
  46. def get_info
  47. search = nil
  48. nameserver = []
  49. Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
  50. begin
  51. slist = reg.read_s('SearchList')
  52. search = slist.split(/,\s*/) unless slist.empty?
  53. rescue Registry::Error
  54. end
  55. if add_search = search.nil?
  56. search = []
  57. begin
  58. nvdom = reg.read_s('NV Domain')
  59. unless nvdom.empty?
  60. @search = [ nvdom ]
  61. if reg.read_i('UseDomainNameDevolution') != 0
  62. if /^[\w\d]+\./ =~ nvdom
  63. devo = $'
  64. end
  65. end
  66. end
  67. rescue Registry::Error
  68. end
  69. end
  70. reg.open('Interfaces') do |reg|
  71. reg.each_key do |iface,|
  72. reg.open(iface) do |regif|
  73. begin
  74. [ 'NameServer', 'DhcpNameServer' ].each do |key|
  75. ns = regif.read_s(key)
  76. unless ns.empty?
  77. nameserver.concat(ns.split(/[,\s]\s*/))
  78. break
  79. end
  80. end
  81. rescue Registry::Error
  82. end
  83. if add_search
  84. begin
  85. [ 'Domain', 'DhcpDomain' ].each do |key|
  86. dom = regif.read_s(key)
  87. unless dom.empty?
  88. search.concat(dom.split(/,\s*/))
  89. break
  90. end
  91. end
  92. rescue Registry::Error
  93. end
  94. end
  95. end
  96. end
  97. end
  98. search << devo if add_search and devo
  99. end
  100. [ search.uniq, nameserver.uniq ]
  101. end
  102. end
  103. __EOS__
  104. else
  105. #====================================================================
  106. # Windows 9x
  107. #====================================================================
  108. module_eval <<-'__EOS__', __FILE__, __LINE__+1
  109. TCPIP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\MSTCP'
  110. DHCP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\DHCP'
  111. WINDOWS = 'Software\Microsoft\Windows\CurrentVersion'
  112. class << self
  113. # private
  114. def get_hosts_dir
  115. Registry::HKEY_LOCAL_MACHINE.open(WINDOWS) do |reg|
  116. reg.read_s_expand('SystemRoot')
  117. end
  118. end
  119. def get_info
  120. search = []
  121. nameserver = []
  122. begin
  123. Registry::HKEY_LOCAL_MACHINE.open(TCPIP_9X) do |reg|
  124. if reg.read_s("EnableDNS") == "1"
  125. domain = reg.read_s("Domain")
  126. ns = reg.read_s("NameServer")
  127. slist = reg.read_s("SearchList")
  128. search << domain unless domain.empty?
  129. search.concat(slist.split(/,\s*/))
  130. nameserver.concat(ns.split(/[,\s]\s*/))
  131. end
  132. end
  133. rescue Registry::Error
  134. end
  135. dhcpinfo = get_dhcpinfo
  136. search.concat(dhcpinfo[0])
  137. nameserver.concat(dhcpinfo[1])
  138. [ search, nameserver ]
  139. end
  140. def get_dhcpinfo
  141. macaddrs = {}
  142. ipaddrs = {}
  143. WsControl.get_iflist.each do |index, macaddr, *ipaddr|
  144. macaddrs[macaddr] = 1
  145. ipaddr.each { |ipaddr| ipaddrs[ipaddr] = 1 }
  146. end
  147. iflist = [ macaddrs, ipaddrs ]
  148. search = []
  149. nameserver = []
  150. version = -1
  151. Registry::HKEY_LOCAL_MACHINE.open(DHCP_9X) do |reg|
  152. begin
  153. version = API.unpackdw(reg.read_bin("Version"))
  154. rescue Registry::Error
  155. end
  156. reg.each_key do |key,|
  157. catch(:not_used) do
  158. reg.open(key) do |regdi|
  159. dom, ns = get_dhcpinfo_key(version, regdi, iflist)
  160. search << dom if dom
  161. nameserver.concat(ns) if ns
  162. end
  163. end
  164. end
  165. end
  166. [ search, nameserver ]
  167. end
  168. def get_dhcpinfo_95(reg)
  169. dhcp = reg.read_bin("DhcpInfo")
  170. [
  171. API.unpackdw(dhcp[4..7]),
  172. API.unpackdw(dhcp[8..11]),
  173. 1,
  174. dhcp[45..50],
  175. reg.read_bin("OptionInfo"),
  176. ]
  177. end
  178. def get_dhcpinfo_98(reg)
  179. [
  180. API.unpackdw(reg.read_bin("DhcpIPAddress")),
  181. API.unpackdw(reg.read_bin("DhcpSubnetMask")),
  182. API.unpackdw(reg.read_bin("HardwareType")),
  183. reg.read_bin("HardwareAddress"),
  184. reg.read_bin("OptionInfo"),
  185. ]
  186. end
  187. def get_dhcpinfo_key(version, reg, iflist)
  188. info = case version
  189. when 1
  190. get_dhcpinfo_95(reg)
  191. when 2
  192. get_dhcpinfo_98(reg)
  193. else
  194. begin
  195. get_dhcpinfo_98(reg)
  196. rescue Registry::Error
  197. get_dhcpinfo_95(reg)
  198. end
  199. end
  200. ipaddr, netmask, hwtype, macaddr, opt = info
  201. throw :not_used unless
  202. ipaddr and ipaddr != 0 and
  203. netmask and netmask != 0 and
  204. macaddr and macaddr.size == 6 and
  205. hwtype == 1 and
  206. iflist[0][macaddr] and iflist[1][ipaddr]
  207. size = opt.size
  208. idx = 0
  209. while idx <= size
  210. opttype = opt[idx]
  211. optsize = opt[idx + 1]
  212. optval = opt[idx + 2, optsize]
  213. case opttype
  214. when 0xFF ## term
  215. break
  216. when 0x0F ## domain
  217. domain = optval.chomp("\0")
  218. when 0x06 ## dns
  219. nameserver = optval.scan(/..../).collect { |addr|
  220. "%d.%d.%d.%d" % addr.unpack('C4')
  221. }
  222. end
  223. idx += optsize + 2
  224. end
  225. [ domain, nameserver ]
  226. rescue Registry::Error
  227. throw :not_used
  228. end
  229. end
  230. module WsControl
  231. WsControl = Win32API.new('wsock32.dll', 'WsControl', 'LLPPPP', 'L')
  232. WSAGetLastError = Win32API.new('wsock32.dll', 'WSAGetLastError', 'V', 'L')
  233. MAX_TDI_ENTITIES = 512
  234. IPPROTO_TCP = 6
  235. WSCTL_TCP_QUERY_INFORMATION = 0
  236. INFO_CLASS_GENERIC = 0x100
  237. INFO_CLASS_PROTOCOL = 0x200
  238. INFO_TYPE_PROVIDER = 0x100
  239. ENTITY_LIST_ID = 0
  240. GENERIC_ENTITY = 0
  241. CL_NL_ENTITY = 0x301
  242. IF_ENTITY = 0x200
  243. ENTITY_TYPE_ID = 1
  244. CL_NL_IP = 0x303
  245. IF_MIB = 0x202
  246. IF_MIB_STATS_ID = 1
  247. IP_MIB_ADDRTABLE_ENTRY_ID = 0x102
  248. def self.wsctl(tei_entity, tei_instance,
  249. toi_class, toi_type, toi_id,
  250. buffsize)
  251. reqinfo = [
  252. ## TDIEntityID
  253. tei_entity, tei_instance,
  254. ## TDIObjectID
  255. toi_class, toi_type, toi_id,
  256. ## TCP_REQUEST_INFORMATION_EX
  257. ""
  258. ].pack('VVVVVa16')
  259. reqsize = API.packdw(reqinfo.size)
  260. buff = "\0" * buffsize
  261. buffsize = API.packdw(buffsize)
  262. result = WsControl.call(
  263. IPPROTO_TCP,
  264. WSCTL_TCP_QUERY_INFORMATION,
  265. reqinfo, reqsize,
  266. buff, buffsize)
  267. if result != 0
  268. raise RuntimeError, "WsControl failed.(#{result})"
  269. end
  270. [ buff, API.unpackdw(buffsize) ]
  271. end
  272. private_class_method :wsctl
  273. def self.get_iflist
  274. # Get TDI Entity List
  275. entities, size =
  276. wsctl(GENERIC_ENTITY, 0,
  277. INFO_CLASS_GENERIC,
  278. INFO_TYPE_PROVIDER,
  279. ENTITY_LIST_ID,
  280. MAX_TDI_ENTITIES * 8) # sizeof(TDIEntityID)
  281. entities = entities[0, size].
  282. scan(/.{8}/).
  283. collect { |e| e.unpack('VV') }
  284. # Get MIB Interface List
  285. iflist = []
  286. ifcount = 0
  287. entities.each do |entity, instance|
  288. if( (entity & IF_ENTITY)>0 )
  289. ifcount += 1
  290. etype, = wsctl(entity, instance,
  291. INFO_CLASS_GENERIC,
  292. INFO_TYPE_PROVIDER,
  293. ENTITY_TYPE_ID,
  294. 4)
  295. if( (API.unpackdw(etype) & IF_MIB)==IF_MIB )
  296. ifentry, = wsctl(entity, instance,
  297. INFO_CLASS_PROTOCOL,
  298. INFO_TYPE_PROVIDER,
  299. IF_MIB_STATS_ID,
  300. 21 * 4 + 8 + 130) # sizeof(IFEntry)
  301. iflist << [
  302. API.unpackdw(ifentry[0,4]),
  303. ifentry[20, 6]
  304. ]
  305. end
  306. end
  307. end
  308. # Get IP Addresses
  309. entities.each do |entity, instance|
  310. if entity == CL_NL_ENTITY
  311. etype, = wsctl(entity, instance,
  312. INFO_CLASS_GENERIC,
  313. INFO_TYPE_PROVIDER,
  314. ENTITY_TYPE_ID,
  315. 4)
  316. if API.unpackdw(etype) == CL_NL_IP
  317. ipentries, = wsctl(entity, instance,
  318. INFO_CLASS_PROTOCOL,
  319. INFO_TYPE_PROVIDER,
  320. IP_MIB_ADDRTABLE_ENTRY_ID,
  321. 24 * (ifcount+1)) # sizeof(IPAddrEntry)
  322. ipentries.scan(/.{24}/) do |ipentry|
  323. ipaddr, index = ipentry.unpack('VV')
  324. if ifitem = iflist.assoc(index)
  325. ifitem << ipaddr
  326. end
  327. end
  328. end
  329. end
  330. end
  331. iflist
  332. end
  333. end
  334. __EOS__
  335. end
  336. #====================================================================
  337. end
  338. end