From 4f7d60ad42e82adaa4745baef03496a00f2002bd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 13 Feb 2021 21:06:27 -0800 Subject: [PATCH] wgengine/monitor: add a darwin implementation for tailscaled mode Tangentially related to #987, #177, #594, #925, #505 Motivated by rebooting a launchd-controlled tailscaled and it going into SetNetworkUp(false) mode immediately because there really is no network up at system boot, but then it got stuck in that paused state forever, without a monitor implementation. --- wgengine/monitor/monitor_darwin_tailscaled.go | 65 +++++++++++++++++++ wgengine/monitor/monitor_unsupported.go | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 wgengine/monitor/monitor_darwin_tailscaled.go diff --git a/wgengine/monitor/monitor_darwin_tailscaled.go b/wgengine/monitor/monitor_darwin_tailscaled.go new file mode 100644 index 000000000..2d53fc77e --- /dev/null +++ b/wgengine/monitor/monitor_darwin_tailscaled.go @@ -0,0 +1,65 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin,!redo + +package monitor + +import ( + "bufio" + "os/exec" + + "tailscale.com/types/logger" +) + +// unspecifiedMessage is a minimal message implementation that should not +// be ignored. In general, OS-specific implementations should use better +// types and avoid this if they can. +type unspecifiedMessage struct{} + +func (unspecifiedMessage) ignore() bool { return false } + +func newOSMon(logf logger.Logf) (osMon, error) { + return new(routeMonitorSubProcMon), nil +} + +// routeMonitorSubProcMon is a very simple (temporary? but I know +// better) monitor implementation for darwin in tailscaled-mode where +// we can just shell out to "route -n monitor". It waits for any input +// but doesn't parse it. Then we poll to see if something is different. +type routeMonitorSubProcMon struct { + cmd *exec.Cmd // of "/sbin/route -n monitor" + br *bufio.Reader + buf []byte +} + +func (m *routeMonitorSubProcMon) Close() error { + if m.cmd != nil { + m.cmd.Process.Kill() + m.cmd = nil + } + return nil +} + +func (m *routeMonitorSubProcMon) Receive() (message, error) { + if m.cmd == nil { + cmd := exec.Command("/sbin/route", "-n", "monitor") + outPipe, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + if err := cmd.Start(); err != nil { + return nil, err + } + m.br = bufio.NewReader(outPipe) + m.cmd = cmd + m.buf = make([]byte, 16<<10) + } + _, err := m.br.Read(m.buf) + if err != nil { + m.Close() + return nil, err + } + return unspecifiedMessage{}, nil +} diff --git a/wgengine/monitor/monitor_unsupported.go b/wgengine/monitor/monitor_unsupported.go index a54990c02..a779536e6 100644 --- a/wgengine/monitor/monitor_unsupported.go +++ b/wgengine/monitor/monitor_unsupported.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !linux,!freebsd,!windows android +// +build !linux,!freebsd,!windows,!darwin android darwin,redo package monitor