all: move network monitoring from wgengine/monitor to net/netmon

We're using it in more and more places, and it's not really specific to
our use of Wireguard (and does more just link/interface monitoring).

Also removes the separate interface we had for it in sockstats -- it's
a small enough package (we already pull in all of its dependencies
via other paths) that it's not worth the extra complexity.

Updates #7621
Updates #7850

Signed-off-by: Mihai Parparita <mihai@tailscale.com>
pull/7908/head
Mihai Parparita 2 years ago committed by Mihai Parparita
parent 3ede3aafe4
commit 4722f7e322

@ -16,7 +16,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
github.com/golang/protobuf/ptypes/timestamp from github.com/prometheus/client_model/go github.com/golang/protobuf/ptypes/timestamp from github.com/prometheus/client_model/go
github.com/hdevalence/ed25519consensus from tailscale.com/tka github.com/hdevalence/ed25519consensus from tailscale.com/tka
L github.com/josharian/native from github.com/mdlayher/netlink+ L github.com/josharian/native from github.com/mdlayher/netlink+
L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces+
L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink
github.com/klauspost/compress/flate from nhooyr.io/websocket github.com/klauspost/compress/flate from nhooyr.io/websocket
github.com/matttproud/golang_protobuf_extensions/pbutil from github.com/prometheus/common/expfmt github.com/matttproud/golang_protobuf_extensions/pbutil from github.com/prometheus/common/expfmt
@ -86,6 +86,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
💣 tailscale.com/net/interfaces from tailscale.com/net/netns+ 💣 tailscale.com/net/interfaces from tailscale.com/net/netns+
tailscale.com/net/netaddr from tailscale.com/ipn+ tailscale.com/net/netaddr from tailscale.com/ipn+
tailscale.com/net/netknob from tailscale.com/net/netns tailscale.com/net/netknob from tailscale.com/net/netns
tailscale.com/net/netmon from tailscale.com/net/sockstats
tailscale.com/net/netns from tailscale.com/derp/derphttp tailscale.com/net/netns from tailscale.com/derp/derphttp
tailscale.com/net/netutil from tailscale.com/client/tailscale tailscale.com/net/netutil from tailscale.com/client/tailscale
tailscale.com/net/packet from tailscale.com/wgengine/filter tailscale.com/net/packet from tailscale.com/wgengine/filter
@ -129,7 +130,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
tailscale.com/util/lineread from tailscale.com/hostinfo+ tailscale.com/util/lineread from tailscale.com/hostinfo+
tailscale.com/util/mak from tailscale.com/syncs+ tailscale.com/util/mak from tailscale.com/syncs+
tailscale.com/util/multierr from tailscale.com/health tailscale.com/util/multierr from tailscale.com/health
tailscale.com/util/set from tailscale.com/health tailscale.com/util/set from tailscale.com/health+
tailscale.com/util/singleflight from tailscale.com/net/dnscache tailscale.com/util/singleflight from tailscale.com/net/dnscache
tailscale.com/util/slicesx from tailscale.com/cmd/derper+ tailscale.com/util/slicesx from tailscale.com/cmd/derper+
tailscale.com/util/vizerror from tailscale.com/tsweb tailscale.com/util/vizerror from tailscale.com/tsweb

@ -13,7 +13,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
github.com/google/uuid from tailscale.com/util/quarantine+ github.com/google/uuid from tailscale.com/util/quarantine+
github.com/hdevalence/ed25519consensus from tailscale.com/tka github.com/hdevalence/ed25519consensus from tailscale.com/tka
L github.com/josharian/native from github.com/mdlayher/netlink+ L github.com/josharian/native from github.com/mdlayher/netlink+
L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces+
L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink
github.com/kballard/go-shellquote from tailscale.com/cmd/tailscale/cli github.com/kballard/go-shellquote from tailscale.com/cmd/tailscale/cli
github.com/klauspost/compress/flate from nhooyr.io/websocket github.com/klauspost/compress/flate from nhooyr.io/websocket
@ -74,6 +74,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli
tailscale.com/net/neterror from tailscale.com/net/netcheck+ tailscale.com/net/neterror from tailscale.com/net/netcheck+
tailscale.com/net/netknob from tailscale.com/net/netns tailscale.com/net/netknob from tailscale.com/net/netns
tailscale.com/net/netmon from tailscale.com/net/sockstats
tailscale.com/net/netns from tailscale.com/derp/derphttp+ tailscale.com/net/netns from tailscale.com/derp/derphttp+
tailscale.com/net/netutil from tailscale.com/client/tailscale+ tailscale.com/net/netutil from tailscale.com/client/tailscale+
tailscale.com/net/packet from tailscale.com/wgengine/filter+ tailscale.com/net/packet from tailscale.com/wgengine/filter+

@ -23,10 +23,10 @@ import (
"tailscale.com/derp/derphttp" "tailscale.com/derp/derphttp"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netmon"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/wgengine/monitor"
) )
var debugArgs struct { var debugArgs struct {
@ -42,7 +42,7 @@ var debugModeFunc = debugMode // so it can be addressable
func debugMode(args []string) error { func debugMode(args []string) error {
fs := flag.NewFlagSet("debug", flag.ExitOnError) fs := flag.NewFlagSet("debug", flag.ExitOnError)
fs.BoolVar(&debugArgs.ifconfig, "ifconfig", false, "If true, print network interface state") fs.BoolVar(&debugArgs.ifconfig, "ifconfig", false, "If true, print network interface state")
fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run link monitor forever. Precludes all other options.") fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run network monitor forever. Precludes all other options.")
fs.BoolVar(&debugArgs.portmap, "portmap", false, "If true, run portmap debugging. Precludes all other options.") fs.BoolVar(&debugArgs.portmap, "portmap", false, "If true, run portmap debugging. Precludes all other options.")
fs.StringVar(&debugArgs.getURL, "get-url", "", "If non-empty, fetch provided URL.") fs.StringVar(&debugArgs.getURL, "get-url", "", "If non-empty, fetch provided URL.")
fs.StringVar(&debugArgs.derpCheck, "derp", "", "if non-empty, test a DERP ping via named region code") fs.StringVar(&debugArgs.derpCheck, "derp", "", "if non-empty, test a DERP ping via named region code")
@ -76,7 +76,7 @@ func runMonitor(ctx context.Context, loop bool) error {
j, _ := json.MarshalIndent(st, "", " ") j, _ := json.MarshalIndent(st, "", " ")
os.Stderr.Write(j) os.Stderr.Write(j)
} }
mon, err := monitor.New(log.Printf) mon, err := netmon.New(log.Printf)
if err != nil { if err != nil {
return err return err
} }
@ -84,10 +84,10 @@ func runMonitor(ctx context.Context, loop bool) error {
mon.RegisterChangeCallback(func(changed bool, st *interfaces.State) { mon.RegisterChangeCallback(func(changed bool, st *interfaces.State) {
if !changed { if !changed {
log.Printf("Link monitor fired; no change") log.Printf("Network monitor fired; no change")
return return
} }
log.Printf("Link monitor fired. New state:") log.Printf("Network monitor fired. New state:")
dump(st) dump(st)
}) })
if loop { if loop {

@ -240,6 +240,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
tailscale.com/net/neterror from tailscale.com/net/dns/resolver+ tailscale.com/net/neterror from tailscale.com/net/dns/resolver+
tailscale.com/net/netknob from tailscale.com/net/netns+ tailscale.com/net/netknob from tailscale.com/net/netns+
tailscale.com/net/netmon from tailscale.com/cmd/tailscaled+
tailscale.com/net/netns from tailscale.com/derp/derphttp+ tailscale.com/net/netns from tailscale.com/derp/derphttp+
💣 tailscale.com/net/netstat from tailscale.com/ipn/ipnauth+ 💣 tailscale.com/net/netstat from tailscale.com/ipn/ipnauth+
tailscale.com/net/netutil from tailscale.com/ipn/ipnlocal+ tailscale.com/net/netutil from tailscale.com/ipn/ipnlocal+
@ -324,7 +325,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/wgengine/capture from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/capture from tailscale.com/ipn/ipnlocal+
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+ tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+ 💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
tailscale.com/wgengine/monitor from tailscale.com/control/controlclient+
tailscale.com/wgengine/netlog from tailscale.com/wgengine tailscale.com/wgengine/netlog from tailscale.com/wgengine
tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled
tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+

@ -39,6 +39,7 @@ import (
"tailscale.com/logtail" "tailscale.com/logtail"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/dnsfallback" "tailscale.com/net/dnsfallback"
"tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/proxymux" "tailscale.com/net/proxymux"
"tailscale.com/net/socks5" "tailscale.com/net/socks5"
@ -59,7 +60,6 @@ import (
"tailscale.com/version" "tailscale.com/version"
"tailscale.com/version/distro" "tailscale.com/version/distro"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netstack" "tailscale.com/wgengine/netstack"
"tailscale.com/wgengine/router" "tailscale.com/wgengine/router"
) )
@ -451,18 +451,18 @@ func startIPNServer(ctx context.Context, logf logger.Logf, logID logid.PublicID)
} }
func getLocalBackend(ctx context.Context, logf logger.Logf, logID logid.PublicID) (_ *ipnlocal.LocalBackend, retErr error) { func getLocalBackend(ctx context.Context, logf logger.Logf, logID logid.PublicID) (_ *ipnlocal.LocalBackend, retErr error) {
linkMon, err := monitor.New(logf) netMon, err := netmon.New(logf)
if err != nil { if err != nil {
return nil, fmt.Errorf("monitor.New: %w", err) return nil, fmt.Errorf("netmon.New: %w", err)
} }
if logPol != nil { if logPol != nil {
logPol.Logtail.SetLinkMonitor(linkMon) logPol.Logtail.SetNetMon(netMon)
} }
socksListener, httpProxyListener := mustStartProxyListeners(args.socksAddr, args.httpProxyAddr) socksListener, httpProxyListener := mustStartProxyListeners(args.socksAddr, args.httpProxyAddr)
dialer := &tsdial.Dialer{Logf: logf} // mutated below (before used) dialer := &tsdial.Dialer{Logf: logf} // mutated below (before used)
e, onlyNetstack, err := createEngine(logf, linkMon, dialer) e, onlyNetstack, err := createEngine(logf, netMon, dialer)
if err != nil { if err != nil {
return nil, fmt.Errorf("createEngine: %w", err) return nil, fmt.Errorf("createEngine: %w", err)
} }
@ -551,14 +551,14 @@ func getLocalBackend(ctx context.Context, logf logger.Logf, logID logid.PublicID
// //
// onlyNetstack is true if the user has explicitly requested that we use netstack // onlyNetstack is true if the user has explicitly requested that we use netstack
// for all networking. // for all networking.
func createEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer) (e wgengine.Engine, onlyNetstack bool, err error) { func createEngine(logf logger.Logf, netMon *netmon.Monitor, dialer *tsdial.Dialer) (e wgengine.Engine, onlyNetstack bool, err error) {
if args.tunname == "" { if args.tunname == "" {
return nil, false, errors.New("no --tun value specified") return nil, false, errors.New("no --tun value specified")
} }
var errs []error var errs []error
for _, name := range strings.Split(args.tunname, ",") { for _, name := range strings.Split(args.tunname, ",") {
logf("wgengine.NewUserspaceEngine(tun %q) ...", name) logf("wgengine.NewUserspaceEngine(tun %q) ...", name)
e, onlyNetstack, err = tryEngine(logf, linkMon, dialer, name) e, onlyNetstack, err = tryEngine(logf, netMon, dialer, name)
if err == nil { if err == nil {
return e, onlyNetstack, nil return e, onlyNetstack, nil
} }
@ -590,11 +590,11 @@ func handleSubnetsInNetstack() bool {
var tstunNew = tstun.New var tstunNew = tstun.New
func tryEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer, name string) (e wgengine.Engine, onlyNetstack bool, err error) { func tryEngine(logf logger.Logf, netMon *netmon.Monitor, dialer *tsdial.Dialer, name string) (e wgengine.Engine, onlyNetstack bool, err error) {
conf := wgengine.Config{ conf := wgengine.Config{
ListenPort: args.port, ListenPort: args.port,
LinkMonitor: linkMon, NetMon: netMon,
Dialer: dialer, Dialer: dialer,
} }
onlyNetstack = name == "userspace-networking" onlyNetstack = name == "userspace-networking"
@ -633,7 +633,7 @@ func tryEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer, na
return e, false, err return e, false, err
} }
r, err := router.New(logf, dev, linkMon) r, err := router.New(logf, dev, netMon)
if err != nil { if err != nil {
dev.Close() dev.Close()
return nil, false, fmt.Errorf("creating router: %w", err) return nil, false, fmt.Errorf("creating router: %w", err)

@ -37,6 +37,7 @@ import (
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/dnsfallback" "tailscale.com/net/dnsfallback"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netmon"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/net/tlsdial" "tailscale.com/net/tlsdial"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -54,7 +55,6 @@ import (
"tailscale.com/util/multierr" "tailscale.com/util/multierr"
"tailscale.com/util/singleflight" "tailscale.com/util/singleflight"
"tailscale.com/util/systemd" "tailscale.com/util/systemd"
"tailscale.com/wgengine/monitor"
) )
// Direct is the client that connects to a tailcontrol server for a node. // Direct is the client that connects to a tailcontrol server for a node.
@ -67,7 +67,7 @@ type Direct struct {
newDecompressor func() (Decompressor, error) newDecompressor func() (Decompressor, error)
keepAlive bool keepAlive bool
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon // or nil netMon *netmon.Monitor // or nil
discoPubKey key.DiscoPublic discoPubKey key.DiscoPublic
getMachinePrivKey func() (key.MachinePrivate, error) getMachinePrivKey func() (key.MachinePrivate, error)
debugFlags []string debugFlags []string
@ -113,7 +113,7 @@ type Options struct {
HTTPTestClient *http.Client // optional HTTP client to use (for tests only) HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only) NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only)
DebugFlags []string // debug settings to send to control DebugFlags []string // debug settings to send to control
LinkMonitor *monitor.Mon // optional link monitor NetMon *netmon.Monitor // optional network monitor
PopBrowserURL func(url string) // optional func to open browser PopBrowserURL func(url string) // optional func to open browser
OnClientVersion func(*tailcfg.ClientVersion) // optional func to inform GUI of client version status OnClientVersion func(*tailcfg.ClientVersion) // optional func to inform GUI of client version status
OnControlTime func(time.Time) // optional func to notify callers of new time from control OnControlTime func(time.Time) // optional func to notify callers of new time from control
@ -241,7 +241,7 @@ func NewDirect(opts Options) (*Direct, error) {
discoPubKey: opts.DiscoPublicKey, discoPubKey: opts.DiscoPublicKey,
debugFlags: opts.DebugFlags, debugFlags: opts.DebugFlags,
keepSharerAndUserSplit: opts.KeepSharerAndUserSplit, keepSharerAndUserSplit: opts.KeepSharerAndUserSplit,
linkMon: opts.LinkMonitor, netMon: opts.NetMon,
skipIPForwardingCheck: opts.SkipIPForwardingCheck, skipIPForwardingCheck: opts.SkipIPForwardingCheck,
pinger: opts.Pinger, pinger: opts.Pinger,
popBrowser: opts.PopBrowserURL, popBrowser: opts.PopBrowserURL,
@ -871,8 +871,8 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, readOnly bool
ReadOnly: readOnly && !allowStream, ReadOnly: readOnly && !allowStream,
} }
var extraDebugFlags []string var extraDebugFlags []string
if hi != nil && c.linkMon != nil && !c.skipIPForwardingCheck && if hi != nil && c.netMon != nil && !c.skipIPForwardingCheck &&
ipForwardingBroken(hi.RoutableIPs, c.linkMon.InterfaceState()) { ipForwardingBroken(hi.RoutableIPs, c.netMon.InterfaceState()) {
extraDebugFlags = append(extraDebugFlags, "warn-ip-forwarding-off") extraDebugFlags = append(extraDebugFlags, "warn-ip-forwarding-off")
} }
if health.RouterHealth() != nil { if health.RouterHealth() != nil {

@ -142,7 +142,7 @@ type LocalBackend struct {
store ipn.StateStore store ipn.StateStore
dialer *tsdial.Dialer // non-nil dialer *tsdial.Dialer // non-nil
backendLogID logid.PublicID backendLogID logid.PublicID
unregisterLinkMon func() unregisterNetMon func()
unregisterHealthWatch func() unregisterHealthWatch func()
portpoll *portlist.Poller // may be nil portpoll *portlist.Poller // may be nil
portpollOnce sync.Once // guards starting readPoller portpollOnce sync.Once // guards starting readPoller
@ -330,12 +330,12 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, store ipn.StateStor
b.statusChanged = sync.NewCond(&b.statusLock) b.statusChanged = sync.NewCond(&b.statusLock)
b.e.SetStatusCallback(b.setWgengineStatus) b.e.SetStatusCallback(b.setWgengineStatus)
linkMon := e.GetLinkMonitor() netMon := e.GetNetMon()
b.prevIfState = linkMon.InterfaceState() b.prevIfState = netMon.InterfaceState()
// Call our linkChange code once with the current state, and // Call our linkChange code once with the current state, and
// then also whenever it changes: // then also whenever it changes:
b.linkChange(false, linkMon.InterfaceState()) b.linkChange(false, netMon.InterfaceState())
b.unregisterLinkMon = linkMon.RegisterChangeCallback(b.linkChange) b.unregisterNetMon = netMon.RegisterChangeCallback(b.linkChange)
b.unregisterHealthWatch = health.RegisterWatcher(b.onHealthChange) b.unregisterHealthWatch = health.RegisterWatcher(b.onHealthChange)
@ -499,7 +499,7 @@ func (b *LocalBackend) maybePauseControlClientLocked() {
b.cc.SetPaused((b.state == ipn.Stopped && b.netMap != nil) || !networkUp) b.cc.SetPaused((b.state == ipn.Stopped && b.netMap != nil) || !networkUp)
} }
// linkChange is our link monitor callback, called whenever the network changes. // linkChange is our network monitor callback, called whenever the network changes.
// major is whether ifst is different than earlier. // major is whether ifst is different than earlier.
func (b *LocalBackend) linkChange(major bool, ifst *interfaces.State) { func (b *LocalBackend) linkChange(major bool, ifst *interfaces.State) {
b.mu.Lock() b.mu.Lock()
@ -576,7 +576,7 @@ func (b *LocalBackend) Shutdown() {
b.sockstatLogger.Shutdown() b.sockstatLogger.Shutdown()
} }
b.unregisterLinkMon() b.unregisterNetMon()
b.unregisterHealthWatch() b.unregisterHealthWatch()
if cc != nil { if cc != nil {
cc.Shutdown() cc.Shutdown()
@ -1423,7 +1423,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
HTTPTestClient: httpTestClient, HTTPTestClient: httpTestClient,
DiscoPublicKey: discoPublic, DiscoPublicKey: discoPublic,
DebugFlags: debugFlags, DebugFlags: debugFlags,
LinkMonitor: b.e.GetLinkMonitor(), NetMon: b.e.GetNetMon(),
Pinger: b, Pinger: b,
PopBrowserURL: b.tellClientToBrowseToURL, PopBrowserURL: b.tellClientToBrowseToURL,
OnClientVersion: b.onClientVersion, OnClientVersion: b.onClientVersion,

@ -143,7 +143,7 @@ func (s *serveListener) Run() {
} }
func (s *serveListener) shouldWarnAboutListenError(err error) bool { func (s *serveListener) shouldWarnAboutListenError(err error) bool {
if !s.b.e.GetLinkMonitor().InterfaceState().HasIP(s.ap.Addr()) { if !s.b.e.GetNetMon().InterfaceState().HasIP(s.ap.Addr()) {
// Machine likely doesn't have IPv6 enabled (or the IP is still being // Machine likely doesn't have IPv6 enabled (or the IP is still being
// assigned). No need to warn. Notably, WSL2 (Issue 6303). // assigned). No need to warn. Notably, WSL2 (Issue 6303).
return false return false

@ -34,6 +34,7 @@ import (
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/logtail" "tailscale.com/logtail"
"tailscale.com/net/netmon"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/net/portmapper" "tailscale.com/net/portmapper"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
@ -46,7 +47,6 @@ import (
"tailscale.com/util/httpm" "tailscale.com/util/httpm"
"tailscale.com/util/mak" "tailscale.com/util/mak"
"tailscale.com/version" "tailscale.com/version"
"tailscale.com/wgengine/monitor"
) )
type localAPIHandler func(*Handler, http.ResponseWriter, *http.Request) type localAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
@ -695,7 +695,7 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
}) })
defer c.Close() defer c.Close()
linkMon, err := monitor.New(logger.WithPrefix(logf, "monitor: ")) netMon, err := netmon.New(logger.WithPrefix(logf, "monitor: "))
if err != nil { if err != nil {
logf("error creating monitor: %v", err) logf("error creating monitor: %v", err)
return return
@ -707,14 +707,14 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
self = netip.MustParseAddr(b) self = netip.MustParseAddr(b)
return gw, self, true return gw, self, true
} }
return linkMon.GatewayAndSelfIP() return netMon.GatewayAndSelfIP()
} }
c.SetGatewayLookupFunc(gatewayAndSelfIP) c.SetGatewayLookupFunc(gatewayAndSelfIP)
gw, selfIP, ok := gatewayAndSelfIP() gw, selfIP, ok := gatewayAndSelfIP()
if !ok { if !ok {
logf("no gateway or self IP; %v", linkMon.InterfaceState()) logf("no gateway or self IP; %v", netMon.InterfaceState())
return return
} }
logf("gw=%v; self=%v", gw, selfIP) logf("gw=%v; self=%v", gw, selfIP)

@ -24,11 +24,11 @@ import (
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/logtail/backoff" "tailscale.com/logtail/backoff"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netmon"
"tailscale.com/net/sockstats" "tailscale.com/net/sockstats"
tslogger "tailscale.com/types/logger" tslogger "tailscale.com/types/logger"
"tailscale.com/types/logid" "tailscale.com/types/logid"
"tailscale.com/util/set" "tailscale.com/util/set"
"tailscale.com/wgengine/monitor"
) )
// DefaultHost is the default host name to upload logs to when // DefaultHost is the default host name to upload logs to when
@ -179,7 +179,7 @@ type Logger struct {
url string url string
lowMem bool lowMem bool
skipClientTime bool skipClientTime bool
linkMonitor *monitor.Mon netMonitor *netmon.Monitor
buffer Buffer buffer Buffer
drainWake chan struct{} // signal to speed up drain drainWake chan struct{} // signal to speed up drain
flushDelayFn func() time.Duration // negative or zero return value to upload aggressively, or >0 to batch at this delay flushDelayFn func() time.Duration // negative or zero return value to upload aggressively, or >0 to batch at this delay
@ -214,12 +214,12 @@ func (l *Logger) SetVerbosityLevel(level int) {
atomic.StoreInt64(&l.stderrLevel, int64(level)) atomic.StoreInt64(&l.stderrLevel, int64(level))
} }
// SetLinkMonitor sets the optional the link monitor. // SetNetMon sets the optional the network monitor.
// //
// It should not be changed concurrently with log writes and should // It should not be changed concurrently with log writes and should
// only be set once. // only be set once.
func (l *Logger) SetLinkMonitor(lm *monitor.Mon) { func (l *Logger) SetNetMon(lm *netmon.Monitor) {
l.linkMonitor = lm l.netMonitor = lm
} }
// SetSockstatsLabel sets the label used in sockstat logs to identify network traffic from this logger. // SetSockstatsLabel sets the label used in sockstat logs to identify network traffic from this logger.
@ -403,16 +403,16 @@ func (l *Logger) uploading(ctx context.Context) {
} }
func (l *Logger) internetUp() bool { func (l *Logger) internetUp() bool {
if l.linkMonitor == nil { if l.netMonitor == nil {
// No way to tell, so assume it is. // No way to tell, so assume it is.
return true return true
} }
return l.linkMonitor.InterfaceState().AnyInterfaceUp() return l.netMonitor.InterfaceState().AnyInterfaceUp()
} }
func (l *Logger) awaitInternetUp(ctx context.Context) { func (l *Logger) awaitInternetUp(ctx context.Context) {
upc := make(chan bool, 1) upc := make(chan bool, 1)
defer l.linkMonitor.RegisterChangeCallback(func(changed bool, st *interfaces.State) { defer l.netMonitor.RegisterChangeCallback(func(changed bool, st *interfaces.State) {
if st.AnyInterfaceUp() { if st.AnyInterfaceUp() {
select { select {
case upc <- true: case upc <- true:

@ -18,12 +18,12 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netmon"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/clientmetric" "tailscale.com/util/clientmetric"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/wgengine/monitor"
) )
var ( var (
@ -64,14 +64,14 @@ type Manager struct {
} }
// NewManagers created a new manager from the given config. // NewManagers created a new manager from the given config.
func NewManager(logf logger.Logf, oscfg OSConfigurator, linkMon *monitor.Mon, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector) *Manager { func NewManager(logf logger.Logf, oscfg OSConfigurator, netMon *netmon.Monitor, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector) *Manager {
if dialer == nil { if dialer == nil {
panic("nil Dialer") panic("nil Dialer")
} }
logf = logger.WithPrefix(logf, "dns: ") logf = logger.WithPrefix(logf, "dns: ")
m := &Manager{ m := &Manager{
logf: logf, logf: logf,
resolver: resolver.New(logf, linkMon, linkSel, dialer), resolver: resolver.New(logf, netMon, linkSel, dialer),
os: oscfg, os: oscfg,
} }
m.ctx, m.ctxCancel = context.WithCancel(context.Background()) m.ctx, m.ctxCancel = context.WithCancel(context.Background())

@ -25,6 +25,7 @@ import (
"tailscale.com/net/dns/publicdns" "tailscale.com/net/dns/publicdns"
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/neterror" "tailscale.com/net/neterror"
"tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/sockstats" "tailscale.com/net/sockstats"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -34,7 +35,6 @@ import (
"tailscale.com/util/cloudenv" "tailscale.com/util/cloudenv"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/version" "tailscale.com/version"
"tailscale.com/wgengine/monitor"
) )
// headerBytes is the number of bytes in a DNS message header. // headerBytes is the number of bytes in a DNS message header.
@ -176,7 +176,7 @@ type resolverAndDelay struct {
// forwarder forwards DNS packets to a number of upstream nameservers. // forwarder forwards DNS packets to a number of upstream nameservers.
type forwarder struct { type forwarder struct {
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon netMon *netmon.Monitor
linkSel ForwardLinkSelector // TODO(bradfitz): remove this when tsdial.Dialer absorbs it linkSel ForwardLinkSelector // TODO(bradfitz): remove this when tsdial.Dialer absorbs it
dialer *tsdial.Dialer dialer *tsdial.Dialer
@ -206,10 +206,10 @@ func init() {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
} }
func newForwarder(logf logger.Logf, linkMon *monitor.Mon, linkSel ForwardLinkSelector, dialer *tsdial.Dialer) *forwarder { func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer) *forwarder {
f := &forwarder{ f := &forwarder{
logf: logger.WithPrefix(logf, "forward: "), logf: logger.WithPrefix(logf, "forward: "),
linkMon: linkMon, netMon: netMon,
linkSel: linkSel, linkSel: linkSel,
dialer: dialer, dialer: dialer,
} }
@ -355,7 +355,7 @@ func (f *forwarder) packetListener(ip netip.Addr) (nettype.PacketListenerWithNet
return stdNetPacketListener, nil return stdNetPacketListener, nil
} }
lc := new(net.ListenConfig) lc := new(net.ListenConfig)
if err := initListenConfig(lc, f.linkMon, linkName); err != nil { if err := initListenConfig(lc, f.netMon, linkName); err != nil {
return nil, err return nil, err
} }
return nettype.MakePacketListenerWithNetIP(lc), nil return nettype.MakePacketListenerWithNetIP(lc), nil
@ -763,7 +763,7 @@ func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, respo
} }
} }
var initListenConfig func(_ *net.ListenConfig, _ *monitor.Mon, tunName string) error var initListenConfig func(_ *net.ListenConfig, _ *netmon.Monitor, tunName string) error
// nameFromQuery extracts the normalized query name from bs. // nameFromQuery extracts the normalized query name from bs.
func nameFromQuery(bs []byte) (dnsname.FQDN, error) { func nameFromQuery(bs []byte) (dnsname.FQDN, error) {

@ -9,15 +9,15 @@ import (
"errors" "errors"
"net" "net"
"tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/wgengine/monitor"
) )
func init() { func init() {
initListenConfig = initListenConfigNetworkExtension initListenConfig = initListenConfigNetworkExtension
} }
func initListenConfigNetworkExtension(nc *net.ListenConfig, mon *monitor.Mon, tunName string) error { func initListenConfigNetworkExtension(nc *net.ListenConfig, mon *netmon.Monitor, tunName string) error {
nif, ok := mon.InterfaceState().Interface[tunName] nif, ok := mon.InterfaceState().Interface[tunName]
if !ok { if !ok {
return errors.New("utun not found") return errors.New("utun not found")

@ -26,6 +26,7 @@ import (
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/net/dns/resolvconffile" "tailscale.com/net/dns/resolvconffile"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/syncs" "tailscale.com/syncs"
@ -34,7 +35,6 @@ import (
"tailscale.com/util/clientmetric" "tailscale.com/util/clientmetric"
"tailscale.com/util/cloudenv" "tailscale.com/util/cloudenv"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/wgengine/monitor"
) )
const dnsSymbolicFQDN = "magicdns.localhost-tailscale-daemon." const dnsSymbolicFQDN = "magicdns.localhost-tailscale-daemon."
@ -179,7 +179,7 @@ func WriteRoutes(w *bufio.Writer, routes map[dnsname.FQDN][]*dnstype.Resolver) {
// it delegates to upstream nameservers if any are set. // it delegates to upstream nameservers if any are set.
type Resolver struct { type Resolver struct {
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon // or nil netMon *netmon.Monitor // or nil
dialer *tsdial.Dialer // non-nil dialer *tsdial.Dialer // non-nil
saveConfigForTests func(cfg Config) // used in tests to capture resolver config saveConfigForTests func(cfg Config) // used in tests to capture resolver config
// forwarder forwards requests to upstream nameservers. // forwarder forwards requests to upstream nameservers.
@ -205,20 +205,20 @@ type ForwardLinkSelector interface {
} }
// New returns a new resolver. // New returns a new resolver.
// linkMon optionally specifies a link monitor to use for socket rebinding. // netMon optionally specifies a network monitor to use for socket rebinding.
func New(logf logger.Logf, linkMon *monitor.Mon, linkSel ForwardLinkSelector, dialer *tsdial.Dialer) *Resolver { func New(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer) *Resolver {
if dialer == nil { if dialer == nil {
panic("nil Dialer") panic("nil Dialer")
} }
r := &Resolver{ r := &Resolver{
logf: logger.WithPrefix(logf, "resolver: "), logf: logger.WithPrefix(logf, "resolver: "),
linkMon: linkMon, netMon: netMon,
closed: make(chan struct{}), closed: make(chan struct{}),
hostToIP: map[dnsname.FQDN][]netip.Addr{}, hostToIP: map[dnsname.FQDN][]netip.Addr{},
ipToHost: map[netip.Addr]dnsname.FQDN{}, ipToHost: map[netip.Addr]dnsname.FQDN{},
dialer: dialer, dialer: dialer,
} }
r.forwarder = newForwarder(r.logf, linkMon, linkSel, dialer) r.forwarder = newForwarder(r.logf, netMon, linkSel, dialer)
return r return r
} }

@ -24,11 +24,11 @@ import (
miekdns "github.com/miekg/dns" miekdns "github.com/miekg/dns"
dns "golang.org/x/net/dns/dnsmessage" dns "golang.org/x/net/dns/dnsmessage"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
"tailscale.com/net/netmon"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/wgengine/monitor"
) )
var ( var (
@ -315,7 +315,7 @@ func TestRDNSNameToIPv6(t *testing.T) {
} }
func newResolver(t testing.TB) *Resolver { func newResolver(t testing.TB) *Resolver {
return New(t.Logf, nil /* no link monitor */, nil /* no link selector */, new(tsdial.Dialer)) return New(t.Logf, nil /* no network monitor */, nil /* no link selector */, new(tsdial.Dialer))
} }
func TestResolveLocal(t *testing.T) { func TestResolveLocal(t *testing.T) {
@ -997,7 +997,7 @@ func TestMarshalResponseFormatError(t *testing.T) {
func TestForwardLinkSelection(t *testing.T) { func TestForwardLinkSelection(t *testing.T) {
configCall := make(chan string, 1) configCall := make(chan string, 1)
tstest.Replace(t, &initListenConfig, func(nc *net.ListenConfig, mon *monitor.Mon, tunName string) error { tstest.Replace(t, &initListenConfig, func(nc *net.ListenConfig, mon *netmon.Monitor, tunName string) error {
select { select {
case configCall <- tunName: case configCall <- tunName:
return nil return nil

@ -351,12 +351,6 @@ func (s *State) String() string {
return sb.String() return sb.String()
} }
// ChangeFunc is a callback function (usually registered with
// wgengine/monitor's Mon) that's called when the network
// changed. The changed parameter is whether the network changed
// enough for State to have changed since the last callback.
type ChangeFunc func(changed bool, state *State)
// An InterfaceFilter indicates whether EqualFiltered should use i when deciding whether two States are equal. // An InterfaceFilter indicates whether EqualFiltered should use i when deciding whether two States are equal.
// ips are all the IPPrefixes associated with i. // ips are all the IPPrefixes associated with i.
type InterfaceFilter func(i Interface, ips []netip.Prefix) bool type InterfaceFilter func(i Interface, ips []netip.Prefix) bool

@ -167,8 +167,8 @@ func defaultRoute() (d DefaultRouteDetails, err error) {
// /proc/net/route. Use netlink to find the default route. // /proc/net/route. Use netlink to find the default route.
// //
// TODO(bradfitz): this allocates a fair bit. We should track // TODO(bradfitz): this allocates a fair bit. We should track
// this in wgengine/monitor instead and have // this in net/interfaces/monitor instead and have
// interfaces.GetState take a link monitor or similar so the // interfaces.GetState take a netmon.Monitor or similar so the
// routing table can be cached and the monitor's existing // routing table can be cached and the monitor's existing
// subscription to route changes can update the cached state, // subscription to route changes can update the cached state,
// rather than querying the whole thing every time like // rather than querying the whole thing every time like

@ -4,7 +4,7 @@
// Package monitor provides facilities for monitoring network // Package monitor provides facilities for monitoring network
// interface and route changes. It primarily exists to know when // interface and route changes. It primarily exists to know when
// portable devices move between different networks. // portable devices move between different networks.
package monitor package netmon
import ( import (
"encoding/json" "encoding/json"
@ -48,15 +48,15 @@ type osMon interface {
IsInterestingInterface(iface string) bool IsInterestingInterface(iface string) bool
} }
// Mon represents a monitoring instance. // Monitor represents a monitoring instance.
type Mon struct { type Monitor struct {
logf logger.Logf logf logger.Logf
om osMon // nil means not supported on this platform om osMon // nil means not supported on this platform
change chan struct{} change chan struct{}
stop chan struct{} // closed on Stop stop chan struct{} // closed on Stop
mu sync.Mutex // guards all following fields mu sync.Mutex // guards all following fields
cbs set.HandleSet[interfaces.ChangeFunc] cbs set.HandleSet[ChangeFunc]
ruleDelCB set.HandleSet[RuleDeleteCallback] ruleDelCB set.HandleSet[RuleDeleteCallback]
ifState *interfaces.State ifState *interfaces.State
gwValid bool // whether gw and gwSelfIP are valid gwValid bool // whether gw and gwSelfIP are valid
@ -70,12 +70,17 @@ type Mon struct {
timeJumped bool // whether we need to send a changed=true after a big time jump timeJumped bool // whether we need to send a changed=true after a big time jump
} }
// ChangeFunc is a callback function registered with Monitor that's called when the
// network changed. The changed parameter is whether the network changed
// enough for State to have changed since the last callback.
type ChangeFunc func(changed bool, state *interfaces.State)
// New instantiates and starts a monitoring instance. // New instantiates and starts a monitoring instance.
// The returned monitor is inactive until it's started by the Start method. // The returned monitor is inactive until it's started by the Start method.
// Use RegisterChangeCallback to get notified of network changes. // Use RegisterChangeCallback to get notified of network changes.
func New(logf logger.Logf) (*Mon, error) { func New(logf logger.Logf) (*Monitor, error) {
logf = logger.WithPrefix(logf, "monitor: ") logf = logger.WithPrefix(logf, "monitor: ")
m := &Mon{ m := &Monitor{
logf: logf, logf: logf,
change: make(chan struct{}, 1), change: make(chan struct{}, 1),
stop: make(chan struct{}), stop: make(chan struct{}),
@ -102,13 +107,13 @@ func New(logf logger.Logf) (*Mon, error) {
// interfaces. // interfaces.
// //
// The returned value is owned by Mon; it must not be modified. // The returned value is owned by Mon; it must not be modified.
func (m *Mon) InterfaceState() *interfaces.State { func (m *Monitor) InterfaceState() *interfaces.State {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
return m.ifState return m.ifState
} }
func (m *Mon) interfaceStateUncached() (*interfaces.State, error) { func (m *Monitor) interfaceStateUncached() (*interfaces.State, error) {
return interfaces.GetState() return interfaces.GetState()
} }
@ -117,7 +122,7 @@ func (m *Mon) interfaceStateUncached() (*interfaces.State, error) {
// //
// It's the same as interfaces.LikelyHomeRouterIP, but it caches the // It's the same as interfaces.LikelyHomeRouterIP, but it caches the
// result until the monitor detects a network change. // result until the monitor detects a network change.
func (m *Mon) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) { func (m *Monitor) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if m.gwValid { if m.gwValid {
@ -133,7 +138,7 @@ func (m *Mon) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
// RegisterChangeCallback adds callback to the set of parties to be // RegisterChangeCallback adds callback to the set of parties to be
// notified (in their own goroutine) when the network state changes. // notified (in their own goroutine) when the network state changes.
// To remove this callback, call unregister (or close the monitor). // To remove this callback, call unregister (or close the monitor).
func (m *Mon) RegisterChangeCallback(callback interfaces.ChangeFunc) (unregister func()) { func (m *Monitor) RegisterChangeCallback(callback ChangeFunc) (unregister func()) {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
handle := m.cbs.Add(callback) handle := m.cbs.Add(callback)
@ -153,7 +158,7 @@ type RuleDeleteCallback func(table uint8, priority uint32)
// RegisterRuleDeleteCallback adds callback to the set of parties to be // RegisterRuleDeleteCallback adds callback to the set of parties to be
// notified (in their own goroutine) when a Linux ip rule is deleted. // notified (in their own goroutine) when a Linux ip rule is deleted.
// To remove this callback, call unregister (or close the monitor). // To remove this callback, call unregister (or close the monitor).
func (m *Mon) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unregister func()) { func (m *Monitor) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unregister func()) {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
handle := m.ruleDelCB.Add(callback) handle := m.ruleDelCB.Add(callback)
@ -166,7 +171,7 @@ func (m *Mon) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unregiste
// Start starts the monitor. // Start starts the monitor.
// A monitor can only be started & closed once. // A monitor can only be started & closed once.
func (m *Mon) Start() { func (m *Monitor) Start() {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if m.started || m.closed { if m.started || m.closed {
@ -187,7 +192,7 @@ func (m *Mon) Start() {
} }
// Close closes the monitor. // Close closes the monitor.
func (m *Mon) Close() error { func (m *Monitor) Close() error {
m.mu.Lock() m.mu.Lock()
if m.closed { if m.closed {
m.mu.Unlock() m.mu.Unlock()
@ -218,7 +223,7 @@ func (m *Mon) Close() error {
// change and re-check the state of the network. Any registered // change and re-check the state of the network. Any registered
// ChangeFunc callbacks will be called within the event coalescing // ChangeFunc callbacks will be called within the event coalescing
// period (under a fraction of a second). // period (under a fraction of a second).
func (m *Mon) InjectEvent() { func (m *Monitor) InjectEvent() {
select { select {
case m.change <- struct{}{}: case m.change <- struct{}{}:
default: default:
@ -228,7 +233,7 @@ func (m *Mon) InjectEvent() {
} }
} }
func (m *Mon) stopped() bool { func (m *Monitor) stopped() bool {
select { select {
case <-m.stop: case <-m.stop:
return true return true
@ -239,7 +244,7 @@ func (m *Mon) stopped() bool {
// pump continuously retrieves messages from the connection, notifying // pump continuously retrieves messages from the connection, notifying
// the change channel of changes, and stopping when a stop is issued. // the change channel of changes, and stopping when a stop is issued.
func (m *Mon) pump() { func (m *Monitor) pump() {
defer m.goroutines.Done() defer m.goroutines.Done()
for !m.stopped() { for !m.stopped() {
msg, err := m.om.Receive() msg, err := m.om.Receive()
@ -263,7 +268,7 @@ func (m *Mon) pump() {
} }
} }
func (m *Mon) notifyRuleDeleted(rdm ipRuleDeletedMessage) { func (m *Monitor) notifyRuleDeleted(rdm ipRuleDeletedMessage) {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
for _, cb := range m.ruleDelCB { for _, cb := range m.ruleDelCB {
@ -274,13 +279,13 @@ func (m *Mon) notifyRuleDeleted(rdm ipRuleDeletedMessage) {
// isInterestingInterface reports whether the provided interface should be // isInterestingInterface reports whether the provided interface should be
// considered when checking for network state changes. // considered when checking for network state changes.
// The ips parameter should be the IPs of the provided interface. // The ips parameter should be the IPs of the provided interface.
func (m *Mon) isInterestingInterface(i interfaces.Interface, ips []netip.Prefix) bool { func (m *Monitor) isInterestingInterface(i interfaces.Interface, ips []netip.Prefix) bool {
return m.om.IsInterestingInterface(i.Name) && interfaces.UseInterestingInterfaces(i, ips) return m.om.IsInterestingInterface(i.Name) && interfaces.UseInterestingInterfaces(i, ips)
} }
// debounce calls the callback function with a delay between events // debounce calls the callback function with a delay between events
// and exits when a stop is issued. // and exits when a stop is issued.
func (m *Mon) debounce() { func (m *Monitor) debounce() {
defer m.goroutines.Done() defer m.goroutines.Done()
for { for {
select { select {
@ -343,7 +348,7 @@ func wallTime() time.Time {
return time.Now().Round(0) return time.Now().Round(0)
} }
func (m *Mon) pollWallTime() { func (m *Monitor) pollWallTime() {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if m.closed { if m.closed {
@ -365,7 +370,7 @@ const shouldMonitorTimeJump = runtime.GOOS != "android" && runtime.GOOS != "ios"
// checkWallTimeAdvanceLocked reports whether wall time jumped more than 150% of // checkWallTimeAdvanceLocked reports whether wall time jumped more than 150% of
// pollWallTimeInterval, indicating we probably just came out of sleep. Once a // pollWallTimeInterval, indicating we probably just came out of sleep. Once a
// time jump is detected it must be reset by calling resetTimeJumpedLocked. // time jump is detected it must be reset by calling resetTimeJumpedLocked.
func (m *Mon) checkWallTimeAdvanceLocked() bool { func (m *Monitor) checkWallTimeAdvanceLocked() bool {
if !shouldMonitorTimeJump { if !shouldMonitorTimeJump {
panic("unreachable") // if callers are correct panic("unreachable") // if callers are correct
} }
@ -378,7 +383,7 @@ func (m *Mon) checkWallTimeAdvanceLocked() bool {
} }
// resetTimeJumpedLocked consumes the signal set by checkWallTimeAdvanceLocked. // resetTimeJumpedLocked consumes the signal set by checkWallTimeAdvanceLocked.
func (m *Mon) resetTimeJumpedLocked() { func (m *Monitor) resetTimeJumpedLocked() {
m.timeJumped = false m.timeJumped = false
} }

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"fmt" "fmt"
@ -24,7 +24,7 @@ type unspecifiedMessage struct{}
func (unspecifiedMessage) ignore() bool { return false } func (unspecifiedMessage) ignore() bool { return false }
func newOSMon(logf logger.Logf, _ *Mon) (osMon, error) { func newOSMon(logf logger.Logf, _ *Monitor) (osMon, error) {
fd, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0) fd, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0)
if err != nil { if err != nil {
return nil, err return nil, err

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"encoding/hex" "encoding/hex"

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"bufio" "bufio"
@ -24,7 +24,7 @@ type devdConn struct {
conn net.Conn conn net.Conn
} }
func newOSMon(logf logger.Logf, m *Mon) (osMon, error) { func newOSMon(logf logger.Logf, m *Monitor) (osMon, error) {
conn, err := net.Dial("unixpacket", "/var/run/devd.seqpacket.pipe") conn, err := net.Dial("unixpacket", "/var/run/devd.seqpacket.pipe")
if err != nil { if err != nil {
logf("devd dial error: %v, falling back to polling method", err) logf("devd dial error: %v, falling back to polling method", err)

@ -3,7 +3,7 @@
//go:build !android //go:build !android
package monitor package netmon
import ( import (
"net" "net"
@ -44,7 +44,7 @@ type nlConn struct {
addrCache map[uint32]map[netip.Addr]bool addrCache map[uint32]map[netip.Addr]bool
} }
func newOSMon(logf logger.Logf, m *Mon) (osMon, error) { func newOSMon(logf logger.Logf, m *Monitor) (osMon, error) {
conn, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{ conn, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{
// Routes get us most of the events of interest, but we need // Routes get us most of the events of interest, but we need
// address as well to cover things like DHCP deciding to give // address as well to cover things like DHCP deciding to give

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"net" "net"

@ -3,13 +3,13 @@
//go:build (!linux && !freebsd && !windows && !darwin) || android //go:build (!linux && !freebsd && !windows && !darwin) || android
package monitor package netmon
import ( import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
func newOSMon(logf logger.Logf, m *Mon) (osMon, error) { func newOSMon(logf logger.Logf, m *Monitor) (osMon, error) {
return newPollingMon(logf, m) return newPollingMon(logf, m)
} }

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"flag" "flag"

@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS // Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
package monitor package netmon
import ( import (
"context" "context"
@ -44,7 +44,7 @@ type winMon struct {
noDeadlockTicker *time.Ticker noDeadlockTicker *time.Ticker
} }
func newOSMon(logf logger.Logf, _ *Mon) (osMon, error) { func newOSMon(logf logger.Logf, _ *Monitor) (osMon, error) {
m := &winMon{ m := &winMon{
logf: logf, logf: logf,
messagec: make(chan eventMessage, 1), messagec: make(chan eventMessage, 1),

@ -3,7 +3,7 @@
//go:build !windows && !darwin //go:build !windows && !darwin
package monitor package netmon
import ( import (
"bytes" "bytes"
@ -17,7 +17,7 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
func newPollingMon(logf logger.Logf, m *Mon) (osMon, error) { func newPollingMon(logf logger.Logf, m *Monitor) (osMon, error) {
return &pollingMon{ return &pollingMon{
logf: logf, logf: logf,
m: m, m: m,
@ -30,7 +30,7 @@ func newPollingMon(logf logger.Logf, m *Mon) (osMon, error) {
// of anything to subscribe to. // of anything to subscribe to.
type pollingMon struct { type pollingMon struct {
logf logger.Logf logf logger.Logf
m *Mon m *Monitor
closeOnce sync.Once closeOnce sync.Once
stop chan struct{} stop chan struct{}

@ -11,7 +11,7 @@ package sockstats
import ( import (
"context" "context"
"tailscale.com/net/interfaces" "tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
@ -107,17 +107,10 @@ func GetValidation() *ValidationSockStats {
return getValidation() return getValidation()
} }
// LinkMonitor is the interface for the parts of wgengine/mointor's Mon that we // SetNetMon configures the sockstats package to monitor the active
// need, to avoid the dependency.
type LinkMonitor interface {
InterfaceState() *interfaces.State
RegisterChangeCallback(interfaces.ChangeFunc) (unregister func())
}
// SetLinkMonitor configures the sockstats package to monitor the active
// interface, so that per-interface stats can be collected. // interface, so that per-interface stats can be collected.
func SetLinkMonitor(lm LinkMonitor) { func SetNetMon(lm *netmon.Monitor) {
setLinkMonitor(lm) setNetMon(lm)
} }
// DebugInfo returns a string containing debug information about the tracked // DebugInfo returns a string containing debug information about the tracked

@ -8,6 +8,7 @@ package sockstats
import ( import (
"context" "context"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
@ -29,7 +30,7 @@ func getValidation() *ValidationSockStats {
return nil return nil
} }
func setLinkMonitor(lm LinkMonitor) { func setNetMon(lm *netmon.Monitor) {
} }
func debugInfo() string { func debugInfo() string {

@ -16,6 +16,7 @@ import (
"time" "time"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/clientmetric" "tailscale.com/util/clientmetric"
) )
@ -84,7 +85,7 @@ func withSockStats(ctx context.Context, label Label, logf logger.Logf) context.C
rxBytesCellularMetric: clientmetric.NewCounter(fmt.Sprintf("sockstats_rx_bytes_cellular_%s", label)), rxBytesCellularMetric: clientmetric.NewCounter(fmt.Sprintf("sockstats_rx_bytes_cellular_%s", label)),
} }
// We might be called before setLinkMonitor has been called (and we've // We might be called before setNetMon has been called (and we've
// had a chance to populate knownInterfaces). In that case, we'll have // had a chance to populate knownInterfaces). In that case, we'll have
// to get the list of interfaces ourselves. // to get the list of interfaces ourselves.
if len(sockStats.knownInterfaces) == 0 { if len(sockStats.knownInterfaces) == 0 {
@ -248,7 +249,7 @@ func getValidation() *ValidationSockStats {
return r return r
} }
func setLinkMonitor(lm LinkMonitor) { func setNetMon(lm *netmon.Monitor) {
sockStats.mu.Lock() sockStats.mu.Lock()
defer sockStats.mu.Unlock() defer sockStats.mu.Unlock()

@ -20,11 +20,11 @@ import (
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netknob" "tailscale.com/net/netknob"
"tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/util/mak" "tailscale.com/util/mak"
"tailscale.com/wgengine/monitor"
) )
// Dialer dials out of tailscaled, while taking care of details while // Dialer dials out of tailscaled, while taking care of details while
@ -50,16 +50,16 @@ type Dialer struct {
netnsDialerOnce sync.Once netnsDialerOnce sync.Once
netnsDialer netns.Dialer netnsDialer netns.Dialer
mu sync.Mutex mu sync.Mutex
closed bool closed bool
dns dnsMap dns dnsMap
tunName string // tun device name tunName string // tun device name
linkMon *monitor.Mon netMon *netmon.Monitor
linkMonUnregister func() netMonUnregister func()
exitDNSDoHBase string // non-empty if DoH-proxying exit node in use; base URL+path (without '?') exitDNSDoHBase string // non-empty if DoH-proxying exit node in use; base URL+path (without '?')
dnsCache *dnscache.MessageCache // nil until first non-empty SetExitDNSDoH dnsCache *dnscache.MessageCache // nil until first non-empty SetExitDNSDoH
nextSysConnID int nextSysConnID int
activeSysConns map[int]net.Conn // active connections not yet closed activeSysConns map[int]net.Conn // active connections not yet closed
} }
// sysConn wraps a net.Conn that was created using d.SystemDial. // sysConn wraps a net.Conn that was created using d.SystemDial.
@ -117,9 +117,9 @@ func (d *Dialer) Close() error {
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
d.closed = true d.closed = true
if d.linkMonUnregister != nil { if d.netMonUnregister != nil {
d.linkMonUnregister() d.netMonUnregister()
d.linkMonUnregister = nil d.netMonUnregister = nil
} }
for _, c := range d.activeSysConns { for _, c := range d.activeSysConns {
c.Close() c.Close()
@ -128,15 +128,15 @@ func (d *Dialer) Close() error {
return nil return nil
} }
func (d *Dialer) SetLinkMonitor(mon *monitor.Mon) { func (d *Dialer) SetNetMon(mon *netmon.Monitor) {
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
if d.linkMonUnregister != nil { if d.netMonUnregister != nil {
go d.linkMonUnregister() go d.netMonUnregister()
d.linkMonUnregister = nil d.netMonUnregister = nil
} }
d.linkMon = mon d.netMon = mon
d.linkMonUnregister = d.linkMon.RegisterChangeCallback(d.linkChanged) d.netMonUnregister = d.netMon.RegisterChangeCallback(d.linkChanged)
} }
func (d *Dialer) linkChanged(major bool, state *interfaces.State) { func (d *Dialer) linkChanged(major bool, state *interfaces.State) {
@ -163,10 +163,10 @@ func (d *Dialer) closeSysConn(id int) {
} }
func (d *Dialer) interfaceIndexLocked(ifName string) (index int, ok bool) { func (d *Dialer) interfaceIndexLocked(ifName string) (index int, ok bool) {
if d.linkMon == nil { if d.netMon == nil {
return 0, false return 0, false
} }
st := d.linkMon.InterfaceState() st := d.netMon.InterfaceState()
iface, ok := st.Interface[ifName] iface, ok := st.Interface[ifName]
if !ok { if !ok {
return 0, false return 0, false

@ -42,6 +42,7 @@ import (
"tailscale.com/logtail" "tailscale.com/logtail"
"tailscale.com/logtail/filch" "tailscale.com/logtail/filch"
"tailscale.com/net/memnet" "tailscale.com/net/memnet"
"tailscale.com/net/netmon"
"tailscale.com/net/proxymux" "tailscale.com/net/proxymux"
"tailscale.com/net/socks5" "tailscale.com/net/socks5"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -51,7 +52,6 @@ import (
"tailscale.com/types/nettype" "tailscale.com/types/nettype"
"tailscale.com/util/mak" "tailscale.com/util/mak"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netstack" "tailscale.com/wgengine/netstack"
) )
@ -106,7 +106,7 @@ type Server struct {
initErr error initErr error
lb *ipnlocal.LocalBackend lb *ipnlocal.LocalBackend
netstack *netstack.Impl netstack *netstack.Impl
linkMon *monitor.Mon netMon *netmon.Monitor
rootPath string // the state directory rootPath string // the state directory
hostname string hostname string
shutdownCtx context.Context shutdownCtx context.Context
@ -356,8 +356,8 @@ func (s *Server) Close() error {
if s.lb != nil { if s.lb != nil {
s.lb.Shutdown() s.lb.Shutdown()
} }
if s.linkMon != nil { if s.netMon != nil {
s.linkMon.Close() s.netMon.Close()
} }
if s.dialer != nil { if s.dialer != nil {
s.dialer.Close() s.dialer.Close()
@ -476,17 +476,17 @@ func (s *Server) start() (reterr error) {
return err return err
} }
s.linkMon, err = monitor.New(logf) s.netMon, err = netmon.New(logf)
if err != nil { if err != nil {
return err return err
} }
closePool.add(s.linkMon) closePool.add(s.netMon)
s.dialer = &tsdial.Dialer{Logf: logf} // mutated below (before used) s.dialer = &tsdial.Dialer{Logf: logf} // mutated below (before used)
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
ListenPort: 0, ListenPort: 0,
LinkMonitor: s.linkMon, NetMon: s.netMon,
Dialer: s.dialer, Dialer: s.dialer,
}) })
if err != nil { if err != nil {
return err return err

@ -24,6 +24,7 @@ import (
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/dnsfallback" _ "tailscale.com/net/dnsfallback"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netmon"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"
_ "tailscale.com/net/socks5" _ "tailscale.com/net/socks5"
@ -47,7 +48,6 @@ import (
_ "tailscale.com/version" _ "tailscale.com/version"
_ "tailscale.com/version/distro" _ "tailscale.com/version/distro"
_ "tailscale.com/wgengine" _ "tailscale.com/wgengine"
_ "tailscale.com/wgengine/monitor"
_ "tailscale.com/wgengine/netstack" _ "tailscale.com/wgengine/netstack"
_ "tailscale.com/wgengine/router" _ "tailscale.com/wgengine/router"
) )

@ -24,6 +24,7 @@ import (
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/dnsfallback" _ "tailscale.com/net/dnsfallback"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netmon"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"
_ "tailscale.com/net/socks5" _ "tailscale.com/net/socks5"
@ -47,7 +48,6 @@ import (
_ "tailscale.com/version" _ "tailscale.com/version"
_ "tailscale.com/version/distro" _ "tailscale.com/version/distro"
_ "tailscale.com/wgengine" _ "tailscale.com/wgengine"
_ "tailscale.com/wgengine/monitor"
_ "tailscale.com/wgengine/netstack" _ "tailscale.com/wgengine/netstack"
_ "tailscale.com/wgengine/router" _ "tailscale.com/wgengine/router"
) )

@ -24,6 +24,7 @@ import (
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/dnsfallback" _ "tailscale.com/net/dnsfallback"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netmon"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"
_ "tailscale.com/net/socks5" _ "tailscale.com/net/socks5"
@ -47,7 +48,6 @@ import (
_ "tailscale.com/version" _ "tailscale.com/version"
_ "tailscale.com/version/distro" _ "tailscale.com/version/distro"
_ "tailscale.com/wgengine" _ "tailscale.com/wgengine"
_ "tailscale.com/wgengine/monitor"
_ "tailscale.com/wgengine/netstack" _ "tailscale.com/wgengine/netstack"
_ "tailscale.com/wgengine/router" _ "tailscale.com/wgengine/router"
) )

@ -24,6 +24,7 @@ import (
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/dnsfallback" _ "tailscale.com/net/dnsfallback"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netmon"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"
_ "tailscale.com/net/socks5" _ "tailscale.com/net/socks5"
@ -47,7 +48,6 @@ import (
_ "tailscale.com/version" _ "tailscale.com/version"
_ "tailscale.com/version/distro" _ "tailscale.com/version/distro"
_ "tailscale.com/wgengine" _ "tailscale.com/wgengine"
_ "tailscale.com/wgengine/monitor"
_ "tailscale.com/wgengine/netstack" _ "tailscale.com/wgengine/netstack"
_ "tailscale.com/wgengine/router" _ "tailscale.com/wgengine/router"
) )

@ -32,6 +32,7 @@ import (
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/dnsfallback" _ "tailscale.com/net/dnsfallback"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netmon"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"
_ "tailscale.com/net/socks5" _ "tailscale.com/net/socks5"
@ -56,7 +57,6 @@ import (
_ "tailscale.com/version/distro" _ "tailscale.com/version/distro"
_ "tailscale.com/wf" _ "tailscale.com/wf"
_ "tailscale.com/wgengine" _ "tailscale.com/wgengine"
_ "tailscale.com/wgengine/monitor"
_ "tailscale.com/wgengine/netstack" _ "tailscale.com/wgengine/netstack"
_ "tailscale.com/wgengine/router" _ "tailscale.com/wgengine/router"
) )

@ -39,10 +39,10 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
traf: traf, traf: traf,
} }
e1, err := wgengine.NewUserspaceEngine(l1, wgengine.Config{ e1, err := wgengine.NewUserspaceEngine(l1, wgengine.Config{
Router: router.NewFake(l1), Router: router.NewFake(l1),
LinkMonitor: nil, NetMon: nil,
ListenPort: 0, ListenPort: 0,
Tun: t1, Tun: t1,
}) })
if err != nil { if err != nil {
log.Fatalf("e1 init: %v", err) log.Fatalf("e1 init: %v", err)
@ -63,10 +63,10 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
traf: traf, traf: traf,
} }
e2, err := wgengine.NewUserspaceEngine(l2, wgengine.Config{ e2, err := wgengine.NewUserspaceEngine(l2, wgengine.Config{
Router: router.NewFake(l2), Router: router.NewFake(l2),
LinkMonitor: nil, NetMon: nil,
ListenPort: 0, ListenPort: 0,
Tun: t2, Tun: t2,
}) })
if err != nil { if err != nil {
log.Fatalf("e2 init: %v", err) log.Fatalf("e2 init: %v", err)

@ -47,6 +47,7 @@ import (
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
"tailscale.com/net/netcheck" "tailscale.com/net/netcheck"
"tailscale.com/net/neterror" "tailscale.com/net/neterror"
"tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/portmapper" "tailscale.com/net/portmapper"
@ -69,7 +70,6 @@ import (
"tailscale.com/util/uniq" "tailscale.com/util/uniq"
"tailscale.com/version" "tailscale.com/version"
"tailscale.com/wgengine/capture" "tailscale.com/wgengine/capture"
"tailscale.com/wgengine/monitor"
) )
const ( const (
@ -279,7 +279,7 @@ type Conn struct {
idleFunc func() time.Duration // nil means unknown idleFunc func() time.Duration // nil means unknown
testOnlyPacketListener nettype.PacketListener testOnlyPacketListener nettype.PacketListener
noteRecvActivity func(key.NodePublic) // or nil, see Options.NoteRecvActivity noteRecvActivity func(key.NodePublic) // or nil, see Options.NoteRecvActivity
linkMon *monitor.Mon // or nil netMon *netmon.Monitor // or nil
// ================================================================ // ================================================================
// No locking required to access these fields, either because // No locking required to access these fields, either because
@ -573,9 +573,9 @@ type Options struct {
// not hold Conn.mu while calling it. // not hold Conn.mu while calling it.
NoteRecvActivity func(key.NodePublic) NoteRecvActivity func(key.NodePublic)
// LinkMonitor is the link monitor to use. // NetMon is the network monitor to use.
// With one, the portmapper won't be used. // With one, the portmapper won't be used.
LinkMonitor *monitor.Mon NetMon *netmon.Monitor
} }
func (o *Options) logf() logger.Logf { func (o *Options) logf() logger.Logf {
@ -643,10 +643,10 @@ func NewConn(opts Options) (*Conn, error) {
c.testOnlyPacketListener = opts.TestOnlyPacketListener c.testOnlyPacketListener = opts.TestOnlyPacketListener
c.noteRecvActivity = opts.NoteRecvActivity c.noteRecvActivity = opts.NoteRecvActivity
c.portMapper = portmapper.NewClient(logger.WithPrefix(c.logf, "portmapper: "), nil, c.onPortMapChanged) c.portMapper = portmapper.NewClient(logger.WithPrefix(c.logf, "portmapper: "), nil, c.onPortMapChanged)
if opts.LinkMonitor != nil { if opts.NetMon != nil {
c.portMapper.SetGatewayLookupFunc(opts.LinkMonitor.GatewayAndSelfIP) c.portMapper.SetGatewayLookupFunc(opts.NetMon.GatewayAndSelfIP)
} }
c.linkMon = opts.LinkMonitor c.netMon = opts.NetMon
if err := c.rebind(keepCurrentPort); err != nil { if err := c.rebind(keepCurrentPort); err != nil {
return nil, err return nil, err
@ -3369,8 +3369,8 @@ func (c *Conn) Rebind() {
} }
var ifIPs []netip.Prefix var ifIPs []netip.Prefix
if c.linkMon != nil { if c.netMon != nil {
st := c.linkMon.InterfaceState() st := c.netMon.InterfaceState()
defIf := st.DefaultRouteInterface defIf := st.DefaultRouteInterface
ifIPs = st.InterfaceIPs[defIf] ifIPs = st.InterfaceIPs[defIf]
c.logf("Rebind; defIf=%q, ips=%v", defIf, ifIPs) c.logf("Rebind; defIf=%q, ips=%v", defIf, ifIPs)

@ -10,9 +10,9 @@ import (
"reflect" "reflect"
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/preftype" "tailscale.com/types/preftype"
"tailscale.com/wgengine/monitor"
) )
// Router is responsible for managing the system network stack. // Router is responsible for managing the system network stack.
@ -34,11 +34,11 @@ type Router interface {
// New returns a new Router for the current platform, using the // New returns a new Router for the current platform, using the
// provided tun device. // provided tun device.
// //
// If linkMon is nil, it's not used. It's currently (2021-07-20) only // If netMon is nil, it's not used. It's currently (2021-07-20) only
// used on Linux in some situations. // used on Linux in some situations.
func New(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func New(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
logf = logger.WithPrefix(logf, "router: ") logf = logger.WithPrefix(logf, "router: ")
return newUserspaceRouter(logf, tundev, linkMon) return newUserspaceRouter(logf, tundev, netMon)
} }
// Cleanup restores the system network configuration to its original state // Cleanup restores the system network configuration to its original state

@ -5,12 +5,12 @@ package router
import ( import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
return newUserspaceBSDRouter(logf, tundev, linkMon) return newUserspaceBSDRouter(logf, tundev, netMon)
} }
func cleanup(logger.Logf, string) { func cleanup(logger.Logf, string) {

@ -10,11 +10,11 @@ import (
"runtime" "runtime"
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor) (Router, error) {
return nil, fmt.Errorf("unsupported OS %q", runtime.GOOS) return nil, fmt.Errorf("unsupported OS %q", runtime.GOOS)
} }

@ -5,8 +5,8 @@ package router
import ( import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
// For now this router only supports the userspace WireGuard implementations. // For now this router only supports the userspace WireGuard implementations.
@ -14,8 +14,8 @@ import (
// Work is currently underway for an in-kernel FreeBSD implementation of wireguard // Work is currently underway for an in-kernel FreeBSD implementation of wireguard
// https://svnweb.freebsd.org/base?view=revision&revision=357986 // https://svnweb.freebsd.org/base?view=revision&revision=357986
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
return newUserspaceBSDRouter(logf, tundev, linkMon) return newUserspaceBSDRouter(logf, tundev, netMon)
} }
func cleanup(logf logger.Logf, interfaceName string) { func cleanup(logf logger.Logf, interfaceName string) {

@ -24,12 +24,12 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/preftype" "tailscale.com/types/preftype"
"tailscale.com/util/multierr" "tailscale.com/util/multierr"
"tailscale.com/version/distro" "tailscale.com/version/distro"
"tailscale.com/wgengine/monitor"
) )
const ( const (
@ -94,8 +94,8 @@ type linuxRouter struct {
closed atomic.Bool closed atomic.Bool
logf func(fmt string, args ...any) logf func(fmt string, args ...any)
tunname string tunname string
linkMon *monitor.Mon netMon *netmon.Monitor
unregLinkMon func() unregNetMon func()
addrs map[netip.Prefix]bool addrs map[netip.Prefix]bool
routes map[netip.Prefix]bool routes map[netip.Prefix]bool
localRoutes map[netip.Prefix]bool localRoutes map[netip.Prefix]bool
@ -121,7 +121,7 @@ type linuxRouter struct {
cmd commandRunner cmd commandRunner
} }
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor) (Router, error) {
tunname, err := tunDev.Name() tunname, err := tunDev.Name()
if err != nil { if err != nil {
return nil, err return nil, err
@ -156,15 +156,15 @@ func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, linkMon *monitor.Mo
ambientCapNetAdmin: useAmbientCaps(), ambientCapNetAdmin: useAmbientCaps(),
} }
return newUserspaceRouterAdvanced(logf, tunname, linkMon, ipt4, ipt6, cmd, supportsV6, supportsV6NAT) return newUserspaceRouterAdvanced(logf, tunname, netMon, ipt4, ipt6, cmd, supportsV6, supportsV6NAT)
} }
func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, linkMon *monitor.Mon, netfilter4, netfilter6 netfilterRunner, cmd commandRunner, supportsV6, supportsV6NAT bool) (Router, error) { func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, netMon *netmon.Monitor, netfilter4, netfilter6 netfilterRunner, cmd commandRunner, supportsV6, supportsV6NAT bool) (Router, error) {
r := &linuxRouter{ r := &linuxRouter{
logf: logf, logf: logf,
tunname: tunname, tunname: tunname,
netfilterMode: netfilterOff, netfilterMode: netfilterOff,
linkMon: linkMon, netMon: netMon,
v6Available: supportsV6, v6Available: supportsV6,
v6NATAvailable: supportsV6NAT, v6NATAvailable: supportsV6NAT,
@ -336,8 +336,8 @@ func (r *linuxRouter) useIPCommand() bool {
return !ok return !ok
} }
// onIPRuleDeleted is the callback from the link monitor for when an IP policy // onIPRuleDeleted is the callback from the network monitor for when an IP
// rule is deleted. See Issue 1591. // policy rule is deleted. See Issue 1591.
// //
// If an ip rule is deleted (with pref number 52xx, as Tailscale sets), then // If an ip rule is deleted (with pref number 52xx, as Tailscale sets), then
// set a timer to restore our rules, in case they were deleted. The timer lets // set a timer to restore our rules, in case they were deleted. The timer lets
@ -372,8 +372,8 @@ func (r *linuxRouter) onIPRuleDeleted(table uint8, priority uint32) {
} }
func (r *linuxRouter) Up() error { func (r *linuxRouter) Up() error {
if r.unregLinkMon == nil && r.linkMon != nil { if r.unregNetMon == nil && r.netMon != nil {
r.unregLinkMon = r.linkMon.RegisterRuleDeleteCallback(r.onIPRuleDeleted) r.unregNetMon = r.netMon.RegisterRuleDeleteCallback(r.onIPRuleDeleted)
} }
if err := r.addIPRules(); err != nil { if err := r.addIPRules(); err != nil {
return fmt.Errorf("adding IP rules: %w", err) return fmt.Errorf("adding IP rules: %w", err)
@ -390,8 +390,8 @@ func (r *linuxRouter) Up() error {
func (r *linuxRouter) Close() error { func (r *linuxRouter) Close() error {
r.closed.Store(true) r.closed.Store(true)
if r.unregLinkMon != nil { if r.unregNetMon != nil {
r.unregLinkMon() r.unregNetMon()
} }
if err := r.downInterface(); err != nil { if err := r.downInterface(); err != nil {
return err return err

@ -21,9 +21,9 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"tailscale.com/net/netmon"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
func TestRouterStates(t *testing.T) { func TestRouterStates(t *testing.T) {
@ -320,7 +320,7 @@ ip route add throw 192.168.0.0/24 table 52` + basic,
}, },
} }
mon, err := monitor.New(logger.Discard) mon, err := netmon.New(logger.Discard)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -659,7 +659,7 @@ func createTestTUN(t *testing.T) tun.Device {
type linuxTest struct { type linuxTest struct {
tun tun.Device tun tun.Device
mon *monitor.Mon mon *netmon.Monitor
r *linuxRouter r *linuxRouter
logOutput tstest.MemLogger logOutput tstest.MemLogger
} }
@ -684,7 +684,7 @@ func newLinuxRootTest(t *testing.T) *linuxTest {
logf := lt.logOutput.Logf logf := lt.logOutput.Logf
mon, err := monitor.New(logger.Discard) mon, err := netmon.New(logger.Discard)
if err != nil { if err != nil {
lt.Close() lt.Close()
t.Fatal(err) t.Fatal(err)

@ -12,8 +12,8 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"go4.org/netipx" "go4.org/netipx"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
// For now this router only supports the WireGuard userspace implementation. // For now this router only supports the WireGuard userspace implementation.
@ -22,14 +22,14 @@ import (
type openbsdRouter struct { type openbsdRouter struct {
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon netMon *netmon.Monitor
tunname string tunname string
local4 netip.Prefix local4 netip.Prefix
local6 netip.Prefix local6 netip.Prefix
routes map[netip.Prefix]struct{} routes map[netip.Prefix]struct{}
} }
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
tunname, err := tundev.Name() tunname, err := tundev.Name()
if err != nil { if err != nil {
return nil, err return nil, err
@ -37,7 +37,7 @@ func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mo
return &openbsdRouter{ return &openbsdRouter{
logf: logf, logf: logf,
linkMon: linkMon, netMon: netMon,
tunname: tunname, tunname: tunname,
}, nil }, nil
} }

@ -14,21 +14,21 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"go4.org/netipx" "go4.org/netipx"
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/version" "tailscale.com/version"
"tailscale.com/wgengine/monitor"
) )
type userspaceBSDRouter struct { type userspaceBSDRouter struct {
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon netMon *netmon.Monitor
tunname string tunname string
local []netip.Prefix local []netip.Prefix
routes map[netip.Prefix]bool routes map[netip.Prefix]bool
} }
func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
tunname, err := tundev.Name() tunname, err := tundev.Name()
if err != nil { if err != nil {
return nil, err return nil, err
@ -36,7 +36,7 @@ func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor
return &userspaceBSDRouter{ return &userspaceBSDRouter{
logf: logf, logf: logf,
linkMon: linkMon, netMon: netMon,
tunname: tunname, tunname: tunname,
}, nil }, nil
} }

@ -22,19 +22,19 @@ import (
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"tailscale.com/logtail/backoff" "tailscale.com/logtail/backoff"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netmon"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
) )
type winRouter struct { type winRouter struct {
logf func(fmt string, args ...any) logf func(fmt string, args ...any)
linkMon *monitor.Mon // may be nil netMon *netmon.Monitor // may be nil
nativeTun *tun.NativeTun nativeTun *tun.NativeTun
routeChangeCallback *winipcfg.RouteChangeCallback routeChangeCallback *winipcfg.RouteChangeCallback
firewall *firewallTweaker firewall *firewallTweaker
} }
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mon) (Router, error) { func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
nativeTun := tundev.(*tun.NativeTun) nativeTun := tundev.(*tun.NativeTun)
luid := winipcfg.LUID(nativeTun.LUID()) luid := winipcfg.LUID(nativeTun.LUID())
guid, err := luid.GUID() guid, err := luid.GUID()
@ -44,7 +44,7 @@ func newUserspaceRouter(logf logger.Logf, tundev tun.Device, linkMon *monitor.Mo
return &winRouter{ return &winRouter{
logf: logf, logf: logf,
linkMon: linkMon, netMon: netMon,
nativeTun: nativeTun, nativeTun: nativeTun,
firewall: &firewallTweaker{ firewall: &firewallTweaker{
logf: logger.WithPrefix(logf, "firewall: "), logf: logger.WithPrefix(logf, "firewall: "),

@ -28,6 +28,7 @@ import (
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/flowtrack" "tailscale.com/net/flowtrack"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netmon"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/sockstats" "tailscale.com/net/sockstats"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
@ -48,7 +49,6 @@ import (
"tailscale.com/wgengine/capture" "tailscale.com/wgengine/capture"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/magicsock"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netlog" "tailscale.com/wgengine/netlog"
"tailscale.com/wgengine/router" "tailscale.com/wgengine/router"
"tailscale.com/wgengine/wgcfg" "tailscale.com/wgengine/wgcfg"
@ -84,21 +84,21 @@ const statusPollInterval = 1 * time.Minute
const networkLoggerUploadTimeout = 5 * time.Second const networkLoggerUploadTimeout = 5 * time.Second
type userspaceEngine struct { type userspaceEngine struct {
logf logger.Logf logf logger.Logf
wgLogger *wglog.Logger //a wireguard-go logging wrapper wgLogger *wglog.Logger //a wireguard-go logging wrapper
reqCh chan struct{} reqCh chan struct{}
waitCh chan struct{} // chan is closed when first Close call completes; contrast with closing bool waitCh chan struct{} // chan is closed when first Close call completes; contrast with closing bool
timeNow func() mono.Time timeNow func() mono.Time
tundev *tstun.Wrapper tundev *tstun.Wrapper
wgdev *device.Device wgdev *device.Device
router router.Router router router.Router
confListenPort uint16 // original conf.ListenPort confListenPort uint16 // original conf.ListenPort
dns *dns.Manager dns *dns.Manager
magicConn *magicsock.Conn magicConn *magicsock.Conn
linkMon *monitor.Mon netMon *netmon.Monitor
linkMonOwned bool // whether we created linkMon (and thus need to close it) netMonOwned bool // whether we created netMon (and thus need to close it)
linkMonUnregister func() // unsubscribes from changes; used regardless of linkMonOwned netMonUnregister func() // unsubscribes from changes; used regardless of netMonOwned
birdClient BIRDClient // or nil birdClient BIRDClient // or nil
testMaybeReconfigHook func() // for tests; if non-nil, fires if maybeReconfigWireguardLocked called testMaybeReconfigHook func() // for tests; if non-nil, fires if maybeReconfigWireguardLocked called
@ -199,9 +199,9 @@ type Config struct {
// If nil, a fake OSConfigurator that does nothing is used. // If nil, a fake OSConfigurator that does nothing is used.
DNS dns.OSConfigurator DNS dns.OSConfigurator
// LinkMonitor optionally provides an existing link monitor to re-use. // NetMon optionally provides an existing network monitor to re-use.
// If nil, a new link monitor is created. // If nil, a new network monitor is created.
LinkMonitor *monitor.Mon NetMon *netmon.Monitor
// Dialer is the dialer to use for outbound connections. // Dialer is the dialer to use for outbound connections.
// If nil, a new Dialer is created // If nil, a new Dialer is created
@ -316,34 +316,34 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(nil)) e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(nil))
e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(nil)) e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(nil))
if conf.LinkMonitor != nil { if conf.NetMon != nil {
e.linkMon = conf.LinkMonitor e.netMon = conf.NetMon
} else { } else {
mon, err := monitor.New(logf) mon, err := netmon.New(logf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
closePool.add(mon) closePool.add(mon)
e.linkMon = mon e.netMon = mon
e.linkMonOwned = true e.netMonOwned = true
} }
tunName, _ := conf.Tun.Name() tunName, _ := conf.Tun.Name()
conf.Dialer.SetTUNName(tunName) conf.Dialer.SetTUNName(tunName)
conf.Dialer.SetLinkMonitor(e.linkMon) conf.Dialer.SetNetMon(e.netMon)
e.dns = dns.NewManager(logf, conf.DNS, e.linkMon, conf.Dialer, fwdDNSLinkSelector{e, tunName}) e.dns = dns.NewManager(logf, conf.DNS, e.netMon, conf.Dialer, fwdDNSLinkSelector{e, tunName})
// TODO: there's probably a better place for this // TODO: there's probably a better place for this
sockstats.SetLinkMonitor(e.linkMon) sockstats.SetNetMon(e.netMon)
logf("link state: %+v", e.linkMon.InterfaceState()) logf("link state: %+v", e.netMon.InterfaceState())
unregisterMonWatch := e.linkMon.RegisterChangeCallback(func(changed bool, st *interfaces.State) { unregisterMonWatch := e.netMon.RegisterChangeCallback(func(changed bool, st *interfaces.State) {
tshttpproxy.InvalidateCache() tshttpproxy.InvalidateCache()
e.linkChange(changed, st) e.linkChange(changed, st)
}) })
closePool.addFunc(unregisterMonWatch) closePool.addFunc(unregisterMonWatch)
e.linkMonUnregister = unregisterMonWatch e.netMonUnregister = unregisterMonWatch
endpointsFn := func(endpoints []tailcfg.Endpoint) { endpointsFn := func(endpoints []tailcfg.Endpoint) {
e.mu.Lock() e.mu.Lock()
@ -359,7 +359,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
DERPActiveFunc: e.RequestStatus, DERPActiveFunc: e.RequestStatus,
IdleFunc: e.tundev.IdleDuration, IdleFunc: e.tundev.IdleDuration,
NoteRecvActivity: e.noteRecvActivity, NoteRecvActivity: e.noteRecvActivity,
LinkMonitor: e.linkMon, NetMon: e.netMon,
} }
var err error var err error
@ -368,7 +368,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
return nil, fmt.Errorf("wgengine: %v", err) return nil, fmt.Errorf("wgengine: %v", err)
} }
closePool.add(e.magicConn) closePool.add(e.magicConn)
e.magicConn.SetNetworkUp(e.linkMon.InterfaceState().AnyInterfaceUp()) e.magicConn.SetNetworkUp(e.netMon.InterfaceState().AnyInterfaceUp())
tsTUNDev.SetDiscoKey(e.magicConn.DiscoPublicKey()) tsTUNDev.SetDiscoKey(e.magicConn.DiscoPublicKey())
@ -455,8 +455,8 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
if err := e.router.Set(nil); err != nil { if err := e.router.Set(nil); err != nil {
return nil, fmt.Errorf("router.Set(nil): %w", err) return nil, fmt.Errorf("router.Set(nil): %w", err)
} }
e.logf("Starting link monitor...") e.logf("Starting network monitor...")
e.linkMon.Start() e.netMon.Start()
e.logf("Engine created.") e.logf("Engine created.")
return e, nil return e, nil
@ -1094,9 +1094,9 @@ func (e *userspaceEngine) Close() {
r := bufio.NewReader(strings.NewReader("")) r := bufio.NewReader(strings.NewReader(""))
e.wgdev.IpcSetOperation(r) e.wgdev.IpcSetOperation(r)
e.magicConn.Close() e.magicConn.Close()
e.linkMonUnregister() e.netMonUnregister()
if e.linkMonOwned { if e.netMonOwned {
e.linkMon.Close() e.netMon.Close()
} }
e.dns.Down() e.dns.Down()
e.router.Close() e.router.Close()
@ -1119,15 +1119,15 @@ func (e *userspaceEngine) Wait() {
<-e.waitCh <-e.waitCh
} }
func (e *userspaceEngine) GetLinkMonitor() *monitor.Mon { func (e *userspaceEngine) GetNetMon() *netmon.Monitor {
return e.linkMon return e.netMon
} }
// LinkChange signals a network change event. It's currently // LinkChange signals a network change event. It's currently
// (2021-03-03) only called on Android. On other platforms, linkMon // (2021-03-03) only called on Android. On other platforms, netMon
// generates link change events for us. // generates link change events for us.
func (e *userspaceEngine) LinkChange(_ bool) { func (e *userspaceEngine) LinkChange(_ bool) {
e.linkMon.InjectEvent() e.netMon.InjectEvent()
} }
func (e *userspaceEngine) linkChange(changed bool, cur *interfaces.State) { func (e *userspaceEngine) linkChange(changed bool, cur *interfaces.State) {

@ -18,6 +18,7 @@ import (
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netmon"
"tailscale.com/net/tstun" "tailscale.com/net/tstun"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
@ -25,7 +26,6 @@ import (
"tailscale.com/wgengine/capture" "tailscale.com/wgengine/capture"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/magicsock"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/router" "tailscale.com/wgengine/router"
"tailscale.com/wgengine/wgcfg" "tailscale.com/wgengine/wgcfg"
) )
@ -126,8 +126,8 @@ func (e *watchdogEngine) watchdog(name string, fn func()) {
func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *dns.Config, debug *tailcfg.Debug) error { func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *dns.Config, debug *tailcfg.Debug) error {
return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, dnsCfg, debug) }) return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, dnsCfg, debug) })
} }
func (e *watchdogEngine) GetLinkMonitor() *monitor.Mon { func (e *watchdogEngine) GetNetMon() *netmon.Monitor {
return e.wrap.GetLinkMonitor() return e.wrap.GetNetMon()
} }
func (e *watchdogEngine) GetFilter() *filter.Filter { func (e *watchdogEngine) GetFilter() *filter.Filter {
return e.wrap.GetFilter() return e.wrap.GetFilter()

@ -10,12 +10,12 @@ import (
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netmon"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/wgengine/capture" "tailscale.com/wgengine/capture"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/router" "tailscale.com/wgengine/router"
"tailscale.com/wgengine/wgcfg" "tailscale.com/wgengine/wgcfg"
) )
@ -92,8 +92,8 @@ type Engine interface {
// WireGuard status changes. // WireGuard status changes.
SetStatusCallback(StatusCallback) SetStatusCallback(StatusCallback)
// GetLinkMonitor returns the link monitor. // GetNetMon returns the network monitor.
GetLinkMonitor() *monitor.Mon GetNetMon() *netmon.Monitor
// RequestStatus requests a WireGuard status update right // RequestStatus requests a WireGuard status update right
// away, sent to the callback registered via SetStatusCallback. // away, sent to the callback registered via SetStatusCallback.
@ -119,7 +119,7 @@ type Engine interface {
// //
// Deprecated: don't use this method. It was removed shortly // Deprecated: don't use this method. It was removed shortly
// before the Tailscale 1.6 release when we remembered that // before the Tailscale 1.6 release when we remembered that
// Android doesn't use the Linux-based link monitor and has // Android doesn't use the Linux-based network monitor and has
// its own mechanism that uses LinkChange. Android is the only // its own mechanism that uses LinkChange. Android is the only
// caller of this method now. Don't add more. // caller of this method now. Don't add more.
LinkChange(isExpensive bool) LinkChange(isExpensive bool)

Loading…
Cancel
Save