summaryrefslogtreecommitdiffhomepage
path: root/net/interfaces/interfaces.go
diff options
context:
space:
mode:
Diffstat (limited to 'net/interfaces/interfaces.go')
-rw-r--r--net/interfaces/interfaces.go117
1 files changed, 73 insertions, 44 deletions
diff --git a/net/interfaces/interfaces.go b/net/interfaces/interfaces.go
index 3a0ffeb0b..f2988af34 100644
--- a/net/interfaces/interfaces.go
+++ b/net/interfaces/interfaces.go
@@ -6,10 +6,10 @@
package interfaces
import (
+ "bytes"
"fmt"
"net"
"net/http"
- "reflect"
"runtime"
"sort"
"strings"
@@ -190,6 +190,9 @@ func ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) error {
}
}
}
+ sort.Slice(pfxs, func(i, j int) bool {
+ return pfxs[i].IP.Less(pfxs[j].IP)
+ })
fn(Interface{iface}, pfxs)
}
return nil
@@ -204,7 +207,7 @@ type State struct {
// IPPrefix, where the IP is the interface IP address and Bits is
// the subnet mask.
InterfaceIPs map[string][]netaddr.IPPrefix
- InterfaceUp map[string]bool
+ Interface map[string]Interface
// HaveV6Global is whether this machine has an IPv6 global address
// on some non-Tailscale interface that's up.
@@ -235,14 +238,14 @@ type State struct {
func (s *State) String() string {
var sb strings.Builder
fmt.Fprintf(&sb, "interfaces.State{defaultRoute=%v ifs={", s.DefaultRouteInterface)
- ifs := make([]string, 0, len(s.InterfaceUp))
- for k := range s.InterfaceUp {
+ ifs := make([]string, 0, len(s.Interface))
+ for k := range s.Interface {
if anyInterestingIP(s.InterfaceIPs[k]) {
ifs = append(ifs, k)
}
}
sort.Slice(ifs, func(i, j int) bool {
- upi, upj := s.InterfaceUp[ifs[i]], s.InterfaceUp[ifs[j]]
+ upi, upj := s.Interface[ifs[i]].IsUp(), s.Interface[ifs[j]].IsUp()
if upi != upj {
// Up sorts before down.
return upi
@@ -253,7 +256,7 @@ func (s *State) String() string {
if i > 0 {
sb.WriteString(" ")
}
- if s.InterfaceUp[ifName] {
+ if s.Interface[ifName].IsUp() {
fmt.Fprintf(&sb, "%s:[", ifName)
needSpace := false
for _, pfx := range s.InterfaceIPs[ifName] {
@@ -286,50 +289,76 @@ func (s *State) String() string {
return sb.String()
}
-func (s *State) Equal(s2 *State) bool {
- return reflect.DeepEqual(s, s2)
-}
-
-func (s *State) HasPAC() bool { return s != nil && s.PAC != "" }
-
-// AnyInterfaceUp reports whether any interface seems like it has Internet access.
-func (s *State) AnyInterfaceUp() bool {
- return s != nil && (s.HaveV4 || s.HaveV6Global)
-}
-
-// RemoveUninterestingInterfacesAndAddresses removes uninteresting IPs
-// from InterfaceIPs, also removing from both the InterfaceIPs and
-// InterfaceUp map any interfaces that don't have any interesting IPs.
-func (s *State) RemoveUninterestingInterfacesAndAddresses() {
- for ifName := range s.InterfaceUp {
- ips := s.InterfaceIPs[ifName]
- keep := ips[:0]
- for _, pfx := range ips {
- if isInterestingIP(pfx.IP) {
- keep = append(keep, pfx)
- }
- }
- if len(keep) == 0 {
- delete(s.InterfaceUp, ifName)
- delete(s.InterfaceIPs, ifName)
+// EqualFiltered reports whether s and s2 are equal,
+// considering only interfaces in s for which filter returns true.
+func (s *State) EqualFiltered(s2 *State, filter func(i Interface, ips []netaddr.IPPrefix) bool) bool {
+ if s == nil && s2 == nil {
+ return true
+ }
+ if s == nil || s2 == nil {
+ return false
+ }
+ if s.HaveV6Global != s2.HaveV6Global ||
+ s.HaveV4 != s2.HaveV4 ||
+ s.IsExpensive != s2.IsExpensive ||
+ s.DefaultRouteInterface != s2.DefaultRouteInterface ||
+ s.HTTPProxy != s2.HTTPProxy ||
+ s.PAC != s2.PAC {
+ return false
+ }
+ for iname, i := range s.Interface {
+ ips := s.InterfaceIPs[iname]
+ if !filter(i, ips) {
continue
}
- if len(keep) < len(ips) {
- s.InterfaceIPs[ifName] = keep
+ i2, ok := s2.Interface[iname]
+ if !ok {
+ return false
+ }
+ ips2, ok := s2.InterfaceIPs[iname]
+ if !ok {
+ return false
+ }
+ if !interfacesEqual(i, i2) || !prefixesEqual(ips, ips2) {
+ return false
}
}
+ return true
+}
+
+func interfacesEqual(a, b Interface) bool {
+ return a.Index == b.Index &&
+ a.MTU == b.MTU &&
+ a.Name == b.Name &&
+ a.Flags == b.Flags &&
+ bytes.Equal([]byte(a.HardwareAddr), []byte(b.HardwareAddr))
}
-// RemoveTailscaleInterfaces modifes s to remove any interfaces that
-// are owned by this process. (TODO: make this true; currently it
-// uses some heuristics)
-func (s *State) RemoveTailscaleInterfaces() {
- for name, pfxs := range s.InterfaceIPs {
- if isTailscaleInterface(name, pfxs) {
- delete(s.InterfaceIPs, name)
- delete(s.InterfaceUp, name)
+func prefixesEqual(a, b []netaddr.IPPrefix) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, v := range a {
+ if b[i] != v {
+ return false
}
}
+ return true
+}
+
+// FilterInteresting reports whether i is an interesting non-Tailscale interface.
+func FilterInteresting(i Interface, ips []netaddr.IPPrefix) bool {
+ return !isTailscaleInterface(i.Name, ips) && anyInterestingIP(ips)
+}
+
+// FilterAll always returns true, to use EqualFiltered against all interfaces.
+func FilterAll(i Interface, ips []netaddr.IPPrefix) bool { return true }
+
+func (s *State) HasPAC() bool { return s != nil && s.PAC != "" }
+
+// AnyInterfaceUp reports whether any interface seems like it has Internet access.
+func (s *State) AnyInterfaceUp() bool {
+ return s != nil && (s.HaveV4 || s.HaveV6Global)
}
func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool {
@@ -364,11 +393,11 @@ var getPAC func() string
func GetState() (*State, error) {
s := &State{
InterfaceIPs: make(map[string][]netaddr.IPPrefix),
- InterfaceUp: make(map[string]bool),
+ Interface: make(map[string]Interface),
}
if err := ForeachInterface(func(ni Interface, pfxs []netaddr.IPPrefix) {
ifUp := ni.IsUp()
- s.InterfaceUp[ni.Name] = ifUp
+ s.Interface[ni.Name] = ni
s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], pfxs...)
if !ifUp || isTailscaleInterface(ni.Name, pfxs) {
return