mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-24 16:00:38 +08:00
feat: add vendor
This commit is contained in:
242
vendor/github.com/libp2p/go-netroute/netroute_windows.go
generated
vendored
Normal file
242
vendor/github.com/libp2p/go-netroute/netroute_windows.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
//go:build windows
|
||||
|
||||
package netroute
|
||||
|
||||
// Implementation Warning: mapping of the correct interface ID and index is not
|
||||
// hooked up.
|
||||
// Reference:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getbestroute2
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/gopacket/routing"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modiphlpapi = windows.NewLazyDLL("iphlpapi.dll")
|
||||
procGetBestRoute2 = modiphlpapi.NewProc("GetBestRoute2")
|
||||
)
|
||||
|
||||
type NetLUID uint64
|
||||
|
||||
type AddressPrefix struct {
|
||||
*windows.RawSockaddrAny
|
||||
PrefixLength byte
|
||||
}
|
||||
|
||||
type RouteProtocol uint32 // MIB_IPFORWARD_PROTO
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_row2
|
||||
type mib_row2 struct {
|
||||
luid NetLUID
|
||||
index uint32
|
||||
destinationPrefix *AddressPrefix
|
||||
nextHop *windows.RawSockaddrAny
|
||||
prefixLength byte
|
||||
lifetime uint32
|
||||
preferredLifetime uint32
|
||||
metric uint32
|
||||
protocol RouteProtocol
|
||||
loopback byte
|
||||
autoconfigured byte
|
||||
publish byte
|
||||
immortal byte
|
||||
age uint32
|
||||
origin byte
|
||||
}
|
||||
|
||||
func callBestRoute(source, dest net.IP) (*mib_row2, net.IP, error) {
|
||||
sourceAddr, _, _ := sockaddrToAny(ipAndZoneToSockaddr(source, ""))
|
||||
destAddr, _, _ := sockaddrToAny(ipAndZoneToSockaddr(dest, ""))
|
||||
bestRoute := make([]byte, 512)
|
||||
bestSource := make([]byte, 116)
|
||||
|
||||
err := getBestRoute2(nil, 0, sourceAddr, destAddr, 0, bestRoute, bestSource)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// interpret best route and best source.
|
||||
route, err := parseRoute(bestRoute)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// per https://docs.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_row2
|
||||
// If the route is to a local loopback address or an IP address on the local link, the next hop is unspecified (all zeros)
|
||||
if isZero(route.nextHop) {
|
||||
route.nextHop = nil
|
||||
}
|
||||
|
||||
var bestSourceRaw windows.RawSockaddrAny
|
||||
bestSourceRaw.Addr.Family = binary.LittleEndian.Uint16(bestSource[0:2])
|
||||
copyInto(bestSourceRaw.Addr.Data[:], bestSource[2:16])
|
||||
copyInto(bestSourceRaw.Pad[:], bestSource[16:])
|
||||
addr, _ := bestSourceRaw.Sockaddr()
|
||||
bestSrc, _ := sockaddrToIPAndZone(addr)
|
||||
|
||||
return route, bestSrc, nil
|
||||
}
|
||||
|
||||
func copyInto(dst []int8, src []byte) {
|
||||
for i, b := range src {
|
||||
dst[i] = int8(b)
|
||||
}
|
||||
}
|
||||
|
||||
func isZero(addr *windows.RawSockaddrAny) bool {
|
||||
for _, b := range addr.Addr.Data {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, b := range addr.Pad {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func parseRoute(mib []byte) (*mib_row2, error) {
|
||||
var route mib_row2
|
||||
var err error
|
||||
|
||||
route.luid = NetLUID(binary.LittleEndian.Uint64(mib[0:]))
|
||||
route.index = binary.LittleEndian.Uint32(mib[8:])
|
||||
idx := 0
|
||||
route.destinationPrefix, idx, err = readDestPrefix(mib, 12)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
route.nextHop, idx, err = readSockAddr(mib, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
route.prefixLength = mib[idx]
|
||||
idx += 1
|
||||
route.lifetime = binary.LittleEndian.Uint32(mib[idx : idx+4])
|
||||
idx += 4
|
||||
route.preferredLifetime = binary.LittleEndian.Uint32(mib[idx : idx+4])
|
||||
idx += 4
|
||||
route.metric = binary.LittleEndian.Uint32(mib[idx : idx+4])
|
||||
idx += 4
|
||||
route.protocol = RouteProtocol(binary.LittleEndian.Uint32(mib[idx : idx+4]))
|
||||
idx += 4
|
||||
route.loopback = mib[idx]
|
||||
idx += 1
|
||||
route.autoconfigured = mib[idx]
|
||||
idx += 1
|
||||
route.publish = mib[idx]
|
||||
idx += 1
|
||||
route.immortal = mib[idx]
|
||||
idx += 1
|
||||
route.age = binary.LittleEndian.Uint32(mib[idx : idx+4])
|
||||
idx += 4
|
||||
route.origin = mib[idx]
|
||||
|
||||
return &route, err
|
||||
}
|
||||
|
||||
func readDestPrefix(buffer []byte, idx int) (*AddressPrefix, int, error) {
|
||||
sock, idx2, err := readSockAddr(buffer, idx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
pfixLen := buffer[idx2]
|
||||
if idx2-idx > 32 {
|
||||
return nil, idx, fmt.Errorf("Unexpectedly large internal sockaddr struct")
|
||||
}
|
||||
return &AddressPrefix{sock, pfixLen}, idx + 32, nil
|
||||
}
|
||||
|
||||
func readSockAddr(buffer []byte, idx int) (*windows.RawSockaddrAny, int, error) {
|
||||
var rsa windows.RawSockaddrAny
|
||||
rsa.Addr.Family = binary.LittleEndian.Uint16(buffer[idx : idx+2])
|
||||
if rsa.Addr.Family == windows.AF_INET || rsa.Addr.Family == windows.AF_UNSPEC {
|
||||
copyInto(rsa.Addr.Data[:], buffer[idx+2:idx+16])
|
||||
return &rsa, idx + 16, nil
|
||||
} else if rsa.Addr.Family == windows.AF_INET6 {
|
||||
copyInto(rsa.Addr.Data[:], buffer[idx+2:idx+16])
|
||||
copyInto(rsa.Pad[:], buffer[idx+16:idx+28])
|
||||
return &rsa, idx + 28, nil
|
||||
} else {
|
||||
return nil, 0, fmt.Errorf("Unknown windows addr family %d", rsa.Addr.Family)
|
||||
}
|
||||
}
|
||||
|
||||
func getBestRoute2(interfaceLuid *NetLUID, interfaceIndex uint32, sourceAddress, destinationAddress *windows.RawSockaddrAny, addressSortOptions uint32, bestRoute []byte, bestSourceAddress []byte) (errcode error) {
|
||||
r0, _, _ := procGetBestRoute2.Call(
|
||||
uintptr(unsafe.Pointer(interfaceLuid)),
|
||||
uintptr(interfaceIndex),
|
||||
uintptr(unsafe.Pointer(sourceAddress)),
|
||||
uintptr(unsafe.Pointer(destinationAddress)),
|
||||
uintptr(addressSortOptions),
|
||||
uintptr(unsafe.Pointer(&bestRoute[0])),
|
||||
uintptr(unsafe.Pointer(&bestSourceAddress[0])))
|
||||
if r0 != 0 {
|
||||
errcode = windows.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getIface(index uint32) *net.Interface {
|
||||
var ifRow windows.MibIfRow
|
||||
ifRow.Index = index
|
||||
err := windows.GetIfEntry(&ifRow)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
physAddrLen := int(ifRow.PhysAddrLen)
|
||||
if len(ifRow.PhysAddr) < physAddrLen && physAddrLen >= 0 {
|
||||
physAddrLen = len(ifRow.PhysAddr)
|
||||
}
|
||||
physAddr := ifRow.PhysAddr[:physAddrLen]
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if bytes.Equal(iface.HardwareAddr, physAddr) {
|
||||
return &iface
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type winRouter struct{}
|
||||
|
||||
func (r *winRouter) Route(dst net.IP) (iface *net.Interface, gateway, preferredSrc net.IP, err error) {
|
||||
return r.RouteWithSrc(nil, nil, dst)
|
||||
}
|
||||
|
||||
func (r *winRouter) RouteWithSrc(input net.HardwareAddr, src, dst net.IP) (iface *net.Interface, gateway, preferredSrc net.IP, err error) {
|
||||
route, pref, err := callBestRoute(src, dst)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
iface = getIface(route.index)
|
||||
|
||||
if route.nextHop == nil || route.nextHop.Addr.Family == 0 /* AF_UNDEF */ {
|
||||
return iface, nil, pref, nil
|
||||
}
|
||||
addr, err := route.nextHop.Sockaddr()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
nextHop, _ := sockaddrToIPAndZone(addr)
|
||||
|
||||
return iface, nextHop, pref, nil
|
||||
}
|
||||
|
||||
func New() (routing.Router, error) {
|
||||
rtr := &winRouter{}
|
||||
return rtr, nil
|
||||
}
|
||||
Reference in New Issue
Block a user