mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-19 19:38:40 +00:00
net/interfaces, net/netns: move default route interface code to interfaces
To populate interfaces.State.DefaultRouteInterface. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
fda9dc8815
commit
8893c2ee78
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !linux
|
// +build !linux,!windows
|
||||||
|
|
||||||
package interfaces
|
package interfaces
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package interfaces
|
package interfaces
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -77,18 +78,73 @@ func likelyHomeRouterIPWindows() (ret netaddr.IP, ok bool) {
|
|||||||
// NonTailscaleMTUs returns a map of interface LUID to interface MTU,
|
// NonTailscaleMTUs returns a map of interface LUID to interface MTU,
|
||||||
// for all interfaces except Tailscale tunnels.
|
// for all interfaces except Tailscale tunnels.
|
||||||
func NonTailscaleMTUs() (map[uint64]uint32, error) {
|
func NonTailscaleMTUs() (map[uint64]uint32, error) {
|
||||||
ifs, err := winipcfg.GetInterfaces()
|
mtus := map[uint64]uint32{}
|
||||||
|
ifs, err := NonTailscaleInterfaces()
|
||||||
|
for luid, iface := range ifs {
|
||||||
|
mtus[luid] = iface.Mtu
|
||||||
|
}
|
||||||
|
return mtus, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NonTailscaleInterfaces returns a map of interface LUID to interface
|
||||||
|
// for all interfaces except Tailscale tunnels.
|
||||||
|
func NonTailscaleInterfaces() (map[uint64]*winipcfg.Interface, error) {
|
||||||
|
ifs, err := winipcfg.GetInterfacesEx(&winipcfg.GetAdapterAddressesFlags{
|
||||||
|
GAA_FLAG_INCLUDE_ALL_INTERFACES: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := map[uint64]uint32{}
|
ret := map[uint64]*winipcfg.Interface{}
|
||||||
for _, iface := range ifs {
|
for _, iface := range ifs {
|
||||||
if iface.Description == tsconst.WintunInterfaceDesc {
|
if iface.Description == tsconst.WintunInterfaceDesc {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ret[iface.Luid] = iface.Mtu
|
ret[iface.Luid] = iface
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWindowsDefault returns the interface that has the non-Tailscale
|
||||||
|
// default route for the given address family.
|
||||||
|
//
|
||||||
|
// It returns (nil, nil) if no interface is found.
|
||||||
|
func GetWindowsDefault(family winipcfg.AddressFamily) (*winipcfg.Interface, error) {
|
||||||
|
ifs, err := NonTailscaleInterfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err := winipcfg.GetRoutes(family)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bestMetric := ^uint32(0)
|
||||||
|
var bestIface *winipcfg.Interface
|
||||||
|
for _, route := range routes {
|
||||||
|
iface := ifs[route.InterfaceLuid]
|
||||||
|
if route.DestinationPrefix.PrefixLength != 0 || iface == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if iface.OperStatus == winipcfg.IfOperStatusUp && route.Metric < bestMetric {
|
||||||
|
bestMetric = route.Metric
|
||||||
|
bestIface = iface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestIface, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultRouteInterface() (string, error) {
|
||||||
|
iface, err := GetWindowsDefault(winipcfg.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if iface == nil {
|
||||||
|
return "(none)", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (%s)", iface.FriendlyName, iface.Description), nil
|
||||||
|
}
|
||||||
|
@ -14,6 +14,17 @@ import (
|
|||||||
"tailscale.com/net/interfaces"
|
"tailscale.com/net/interfaces"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func interfaceIndex(iface *winipcfg.Interface) uint32 {
|
||||||
|
if iface == nil {
|
||||||
|
// The zero ifidx means "unspecified". If we end up passing zero
|
||||||
|
// to bindSocket*(), it unsets the binding and lets the socket
|
||||||
|
// behave as normal again, which is what we want if there's no
|
||||||
|
// default route we can use.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return iface.Index
|
||||||
|
}
|
||||||
|
|
||||||
// control binds c to the Windows interface that holds a default
|
// control binds c to the Windows interface that holds a default
|
||||||
// route, and is not the Tailscale WinTun interface.
|
// route, and is not the Tailscale WinTun interface.
|
||||||
func control(network, address string, c syscall.RawConn) error {
|
func control(network, address string, c syscall.RawConn) error {
|
||||||
@ -28,21 +39,21 @@ func control(network, address string, c syscall.RawConn) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if canV4 {
|
if canV4 {
|
||||||
if4, err := getDefaultInterface(winipcfg.AF_INET)
|
iface, err := interfaces.GetWindowsDefault(winipcfg.AF_INET)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := bindSocket4(c, if4); err != nil {
|
if err := bindSocket4(c, interfaceIndex(iface)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if canV6 {
|
if canV6 {
|
||||||
if6, err := getDefaultInterface(winipcfg.AF_INET6)
|
iface, err := interfaces.GetWindowsDefault(winipcfg.AF_INET6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := bindSocket6(c, if6); err != nil {
|
if err := bindSocket6(c, interfaceIndex(iface)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,38 +61,6 @@ func control(network, address string, c syscall.RawConn) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultInterface returns the index of the interface that has the
|
|
||||||
// non-Tailscale default route for the given address family.
|
|
||||||
func getDefaultInterface(family winipcfg.AddressFamily) (ifidx uint32, err error) {
|
|
||||||
ifs, err := interfaces.NonTailscaleMTUs()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
routes, err := winipcfg.GetRoutes(family)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bestMetric := ^uint32(0)
|
|
||||||
// The zero index means "unspecified". If we end up passing zero
|
|
||||||
// to bindSocket*(), it unsets the binding and lets the socket
|
|
||||||
// behave as normal again, which is what we want if there's no
|
|
||||||
// default route we can use.
|
|
||||||
var index uint32
|
|
||||||
for _, route := range routes {
|
|
||||||
if route.DestinationPrefix.PrefixLength != 0 || ifs[route.InterfaceLuid] == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if route.Metric < bestMetric {
|
|
||||||
bestMetric = route.Metric
|
|
||||||
index = route.InterfaceIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return index, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sockoptBoundInterface is the value of IP_UNICAST_IF and IPV6_UNICAST_IF.
|
// sockoptBoundInterface is the value of IP_UNICAST_IF and IPV6_UNICAST_IF.
|
||||||
//
|
//
|
||||||
// See https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
|
// See https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
|
||||||
|
Loading…
x
Reference in New Issue
Block a user