feat: add vendor

This commit is contained in:
fengcaiwen
2023-10-21 20:48:01 +08:00
parent 1c637f45b5
commit 6a6c4e3257
8701 changed files with 2400820 additions and 1 deletions

29
vendor/github.com/libp2p/go-netroute/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,29 @@
Copyright (c) 2020 Will Scott. All rights reserved.
Copyright (c) 2012 Google, Inc. All rights reserved.
Copyright (c) 2009-2011 Andreas Krennmair. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Andreas Krennmair, Google, nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

60
vendor/github.com/libp2p/go-netroute/README.md generated vendored Normal file
View File

@@ -0,0 +1,60 @@
Go Netroute
===
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://github.com/libp2p/libp2p)
[![Build Status](https://travis-ci.com/libp2p/go-netroute.svg?branch=master)](https://travis-ci.com/libp2p/go-netroute)
A cross-platform implementation of the [`gopacket/routing.Router`](https://godoc.org/github.com/google/gopacket/routing#Router) interface.
This library is derived from `gopacket` for linux, `x/net/route` for mac, and `iphlpapi.dll` for windows.
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Documentation](#documentation)
- [Contribute](#contribute)
- [License](#license)
## Install
```
go get github.com/libp2p/go-netroute
```
## Usage
To be used for querying the local OS routing table.
```go
import (
netroute "github.com/libp2p/go-netroute"
)
func main() {
r, err := netroute.New()
if err != nil {
panic(err)
}
iface, gw, src, err := r.Route(net.IPv4(127, 0, 0, 1))
fmt.Printf("%v, %v, %v, %v\n", iface, gw, src, err)
}
```
## Documentation
See the [gopacket](https://github.com/google/gopacket/blob/master/routing/) interface for thoughts on design,
and [godoc](https://godoc.org/github.com/libp2p/go-netroute) for API documentation.
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/libp2p/go-netroute/issues).
Check out our [contributing document](https://github.com/libp2p/community/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[BSD](LICENSE) © Will Scott, and the Gopacket authors (i.e. Google)

161
vendor/github.com/libp2p/go-netroute/common.go generated vendored Normal file
View File

@@ -0,0 +1,161 @@
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// Originally found in
// https://github.com/google/gopacket/blob/master/routing/routing.go
// - Route selection modified to choose most selective route
// to break ties when route priority is insufficient.
package netroute
import (
"bytes"
"errors"
"fmt"
"net"
"strings"
)
// rtInfo contains information on a single route.
type rtInfo struct {
Src, Dst *net.IPNet
Gateway, PrefSrc net.IP
// We currently ignore the InputIface.
InputIface, OutputIface uint32
Priority uint32
}
func (rt rtInfo) IsMoreSpecThan(mostSpecificRt *rtInfo) bool {
if mostSpecificRt == nil {
return true
}
var candSpec, curSpec int
if rt.Dst != nil {
candSpec, _ = rt.Dst.Mask.Size()
}
if mostSpecificRt.Dst != nil {
curSpec, _ = mostSpecificRt.Dst.Mask.Size()
}
if candSpec > curSpec {
return true
} else if candSpec < curSpec {
return false
}
// Windows and MacOS hasn't metric/priority on rule entry,
// But the interface device has the priority property.
//
// Before we find more correctly way on different OS platform,
// we keep the same rule selecting logical as before which
// is more later more special
return mostSpecificRt.Priority >= rt.Priority
}
// routeSlice implements sort.Interface to sort routes by Priority.
type routeSlice []*rtInfo
func (r routeSlice) Len() int {
return len(r)
}
func (r routeSlice) Less(i, j int) bool {
return r[i].Priority < r[j].Priority
}
func (r routeSlice) Swap(i, j int) {
r[i], r[j] = r[j], r[i]
}
type router struct {
ifaces map[int]net.Interface
addrs map[int]ipAddrs
v4, v6 routeSlice
}
func (r *router) String() string {
strs := []string{"ROUTER", "--- V4 ---"}
for _, route := range r.v4 {
strs = append(strs, fmt.Sprintf("%+v", *route))
}
strs = append(strs, "--- V6 ---")
for _, route := range r.v6 {
strs = append(strs, fmt.Sprintf("%+v", *route))
}
return strings.Join(strs, "\n")
}
type ipAddrs struct {
v4, v6 net.IP
}
func (r *router) Route(dst net.IP) (iface *net.Interface, gateway, preferredSrc net.IP, err error) {
return r.RouteWithSrc(nil, nil, dst)
}
func (r *router) RouteWithSrc(input net.HardwareAddr, src, dst net.IP) (iface *net.Interface, gateway, preferredSrc net.IP, err error) {
var ifaceIndex int
switch {
case dst.To4() != nil:
ifaceIndex, gateway, preferredSrc, err = r.route(r.v4, input, src, dst)
case dst.To16() != nil:
ifaceIndex, gateway, preferredSrc, err = r.route(r.v6, input, src, dst)
default:
err = errors.New("IP is not valid as IPv4 or IPv6")
return
}
if err != nil {
return
}
// Interfaces are 1-indexed, but we store them in a 0-indexed array.
correspondingIface, ok := r.ifaces[ifaceIndex]
if !ok {
err = errors.New("Route refereced unknown interface")
}
iface = &correspondingIface
if preferredSrc == nil {
switch {
case dst.To4() != nil:
preferredSrc = r.addrs[ifaceIndex].v4
case dst.To16() != nil:
preferredSrc = r.addrs[ifaceIndex].v6
}
}
return
}
func (r *router) route(routes routeSlice, input net.HardwareAddr, src, dst net.IP) (iface int, gateway, preferredSrc net.IP, err error) {
var inputIndex uint32
if input != nil {
for i, iface := range r.ifaces {
if bytes.Equal(input, iface.HardwareAddr) {
// Convert from zero- to one-indexed.
inputIndex = uint32(i + 1)
break
}
}
}
var mostSpecificRt *rtInfo
for _, rt := range routes {
if rt.InputIface != 0 && rt.InputIface != inputIndex {
continue
}
if src != nil && rt.Src != nil && !rt.Src.Contains(src) {
continue
}
if rt.Dst != nil && !rt.Dst.Contains(dst) {
continue
}
if rt.IsMoreSpecThan(mostSpecificRt) {
mostSpecificRt = rt
}
}
if mostSpecificRt != nil {
return int(mostSpecificRt.OutputIface), mostSpecificRt.Gateway, mostSpecificRt.PrefSrc, nil
}
err = fmt.Errorf("no route found for %v", dst)
return
}

152
vendor/github.com/libp2p/go-netroute/netroute_bsd.go generated vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// This is a BSD import for the routing structure initially found in
// https://github.com/google/gopacket/blob/master/routing/routing.go
// RIB parsing follows the BSD route format described in
// https://github.com/freebsd/freebsd/blob/master/sys/net/route.h
package netroute
import (
"fmt"
"net"
"sort"
"syscall"
"github.com/google/gopacket/routing"
"golang.org/x/net/route"
)
func toIPAddr(a route.Addr) (net.IP, error) {
switch t := a.(type) {
case *route.Inet4Addr:
ip := net.IPv4(t.IP[0], t.IP[1], t.IP[2], t.IP[3])
return ip, nil
case *route.Inet6Addr:
ip := make(net.IP, net.IPv6len)
copy(ip, t.IP[:])
return ip, nil
default:
return net.IP{}, fmt.Errorf("unknown family: %v", t)
}
}
// selected BSD Route flags.
const (
RTF_UP = 0x1
RTF_GATEWAY = 0x2
RTF_HOST = 0x4
RTF_REJECT = 0x8
RTF_DYNAMIC = 0x10
RTF_MODIFIED = 0x20
RTF_STATIC = 0x800
RTF_BLACKHOLE = 0x1000
RTF_LOCAL = 0x200000
RTF_BROADCAST = 0x400000
RTF_MULTICAST = 0x800000
)
func New() (routing.Router, error) {
rtr := &router{}
rtr.ifaces = make(map[int]net.Interface)
rtr.addrs = make(map[int]ipAddrs)
tab, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0)
if err != nil {
return nil, err
}
msgs, err := route.ParseRIB(route.RIBTypeRoute, tab)
if err != nil {
return nil, err
}
var ipn *net.IPNet
for _, msg := range msgs {
m := msg.(*route.RouteMessage)
// We ignore the error (m.Err) here. It's not clear what this error actually means,
// and it makes us miss routes that _should_ be included.
routeInfo := new(rtInfo)
if m.Version < 3 || m.Version > 5 {
return nil, fmt.Errorf("unexpected RIB message version: %d", m.Version)
}
if m.Type != 4 /* RTM_GET */ {
return nil, fmt.Errorf("unexpected RIB message type: %d", m.Type)
}
if m.Flags&RTF_UP == 0 ||
m.Flags&(RTF_REJECT|RTF_BLACKHOLE) != 0 {
continue
}
dst, err := toIPAddr(m.Addrs[0])
if err == nil {
mask, _ := toIPAddr(m.Addrs[2])
if mask == nil {
mask = net.IP(net.CIDRMask(0, 8*len(dst)))
}
ipn = &net.IPNet{IP: dst, Mask: net.IPMask(mask)}
if m.Flags&RTF_HOST != 0 {
ipn.Mask = net.CIDRMask(8*len(ipn.IP), 8*len(ipn.IP))
}
routeInfo.Dst = ipn
} else {
return nil, fmt.Errorf("unexpected RIB destination: %v", err)
}
if m.Flags&RTF_GATEWAY != 0 {
if gw, err := toIPAddr(m.Addrs[1]); err == nil {
routeInfo.Gateway = gw
}
}
if src, err := toIPAddr(m.Addrs[5]); err == nil {
ipn = &net.IPNet{IP: src, Mask: net.CIDRMask(8*len(src), 8*len(src))}
routeInfo.Src = ipn
routeInfo.PrefSrc = src
if m.Flags&0x2 != 0 /* RTF_GATEWAY */ {
routeInfo.Src.Mask = net.CIDRMask(0, 8*len(routeInfo.Src.IP))
}
}
routeInfo.OutputIface = uint32(m.Index)
switch m.Addrs[0].(type) {
case *route.Inet4Addr:
rtr.v4 = append(rtr.v4, routeInfo)
case *route.Inet6Addr:
rtr.v6 = append(rtr.v6, routeInfo)
}
}
sort.Sort(rtr.v4)
sort.Sort(rtr.v6)
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range ifaces {
rtr.ifaces[iface.Index] = iface
var addrs ipAddrs
ifaceAddrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range ifaceAddrs {
if inet, ok := addr.(*net.IPNet); ok {
// Go has a nasty habit of giving you IPv4s as ::ffff:1.2.3.4 instead of 1.2.3.4.
// We want to use mapped v4 addresses as v4 preferred addresses, never as v6
// preferred addresses.
if v4 := inet.IP.To4(); v4 != nil {
if addrs.v4 == nil {
addrs.v4 = v4
}
} else if addrs.v6 == nil {
addrs.v6 = inet.IP
}
}
}
rtr.addrs[iface.Index] = addrs
}
return rtr, nil
}

127
vendor/github.com/libp2p/go-netroute/netroute_linux.go generated vendored Normal file
View File

@@ -0,0 +1,127 @@
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//go:build linux
// Generate a local routing table structure following the code at
// https://github.com/google/gopacket/blob/master/routing/routing.go
package netroute
import (
"net"
"sort"
"syscall"
"unsafe"
"github.com/google/gopacket/routing"
)
// Pulled from http://man7.org/linux/man-pages/man7/rtnetlink.7.html
// See the section on RTM_NEWROUTE, specifically 'struct rtmsg'.
type routeInfoInMemory struct {
Family byte
DstLen byte
SrcLen byte
TOS byte
Table byte
Protocol byte
Scope byte
Type byte
Flags uint32
}
func New() (routing.Router, error) {
rtr := &router{}
rtr.ifaces = make(map[int]net.Interface)
rtr.addrs = make(map[int]ipAddrs)
tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)
if err != nil {
return nil, err
}
msgs, err := syscall.ParseNetlinkMessage(tab)
if err != nil {
return nil, err
}
loop:
for _, m := range msgs {
switch m.Header.Type {
case syscall.NLMSG_DONE:
break loop
case syscall.RTM_NEWROUTE:
rt := (*routeInfoInMemory)(unsafe.Pointer(&m.Data[0]))
routeInfo := rtInfo{}
attrs, err := syscall.ParseNetlinkRouteAttr(&m)
if err != nil {
return nil, err
}
switch rt.Family {
case syscall.AF_INET:
rtr.v4 = append(rtr.v4, &routeInfo)
case syscall.AF_INET6:
rtr.v6 = append(rtr.v6, &routeInfo)
default:
continue loop
}
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.RTA_DST:
routeInfo.Dst = &net.IPNet{
IP: net.IP(attr.Value),
Mask: net.CIDRMask(int(rt.DstLen), len(attr.Value)*8),
}
case syscall.RTA_SRC:
routeInfo.Src = &net.IPNet{
IP: net.IP(attr.Value),
Mask: net.CIDRMask(int(rt.SrcLen), len(attr.Value)*8),
}
case syscall.RTA_GATEWAY:
routeInfo.Gateway = net.IP(attr.Value)
case syscall.RTA_PREFSRC:
routeInfo.PrefSrc = net.IP(attr.Value)
case syscall.RTA_IIF:
routeInfo.InputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
case syscall.RTA_OIF:
routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
case syscall.RTA_PRIORITY:
routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
}
}
}
}
sort.Sort(rtr.v4)
sort.Sort(rtr.v6)
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range ifaces {
rtr.ifaces[iface.Index] = iface
var addrs ipAddrs
ifaceAddrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range ifaceAddrs {
if inet, ok := addr.(*net.IPNet); ok {
// Go has a nasty habit of giving you IPv4s as ::ffff:1.2.3.4 instead of 1.2.3.4.
// We want to use mapped v4 addresses as v4 preferred addresses, never as v6
// preferred addresses.
if v4 := inet.IP.To4(); v4 != nil {
if addrs.v4 == nil {
addrs.v4 = v4
}
} else if addrs.v6 == nil {
addrs.v6 = inet.IP
}
}
}
rtr.addrs[iface.Index] = addrs
}
return rtr, nil
}

141
vendor/github.com/libp2p/go-netroute/netroute_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,141 @@
// Generate a local routing table structure following the code at
// https://github.com/google/gopacket/blob/master/routing/routing.go
//
// Plan 9 networking is described here: http://9p.io/magic/man2html/3/ip
package netroute
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"strconv"
"strings"
"github.com/google/gopacket/routing"
)
const netdir = "/net"
func New() (routing.Router, error) {
rtr := &router{}
rtr.ifaces = make(map[int]net.Interface)
rtr.addrs = make(map[int]ipAddrs)
ifaces, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("could not get interfaces: %v", err)
}
for _, iface := range ifaces {
rtr.ifaces[iface.Index] = iface
var addrs ipAddrs
ifaceAddrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range ifaceAddrs {
if inet, ok := addr.(*net.IPNet); ok {
// Go has a nasty habit of giving you IPv4s as ::ffff:1.2.3.4 instead of 1.2.3.4.
// We want to use mapped v4 addresses as v4 preferred addresses, never as v6
// preferred addresses.
if v4 := inet.IP.To4(); v4 != nil {
if addrs.v4 == nil {
addrs.v4 = v4
}
} else if addrs.v6 == nil {
addrs.v6 = inet.IP
}
}
}
rtr.addrs[iface.Index] = addrs
}
rtr.v4, rtr.v6, err = parseIPRoutes()
if err != nil {
return nil, err
}
return rtr, nil
}
func parseIPRoutes() (v4, v6 routeSlice, err error) {
buf, err := ioutil.ReadFile(netdir + "/iproute")
if err != nil {
return nil, nil, err
}
for {
i := bytes.IndexRune(buf, '\n')
if i <= 0 {
break
}
f := strings.Fields(string(buf[:i]))
buf = buf[i+1:]
if len(f) < 8 {
return nil, nil, fmt.Errorf("iproute entry contains %d fields", len(f))
}
flags, rt, err := parseRoute(f)
if err != nil {
return nil, nil, err
}
if rt.Dst != nil {
// If gateway for destination 127.0.0.1/32 is 127.0.0.1, set it to nil.
if m, n := rt.Dst.Mask.Size(); n > 0 && m == n && rt.Dst.IP.Equal(rt.Gateway) {
rt.Gateway = nil
}
}
if strings.ContainsRune(flags, '4') { // IPv4
v4 = append(v4, rt)
}
if strings.ContainsRune(flags, '6') { // IPv6
v6 = append(v6, rt)
}
}
return v4, v6, nil
}
func parseRoute(f []string) (flags string, rt *rtInfo, err error) {
rt = new(rtInfo)
isV4 := strings.ContainsRune(f[3], '4') // flags
rt.PrefSrc, rt.Src, err = parsePlan9CIDR(f[6], f[7], isV4)
if err != nil {
return "", nil, err
}
_, rt.Dst, err = parsePlan9CIDR(f[0], f[1], isV4)
if err != nil {
return "", nil, err
}
rt.Gateway = net.ParseIP(f[2])
n, err := strconv.ParseUint(f[5], 10, 32)
if err != nil {
return "", nil, err
}
rt.InputIface = 0
rt.OutputIface = uint32(n) + 1 // starts at 0, so net package adds 1
rt.Priority = 0
return f[3], rt, nil
}
func parsePlan9CIDR(addr, mask string, isV4 bool) (net.IP, *net.IPNet, error) {
if len(mask) == 0 || mask[0] != '/' {
return nil, nil, fmt.Errorf("invalid CIDR mask %v", mask)
}
n, err := strconv.ParseUint(mask[1:], 10, 32)
if err != nil {
return nil, nil, err
}
ip := net.ParseIP(addr)
iplen := net.IPv6len
if isV4 {
// Plan 9 uses IPv6 mask for IPv4 addresses
n -= 8 * (net.IPv6len - net.IPv4len)
iplen = net.IPv4len
}
if n == 0 && ip.IsUnspecified() {
return nil, nil, nil
}
m := net.CIDRMask(int(n), 8*iplen)
return ip, &net.IPNet{IP: ip.Mask(m), Mask: m}, nil
}

22
vendor/github.com/libp2p/go-netroute/netroute_stub.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// A stub routing table conformant interface for js/wasm environments.
//go:build js && wasm
package netroute
import (
"net"
"github.com/google/gopacket/routing"
)
func New() (routing.Router, error) {
rtr := &router{}
rtr.ifaces = make(map[int]net.Interface)
rtr.ifaces[0] = net.Interface{}
rtr.addrs = make(map[int]ipAddrs)
rtr.addrs[0] = ipAddrs{}
rtr.v4 = routeSlice{&rtInfo{}}
rtr.v6 = routeSlice{&rtInfo{}}
return rtr, nil
}

View 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
}

View File

@@ -0,0 +1,130 @@
//go:build windows
package netroute
import (
"net"
"strconv"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// socklen is a type for the length of a sockaddr.
type socklen uint
// ipAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a Sockaddr
// Returns nil if conversion fails.
func ipAndZoneToSockaddr(ip net.IP, zone string) windows.Sockaddr {
// Unspecified?
if ip == nil {
if zone != "" {
return &windows.SockaddrInet6{ZoneId: uint32(ip6ZoneToInt(zone))}
}
return new(windows.SockaddrInet4)
}
// Valid IPv4?
if ip4 := ip.To4(); ip4 != nil && zone == "" {
var buf [4]byte
copy(buf[:], ip4) // last 4 bytes
return &windows.SockaddrInet4{Addr: buf}
}
// Valid IPv6 address?
if ip6 := ip.To16(); ip6 != nil {
var buf [16]byte
copy(buf[:], ip6)
return &windows.SockaddrInet6{Addr: buf, ZoneId: uint32(ip6ZoneToInt(zone))}
}
return nil
}
// sockaddrToIPAndZone converts a Sockaddr to a net.IP (with optional IPv6 Zone)
// Returns nil if conversion fails.
func sockaddrToIPAndZone(sa windows.Sockaddr) (net.IP, string) {
switch sa := sa.(type) {
case *windows.SockaddrInet4:
ip := make([]byte, 16)
// V4InV6Prefix
ip[10] = 0xff
ip[11] = 0xff
copy(ip[12:16], sa.Addr[:])
return ip, ""
case *windows.SockaddrInet6:
ip := make([]byte, 16)
copy(ip, sa.Addr[:])
return ip, ip6ZoneToString(int(sa.ZoneId))
}
return nil, ""
}
func sockaddrToAny(sa windows.Sockaddr) (*windows.RawSockaddrAny, socklen, error) {
if sa == nil {
return nil, 0, syscall.EINVAL
}
switch sa := sa.(type) {
case *windows.SockaddrInet4:
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, syscall.EINVAL
}
raw := new(windows.RawSockaddrAny)
raw.Addr.Family = windows.AF_INET
raw4 := (*windows.RawSockaddrInet4)(unsafe.Pointer(raw))
p := (*[2]byte)(unsafe.Pointer(&raw4.Port))
p[0] = byte(sa.Port >> 8)
p[1] = byte(sa.Port)
for i := 0; i < len(sa.Addr); i++ {
raw4.Addr[i] = sa.Addr[i]
}
return raw, socklen(unsafe.Sizeof(*raw4)), nil
case *windows.SockaddrInet6:
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, syscall.EINVAL
}
raw := new(windows.RawSockaddrAny)
raw.Addr.Family = windows.AF_INET6
raw6 := (*windows.RawSockaddrInet6)(unsafe.Pointer(raw))
p := (*[2]byte)(unsafe.Pointer(&raw6.Port))
p[0] = byte(sa.Port >> 8)
p[1] = byte(sa.Port)
raw6.Scope_id = sa.ZoneId
for i := 0; i < len(sa.Addr); i++ {
raw6.Addr[i] = sa.Addr[i]
}
return raw, socklen(unsafe.Sizeof(*raw6)), nil
case *windows.SockaddrUnix:
return nil, 0, syscall.EWINDOWS
}
return nil, 0, syscall.EAFNOSUPPORT
}
// from: go/src/pkg/net/ipsock.go
// ip6ZoneToString converts an IP6 Zone unix int to a net string
// returns "" if zone is 0
func ip6ZoneToString(zone int) string {
if zone == 0 {
return ""
}
if ifi, err := net.InterfaceByIndex(zone); err == nil {
return ifi.Name
}
return strconv.Itoa(zone)
}
// ip6ZoneToInt converts an IP6 Zone net string to a unix int
// returns 0 if zone is ""
func ip6ZoneToInt(zone string) int {
if zone == "" {
return 0
}
if ifi, err := net.InterfaceByName(zone); err == nil {
return ifi.Index
}
n, _ := strconv.ParseInt(zone, 10, 32)
return int(n)
}

3
vendor/github.com/libp2p/go-netroute/version.json generated vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"version": "v0.2.1"
}