PageRenderTime 431ms CodeModel.GetById 393ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

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