1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// 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.
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]))
// TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
// contains IPv4 address list only. We should use another API
// for fetching IPv6 stuff from the kernel.
err := syscall.GetAdaptersInfo(a, &l)
if err == syscall.ERROR_BUFFER_OVERFLOW {
b = make([]byte, l)
a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err = syscall.GetAdaptersInfo(a, &l)
}
if err != nil {
return nil, os.NewSyscallError("GetAdaptersInfo", err)
}
return a, nil
}
func getInterfaceList() ([]syscall.InterfaceInfo, error) {
s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
if err != nil {
return nil, os.NewSyscallError("Socket", err)
}
defer syscall.Closesocket(s)
ii := [20]syscall.InterfaceInfo{}
ret := uint32(0)
size := uint32(unsafe.Sizeof(ii))
err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
if err != nil {
return nil, os.NewSyscallError("WSAIoctl", err)
}
c := ret / uint32(unsafe.Sizeof(ii[0]))
return ii[:c-1], nil
}
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
ai, err := getAdapterList()
if err != nil {
return nil, err
}
ii, err := getInterfaceList()
if err != nil {
return nil, err
}
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 != nil {
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 ifi is nil, interfaceAddrTable returns addresses for all
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
ai, err := getAdapterList()
if err != nil {
return nil, err
}
var ifat []Addr
for ; ai != nil; ai = ai.Next {
index := ai.Index
if ifi == nil || ifi.Index == int(index) {
ipl := &ai.IpAddressList
for ; ipl != nil; ipl = ipl.Next {
ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
ifat = append(ifat, ifa.toAddr())
}
}
}
return ifat, nil
}
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms.
return nil, nil
}
|