|
|
|
|
@ -159,6 +159,32 @@ func ForeachInterfaceAddress(fn func(Interface, netaddr.IP)) error { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ForeachInterface calls fn for each interface on the machine, with all its addresses.
|
|
|
|
|
func ForeachInterface(fn func(Interface, []netaddr.IP)) error { |
|
|
|
|
ifaces, err := net.Interfaces() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
for i := range ifaces { |
|
|
|
|
iface := &ifaces[i] |
|
|
|
|
addrs, err := iface.Addrs() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
var ips []netaddr.IP |
|
|
|
|
for _, a := range addrs { |
|
|
|
|
switch v := a.(type) { |
|
|
|
|
case *net.IPNet: |
|
|
|
|
if ip, ok := netaddr.FromStdIP(v.IP); ok { |
|
|
|
|
ips = append(ips, ip) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fn(Interface{iface}, ips) |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// State is intended to store the state of the machine's network interfaces,
|
|
|
|
|
// routing table, and other network configuration.
|
|
|
|
|
// For now it's pretty basic.
|
|
|
|
|
@ -259,18 +285,35 @@ func (s *State) AnyInterfaceUp() bool { |
|
|
|
|
|
|
|
|
|
// RemoveTailscaleInterfaces modifes s to remove any interfaces that
|
|
|
|
|
// are owned by this process. (TODO: make this true; currently it
|
|
|
|
|
// makes the Linux-only assumption that the interface is named
|
|
|
|
|
// /^tailscale/)
|
|
|
|
|
// uses some heuristics)
|
|
|
|
|
func (s *State) RemoveTailscaleInterfaces() { |
|
|
|
|
for name := range s.InterfaceIPs { |
|
|
|
|
if isTailscaleInterfaceName(name) { |
|
|
|
|
for name, ips := range s.InterfaceIPs { |
|
|
|
|
if isTailscaleInterface(name, ips) { |
|
|
|
|
delete(s.InterfaceIPs, name) |
|
|
|
|
delete(s.InterfaceUp, name) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isTailscaleInterfaceName(name string) bool { |
|
|
|
|
func hasTailscaleIP(ips []netaddr.IP) bool { |
|
|
|
|
for _, ip := range ips { |
|
|
|
|
if tsaddr.IsTailscaleIP(ip) { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isTailscaleInterface(name string, ips []netaddr.IP) bool { |
|
|
|
|
if runtime.GOOS == "darwin" && strings.HasPrefix(name, "utun") && hasTailscaleIP(ips) { |
|
|
|
|
// On macOS in the sandboxed app (at least as of
|
|
|
|
|
// 2021-02-25), we often see two utun devices
|
|
|
|
|
// (e.g. utun4 and utun7) with the same IPv4 and IPv6
|
|
|
|
|
// addresses. Just remove all utun devices with
|
|
|
|
|
// Tailscale IPs until we know what's happening with
|
|
|
|
|
// macOS NetworkExtensions and utun devices.
|
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
return name == "Tailscale" || // as it is on Windows
|
|
|
|
|
strings.HasPrefix(name, "tailscale") // TODO: use --tun flag value, etc; see TODO in method doc
|
|
|
|
|
} |
|
|
|
|
@ -286,11 +329,17 @@ func GetState() (*State, error) { |
|
|
|
|
InterfaceIPs: make(map[string][]netaddr.IP), |
|
|
|
|
InterfaceUp: make(map[string]bool), |
|
|
|
|
} |
|
|
|
|
if err := ForeachInterfaceAddress(func(ni Interface, ip netaddr.IP) { |
|
|
|
|
if err := ForeachInterface(func(ni Interface, ips []netaddr.IP) { |
|
|
|
|
ifUp := ni.IsUp() |
|
|
|
|
s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], ip) |
|
|
|
|
s.InterfaceUp[ni.Name] = ifUp |
|
|
|
|
if ifUp && !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !isTailscaleInterfaceName(ni.Name) { |
|
|
|
|
s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], ips...) |
|
|
|
|
if !ifUp || isTailscaleInterface(ni.Name, ips) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
for _, ip := range ips { |
|
|
|
|
if ip.IsLoopback() || ip.IsLinkLocalUnicast() { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
s.HaveV6Global = s.HaveV6Global || isGlobalV6(ip) |
|
|
|
|
s.HaveV4 = s.HaveV4 || ip.Is4() |
|
|
|
|
} |
|
|
|
|
|