|  | // Copyright 2011 The Go Authors.  All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Network interface identification for Windows | 
|  |  | 
|  | package net | 
|  |  | 
|  | import ( | 
|  | "os" | 
|  | "syscall" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | func bytePtrToString(p *uint8) string { | 
|  | a := (*[10000]uint8)(unsafe.Pointer(p)) | 
|  | i := 0 | 
|  | for a[i] != 0 { | 
|  | i++ | 
|  | } | 
|  | return string(a[:i]) | 
|  | } | 
|  |  | 
|  | func getAdapterList() (*syscall.IpAdapterInfo, error) { | 
|  | b := make([]byte, 1000) | 
|  | l := uint32(len(b)) | 
|  | a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) | 
|  | e := syscall.GetAdaptersInfo(a, &l) | 
|  | if e == syscall.ERROR_BUFFER_OVERFLOW { | 
|  | b = make([]byte, l) | 
|  | a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) | 
|  | e = syscall.GetAdaptersInfo(a, &l) | 
|  | } | 
|  | if e != 0 { | 
|  | return nil, os.NewSyscallError("GetAdaptersInfo", e) | 
|  | } | 
|  | return a, nil | 
|  | } | 
|  |  | 
|  | func getInterfaceList() ([]syscall.InterfaceInfo, error) { | 
|  | s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) | 
|  | if e != nil { | 
|  | return nil, os.NewSyscallError("Socket", e) | 
|  | } | 
|  | defer syscall.Closesocket(s) | 
|  |  | 
|  | ii := [20]syscall.InterfaceInfo{} | 
|  | ret := uint32(0) | 
|  | size := uint32(unsafe.Sizeof(ii)) | 
|  | e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0) | 
|  | if e != nil { | 
|  | return nil, os.NewSyscallError("WSAIoctl", e) | 
|  | } | 
|  | c := ret / uint32(unsafe.Sizeof(ii[0])) | 
|  | return ii[:c-1], nil | 
|  | } | 
|  |  | 
|  | // If the ifindex is zero, interfaceTable returns mappings of all | 
|  | // network interfaces.  Otheriwse it returns a mapping of a specific | 
|  | // interface. | 
|  | func interfaceTable(ifindex int) ([]Interface, error) { | 
|  | ai, e := getAdapterList() | 
|  | if e != nil { | 
|  | return nil, e | 
|  | } | 
|  |  | 
|  | ii, e := getInterfaceList() | 
|  | if e != nil { | 
|  | return nil, e | 
|  | } | 
|  |  | 
|  | var ift []Interface | 
|  | for ; ai != nil; ai = ai.Next { | 
|  | index := ai.Index | 
|  | if ifindex == 0 || ifindex == int(index) { | 
|  | var flags Flags | 
|  |  | 
|  | row := syscall.MibIfRow{Index: index} | 
|  | e := syscall.GetIfEntry(&row) | 
|  | if e != 0 { | 
|  | return nil, os.NewSyscallError("GetIfEntry", e) | 
|  | } | 
|  |  | 
|  | for _, ii := range ii { | 
|  | ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr | 
|  | ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3]) | 
|  | ipl := &ai.IpAddressList | 
|  | for ipl != nil { | 
|  | ips := bytePtrToString(&ipl.IpAddress.String[0]) | 
|  | if ipv4.Equal(parseIPv4(ips)) { | 
|  | break | 
|  | } | 
|  | ipl = ipl.Next | 
|  | } | 
|  | if ipl == nil { | 
|  | continue | 
|  | } | 
|  | if ii.Flags&syscall.IFF_UP != 0 { | 
|  | flags |= FlagUp | 
|  | } | 
|  | if ii.Flags&syscall.IFF_LOOPBACK != 0 { | 
|  | flags |= FlagLoopback | 
|  | } | 
|  | if ii.Flags&syscall.IFF_BROADCAST != 0 { | 
|  | flags |= FlagBroadcast | 
|  | } | 
|  | if ii.Flags&syscall.IFF_POINTTOPOINT != 0 { | 
|  | flags |= FlagPointToPoint | 
|  | } | 
|  | if ii.Flags&syscall.IFF_MULTICAST != 0 { | 
|  | flags |= FlagMulticast | 
|  | } | 
|  | } | 
|  |  | 
|  | name := bytePtrToString(&ai.AdapterName[0]) | 
|  |  | 
|  | ifi := Interface{ | 
|  | Index:        int(index), | 
|  | MTU:          int(row.Mtu), | 
|  | Name:         name, | 
|  | HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]), | 
|  | Flags:        flags} | 
|  | ift = append(ift, ifi) | 
|  | } | 
|  | } | 
|  | return ift, nil | 
|  | } | 
|  |  | 
|  | // If the ifindex is zero, interfaceAddrTable returns addresses | 
|  | // for all network interfaces.  Otherwise it returns addresses | 
|  | // for a specific interface. | 
|  | func interfaceAddrTable(ifindex int) ([]Addr, error) { | 
|  | ai, e := getAdapterList() | 
|  | if e != nil { | 
|  | return nil, e | 
|  | } | 
|  |  | 
|  | var ifat []Addr | 
|  | for ; ai != nil; ai = ai.Next { | 
|  | index := ai.Index | 
|  | if ifindex == 0 || ifindex == int(index) { | 
|  | ipl := &ai.IpAddressList | 
|  | for ; ipl != nil; ipl = ipl.Next { | 
|  | ifa := IPAddr{} | 
|  | ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0])) | 
|  | ifat = append(ifat, ifa.toAddr()) | 
|  | } | 
|  | } | 
|  | } | 
|  | return ifat, nil | 
|  | } | 
|  |  | 
|  | // If the ifindex is zero, interfaceMulticastAddrTable returns | 
|  | // addresses for all network interfaces.  Otherwise it returns | 
|  | // addresses for a specific interface. | 
|  | func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { | 
|  | return nil, nil | 
|  | } |