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