github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/net/interface_windows.go (about)

     1  // Copyright 2011 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package net
     6  
     7  import (
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  func bytePtrToString(p *uint8) string {
    14  	a := (*[10000]uint8)(unsafe.Pointer(p))
    15  	i := 0
    16  	for a[i] != 0 {
    17  		i++
    18  	}
    19  	return string(a[:i])
    20  }
    21  
    22  func getAdapterList() (*syscall.IpAdapterInfo, error) {
    23  	b := make([]byte, 1000)
    24  	l := uint32(len(b))
    25  	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
    26  	// TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
    27  	// contains IPv4 address list only. We should use another API
    28  	// for fetching IPv6 stuff from the kernel.
    29  	err := syscall.GetAdaptersInfo(a, &l)
    30  	if err == syscall.ERROR_BUFFER_OVERFLOW {
    31  		b = make([]byte, l)
    32  		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
    33  		err = syscall.GetAdaptersInfo(a, &l)
    34  	}
    35  	if err != nil {
    36  		return nil, os.NewSyscallError("GetAdaptersInfo", err)
    37  	}
    38  	return a, nil
    39  }
    40  
    41  func getInterfaceList() ([]syscall.InterfaceInfo, error) {
    42  	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    43  	if err != nil {
    44  		return nil, os.NewSyscallError("Socket", err)
    45  	}
    46  	defer syscall.Closesocket(s)
    47  
    48  	ii := [20]syscall.InterfaceInfo{}
    49  	ret := uint32(0)
    50  	size := uint32(unsafe.Sizeof(ii))
    51  	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
    52  	if err != nil {
    53  		return nil, os.NewSyscallError("WSAIoctl", err)
    54  	}
    55  	c := ret / uint32(unsafe.Sizeof(ii[0]))
    56  	return ii[:c-1], nil
    57  }
    58  
    59  // If the ifindex is zero, interfaceTable returns mappings of all
    60  // network interfaces.  Otherwise it returns a mapping of a specific
    61  // interface.
    62  func interfaceTable(ifindex int) ([]Interface, error) {
    63  	ai, err := getAdapterList()
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	ii, err := getInterfaceList()
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	var ift []Interface
    74  	for ; ai != nil; ai = ai.Next {
    75  		index := ai.Index
    76  		if ifindex == 0 || ifindex == int(index) {
    77  			var flags Flags
    78  
    79  			row := syscall.MibIfRow{Index: index}
    80  			e := syscall.GetIfEntry(&row)
    81  			if e != nil {
    82  				return nil, os.NewSyscallError("GetIfEntry", e)
    83  			}
    84  
    85  			for _, ii := range ii {
    86  				ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
    87  				ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
    88  				ipl := &ai.IpAddressList
    89  				for ipl != nil {
    90  					ips := bytePtrToString(&ipl.IpAddress.String[0])
    91  					if ipv4.Equal(parseIPv4(ips)) {
    92  						break
    93  					}
    94  					ipl = ipl.Next
    95  				}
    96  				if ipl == nil {
    97  					continue
    98  				}
    99  				if ii.Flags&syscall.IFF_UP != 0 {
   100  					flags |= FlagUp
   101  				}
   102  				if ii.Flags&syscall.IFF_LOOPBACK != 0 {
   103  					flags |= FlagLoopback
   104  				}
   105  				if ii.Flags&syscall.IFF_BROADCAST != 0 {
   106  					flags |= FlagBroadcast
   107  				}
   108  				if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
   109  					flags |= FlagPointToPoint
   110  				}
   111  				if ii.Flags&syscall.IFF_MULTICAST != 0 {
   112  					flags |= FlagMulticast
   113  				}
   114  			}
   115  
   116  			name := bytePtrToString(&ai.AdapterName[0])
   117  
   118  			ifi := Interface{
   119  				Index:        int(index),
   120  				MTU:          int(row.Mtu),
   121  				Name:         name,
   122  				HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
   123  				Flags:        flags}
   124  			ift = append(ift, ifi)
   125  		}
   126  	}
   127  	return ift, nil
   128  }
   129  
   130  // If the ifi is nil, interfaceAddrTable returns addresses for all
   131  // network interfaces.  Otherwise it returns addresses for a specific
   132  // interface.
   133  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   134  	ai, err := getAdapterList()
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	var ifat []Addr
   140  	for ; ai != nil; ai = ai.Next {
   141  		index := ai.Index
   142  		if ifi == nil || ifi.Index == int(index) {
   143  			ipl := &ai.IpAddressList
   144  			for ; ipl != nil; ipl = ipl.Next {
   145  				ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
   146  				ifat = append(ifat, ifa.toAddr())
   147  			}
   148  		}
   149  	}
   150  	return ifat, nil
   151  }
   152  
   153  // interfaceMulticastAddrTable returns addresses for a specific
   154  // interface.
   155  func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   156  	// TODO(mikio): Implement this like other platforms.
   157  	return nil, nil
   158  }