Open AudriusButkevicius opened 9 years ago
Thanks! Very thoughtful of you to offer.
package main
import (
"fmt"
"log"
"net"
"unsafe"
"golang.org/x/sys/windows"
)
type (
DWORD uint32
ULONG uint32
NET_IFINDEX ULONG
IF_INDEX NET_IFINDEX
NL_ROUTE_PROTOCOL int32
MIB_IPFORWARD_PROTO NL_ROUTE_PROTOCOL
MIB_IPFORWARD_TYPE int32
)
type MIB_IPFORWARDROW struct {
DwForwardDest DWORD
DwForwardMask DWORD
DwForwardPolicy DWORD
DwForwardNextHop DWORD
DwForwardIfIndex IF_INDEX
ForwardType MIB_IPFORWARD_TYPE
ForwardProto MIB_IPFORWARD_PROTO
DwForwardAge DWORD
DwForwardNextHopAS DWORD
DwForwardMetric1 DWORD
DwForwardMetric2 DWORD
DwForwardMetric3 DWORD
DwForwardMetric4 DWORD
DwForwardMetric5 DWORD
}
func ipDword(ip net.IP) (d DWORD) {
ip = ip.To4()
d |= DWORD(ip[0]) << 0
d |= DWORD(ip[1]) << 8
d |= DWORD(ip[2]) << 16
d |= DWORD(ip[3]) << 24
return
}
func dwordIP(d DWORD) (ip net.IP) {
ip = make(net.IP, net.IPv4len)
ip[0] = byte(d & 0xff)
ip[1] = byte((d >> 8) & 0xff)
ip[2] = byte((d >> 16) & 0xff)
ip[3] = byte((d >> 24) & 0xff)
return
}
func init() {
log.SetFlags(log.Lshortfile)
}
func main() {
dll, err := windows.LoadDLL("Iphlpapi.dll")
if err != nil {
log.Fatal(err)
}
defer dll.Release()
getBestRoute, err := dll.FindProc("GetBestRoute")
if err != nil {
log.Fatal(err)
}
var row MIB_IPFORWARDROW
// 8.8.8.8 is Google's public DNS, also there is 8.8.4.4
_, _, err = getBestRoute.Call(
uintptr(ipDword(net.ParseIP("8.8.8.8"))),
uintptr(ipDword(net.ParseIP("0.0.0.0"))),
uintptr(unsafe.Pointer(&row)),
)
if err != nil && err != windows.Errno(0) {
log.Fatal(err)
}
for _, val := range []struct {
Name string
Value DWORD
}{
{"DwForwardDest", row.DwForwardDest},
{"DwForwardMask", row.DwForwardMask},
{"DwForwardPolicy", row.DwForwardPolicy},
{"DwForwardNextHop", row.DwForwardNextHop},
{"DwForwardAge", row.DwForwardAge},
{"DwForwardNextHopAS", row.DwForwardNextHopAS},
{"DwForwardMetric1", row.DwForwardMetric1},
{"DwForwardMetric2", row.DwForwardMetric2},
{"DwForwardMetric3", row.DwForwardMetric3},
{"DwForwardMetric4", row.DwForwardMetric4},
{"DwForwardMetric5", row.DwForwardMetric5},
} {
fmt.Printf("%20s %s\n", val.Name+":", dwordIP(val.Value).String())
}
}
DwForwardDest: 0.0.0.0
DwForwardMask: 0.0.0.0
DwForwardPolicy: 0.0.0.0
DwForwardNextHop: 192.168.1.1
DwForwardAge: 79.42.1.0
DwForwardNextHopAS: 0.0.0.0
DwForwardMetric1: 50.0.0.0
DwForwardMetric2: 255.255.255.255
DwForwardMetric3: 255.255.255.255
DwForwardMetric4: 255.255.255.255
DwForwardMetric5: 255.255.255.255
The DwForwardNextHop
is the gateway.
I wonder if searching for a route to 8.8.8.8 will work for people running in networks that try to prevent connecting to public DNS. I tried finding the best route to 0.0.0.0 and it seemed to give the same result as 8.8.8.8
Another issue is that I don't think this handles IPv6
GetBestRoute2 handles IPv6, but it appeared in Vista.
Probably, GetBestInterfaceEx can be used with a workaround or as a combination with the
calmh/syncthing@6a6ec72
Currently I have no idea how to associate windows network interface with adapter. As I know interface is network level abstraction, and adapter is hardware level abstraction. The calmh/syncthing@6a6ec72
obtains information for adapters. The GetBestInterfaceEx
obtains interface index. Hm.... May be it is the same. May be not.
Go is sort of not supported on XP anyway, so not sure it should matter.
Аnyway, it turned out that the GetAdaptersInfo
works only for IPv4.
If the user has a complicated network they could have multiple gateways, each of which handles some subset of IP addresses. That's what makes it problematic to search for the best router for a given well-known IP address. On the other hand, I'm not sure we can do any better. (The current API for this code returns just one IP address after all.)
Just sharing my implementation incase you feel to incorporate it someday (IPv4 only though). Feel free to copy it and modify it in any shape or form, you can ignore the license completely.
https://github.com/calmh/syncthing/commit/6a6ec722cfcc01cd0ce44896aaa07bd77c7b4466
I have no clue how to check which one is the default one though :dancer: Stackoverflow suggests: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365924(v=vs.85).aspx