From 1ac570def79335b97b2fb2dd699cbc6618e0b11e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 30 Apr 2020 13:20:09 -0700 Subject: [PATCH] wgengine/router: split out from wgengine. The router implementations are logically separate, with their own API. Signed-off-by: David Anderson --- cmd/tailscaled/tailscaled.go | 11 +++- ipn/e2e_test.go | 3 +- scripts/check_license_headers.sh | 2 +- wgengine/{ => router}/ifconfig_windows.go | 2 +- wgengine/router/router.go | 57 +++++++++++++++++++ wgengine/{ => router}/router_darwin.go | 4 +- .../{ => router}/router_darwin_support.go | 2 +- wgengine/{ => router}/router_default.go | 4 +- wgengine/{ => router}/router_fake.go | 8 +-- wgengine/{ => router}/router_freebsd.go | 4 +- wgengine/{ => router}/router_linux.go | 4 +- wgengine/{ => router}/router_openbsd.go | 4 +- wgengine/{ => router}/router_windows.go | 4 +- wgengine/userspace.go | 19 ++++--- wgengine/watchdog_test.go | 6 +- wgengine/wgengine.go | 49 ---------------- 16 files changed, 98 insertions(+), 85 deletions(-) rename wgengine/{ => router}/ifconfig_windows.go (99%) create mode 100644 wgengine/router/router.go rename wgengine/{ => router}/router_darwin.go (93%) rename wgengine/{ => router}/router_darwin_support.go (98%) rename wgengine/{ => router}/router_default.go (90%) rename wgengine/{ => router}/router_fake.go (75%) rename wgengine/{ => router}/router_freebsd.go (98%) rename wgengine/{ => router}/router_linux.go (99%) rename wgengine/{ => router}/router_openbsd.go (99%) rename wgengine/{ => router}/router_windows.go (96%) diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index a6fc9ad8f..7cded7647 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -14,6 +14,7 @@ "log" "net/http" "net/http/pprof" + "runtime" "github.com/apenwarr/fixconsole" "github.com/pborman/getopt/v2" @@ -33,10 +34,18 @@ // later, the global state key doesn't look like a username. const globalStateKey = "_daemon" +var defaultTunName = "tailscale0" + +func init() { + if runtime.GOOS == "openbsd" { + defaultTunName = "tun" + } +} + func main() { fake := getopt.BoolLong("fake", 0, "fake tunnel+routing instead of tuntap") debug := getopt.StringLong("debug", 0, "", "Address of debug server") - tunname := getopt.StringLong("tun", 0, wgengine.DefaultTunName, "tunnel interface name") + tunname := getopt.StringLong("tun", 0, defaultTunName, "tunnel interface name") listenport := getopt.Uint16Long("port", 'p', magicsock.DefaultPort, "WireGuard port (0=autoselect)") statepath := getopt.StringLong("state", 0, paths.DefaultTailscaledStateFile(), "Path of state file") socketpath := getopt.StringLong("socket", 's', paths.DefaultTailscaledSocket(), "Path of the service unix socket") diff --git a/ipn/e2e_test.go b/ipn/e2e_test.go index 398ae0f71..5dd7c642e 100644 --- a/ipn/e2e_test.go +++ b/ipn/e2e_test.go @@ -24,6 +24,7 @@ "tailscale.com/tstest" "tailscale.com/wgengine" "tailscale.com/wgengine/magicsock" + "tailscale.com/wgengine/router" "tailscale.io/control" // not yet released ) @@ -196,7 +197,7 @@ func newNode(t *testing.T, prefix string, https *httptest.Server) testNode { } tun := tuntest.NewChannelTUN() - e1, err := wgengine.NewUserspaceEngineAdvanced(logfe, tun.TUN(), wgengine.NewFakeRouter, 0) + e1, err := wgengine.NewUserspaceEngineAdvanced(logfe, tun.TUN(), router.NewFake, 0) if err != nil { t.Fatalf("NewFakeEngine: %v\n", err) } diff --git a/scripts/check_license_headers.sh b/scripts/check_license_headers.sh index 29bb2eee5..7264fa2a3 100755 --- a/scripts/check_license_headers.sh +++ b/scripts/check_license_headers.sh @@ -35,7 +35,7 @@ for file in $(find $1 -name '*.go'); do $1/tempfork/*) # Skip, tempfork of third-party code ;; - $1/wgengine/ifconfig_windows.go) + $1/wgengine/router/ifconfig_windows.go) # WireGuard copyright. ;; *) diff --git a/wgengine/ifconfig_windows.go b/wgengine/router/ifconfig_windows.go similarity index 99% rename from wgengine/ifconfig_windows.go rename to wgengine/router/ifconfig_windows.go index f22aacc2c..7b5a6352f 100644 --- a/wgengine/ifconfig_windows.go +++ b/wgengine/router/ifconfig_windows.go @@ -3,7 +3,7 @@ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. */ -package wgengine +package router import ( "bytes" diff --git a/wgengine/router/router.go b/wgengine/router/router.go new file mode 100644 index 000000000..dac043200 --- /dev/null +++ b/wgengine/router/router.go @@ -0,0 +1,57 @@ +// Copyright (c) 2020 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. + +// Package router presents an interface to manipulate the host network +// stack's state. +package router + +import ( + "fmt" + + "github.com/tailscale/wireguard-go/device" + "github.com/tailscale/wireguard-go/tun" + "github.com/tailscale/wireguard-go/wgcfg" + "tailscale.com/types/logger" +) + +// Router is responsible for managing the system network stack. +// +// There is typically only one instance of this interface per process. +type Router interface { + // Up brings the router up. + Up() error + + // SetRoutes is called regularly on network map updates. + // It's how you kernel route table entries are populated for + // each peer. + SetRoutes(RouteSettings) error + + // Close closes the router. + Close() error +} + +// NewUserspaceRouter returns a new Router for the current platform, using the provided tun device. +func New(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, error) { + return newUserspaceRouter(logf, wgdev, tundev) +} + +// RouteSettings is the full WireGuard config data (set of peers keys, +// IP, etc in wgcfg.Config) plus the things that WireGuard doesn't do +// itself, like DNS stuff. +type RouteSettings struct { + LocalAddr wgcfg.CIDR // TODO: why is this here? how does it differ from wgcfg.Config's info? + DNS []wgcfg.IP + DNSDomains []string + Cfg *wgcfg.Config +} + +// OnlyRelevantParts returns a string minimally describing the route settings. +func (rs *RouteSettings) OnlyRelevantParts() string { + var peers [][]wgcfg.CIDR + for _, p := range rs.Cfg.Peers { + peers = append(peers, p.AllowedIPs) + } + return fmt.Sprintf("%v %v %v %v", + rs.LocalAddr, rs.DNS, rs.DNSDomains, peers) +} diff --git a/wgengine/router_darwin.go b/wgengine/router/router_darwin.go similarity index 93% rename from wgengine/router_darwin.go rename to wgengine/router/router_darwin.go index 44b089b2f..f1c80d619 100644 --- a/wgengine/router_darwin.go +++ b/wgengine/router/router_darwin.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. -package wgengine +package router import ( "github.com/tailscale/wireguard-go/device" @@ -10,8 +10,6 @@ "tailscale.com/types/logger" ) -const DefaultTunName = "tailscale0" - type darwinRouter struct { tunname string } diff --git a/wgengine/router_darwin_support.go b/wgengine/router/router_darwin_support.go similarity index 98% rename from wgengine/router_darwin_support.go rename to wgengine/router/router_darwin_support.go index 9032d401d..031c4942d 100644 --- a/wgengine/router_darwin_support.go +++ b/wgengine/router/router_darwin_support.go @@ -4,7 +4,7 @@ // +build linux darwin -package wgengine +package router // SetRoutesFunc applies the given route settings to the OS network // stack. diff --git a/wgengine/router_default.go b/wgengine/router/router_default.go similarity index 90% rename from wgengine/router_default.go rename to wgengine/router/router_default.go index 56d3da9e1..c5440f8c9 100644 --- a/wgengine/router_default.go +++ b/wgengine/router/router_default.go @@ -4,7 +4,7 @@ // +build !windows,!linux,!darwin,!openbsd,!freebsd -package wgengine +package router import ( "github.com/tailscale/wireguard-go/device" @@ -12,8 +12,6 @@ "tailscale.com/types/logger" ) -const DefaultTunName = "tailscale0" - func newUserspaceRouter(logf logger.Logf, tunname string, dev *device.Device, tuntap tun.Device, netChanged func()) Router { return NewFakeRouter(logf, tunname, dev, tuntap, netChanged) } diff --git a/wgengine/router_fake.go b/wgengine/router/router_fake.go similarity index 75% rename from wgengine/router_fake.go rename to wgengine/router/router_fake.go index f100de055..f3d55b8ff 100644 --- a/wgengine/router_fake.go +++ b/wgengine/router/router_fake.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. -package wgengine +package router import ( "github.com/tailscale/wireguard-go/device" @@ -10,9 +10,9 @@ "tailscale.com/types/logger" ) -// NewFakeRouter returns a new fake Router implementation whose -// implementation does nothing and always returns nil errors. -func NewFakeRouter(logf logger.Logf, _ *device.Device, _ tun.Device) (Router, error) { +// NewFakeRouter returns a Router that does nothing when called and +// always returns nil errors. +func NewFake(logf logger.Logf, _ *device.Device, _ tun.Device) (Router, error) { return fakeRouter{logf: logf}, nil } diff --git a/wgengine/router_freebsd.go b/wgengine/router/router_freebsd.go similarity index 98% rename from wgengine/router_freebsd.go rename to wgengine/router/router_freebsd.go index bfaf4db47..a0be4c141 100644 --- a/wgengine/router_freebsd.go +++ b/wgengine/router/router_freebsd.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. -package wgengine +package router import ( "fmt" @@ -20,8 +20,6 @@ // Work is currently underway for an in-kernel FreeBSD implementation of wireguard // https://svnweb.freebsd.org/base?view=revision&revision=357986 -const DefaultTunName = "tailscale0" - type freebsdRouter struct { logf logger.Logf tunname string diff --git a/wgengine/router_linux.go b/wgengine/router/router_linux.go similarity index 99% rename from wgengine/router_linux.go rename to wgengine/router/router_linux.go index 77aa22bd0..c02a63e8a 100644 --- a/wgengine/router_linux.go +++ b/wgengine/router/router_linux.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. -package wgengine +package router import ( "bytes" @@ -22,8 +22,6 @@ "tailscale.com/types/logger" ) -const DefaultTunName = "tailscale0" - type linuxRouter struct { logf func(fmt string, args ...interface{}) tunname string diff --git a/wgengine/router_openbsd.go b/wgengine/router/router_openbsd.go similarity index 99% rename from wgengine/router_openbsd.go rename to wgengine/router/router_openbsd.go index 5391a6418..96befa8bd 100644 --- a/wgengine/router_openbsd.go +++ b/wgengine/router/router_openbsd.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. -package wgengine +package router import ( "bytes" @@ -25,8 +25,6 @@ // There is an experimental kernel version in the works for OpenBSD: // https://git.zx2c4.com/wireguard-openbsd. -const DefaultTunName = "tun" - type openbsdRouter struct { logf logger.Logf tunname string diff --git a/wgengine/router_windows.go b/wgengine/router/router_windows.go similarity index 96% rename from wgengine/router_windows.go rename to wgengine/router/router_windows.go index bfd10c9ac..f44fb2db5 100644 --- a/wgengine/router_windows.go +++ b/wgengine/router/router_windows.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. -package wgengine +package router import ( "log" @@ -13,8 +13,6 @@ "tailscale.com/types/logger" ) -const DefaultTunName = "tailscale0" - type winRouter struct { logf func(fmt string, args ...interface{}) tunname string diff --git a/wgengine/userspace.go b/wgengine/userspace.go index 66ef65b00..15694d3a6 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -32,6 +32,7 @@ "tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/monitor" "tailscale.com/wgengine/packet" + "tailscale.com/wgengine/router" ) // minimalMTU is the MTU we set on tailscale's tuntap @@ -50,7 +51,7 @@ type userspaceEngine struct { waitCh chan struct{} tundev tun.Device wgdev *device.Device - router Router + router router.Router magicConn *magicsock.Conn linkMon *monitor.Mon @@ -82,11 +83,11 @@ func (l *Loggify) Write(b []byte) (int, error) { func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16) (Engine, error) { logf("Starting userspace wireguard engine (FAKE tuntap device).") tun := NewFakeTun() - return NewUserspaceEngineAdvanced(logf, tun, NewFakeRouter, listenPort) + return NewUserspaceEngineAdvanced(logf, tun, router.NewFake, listenPort) } -// NewUserspaceEngine creates the named tun device and returns a Tailscale Engine -// running on it. +// NewUserspaceEngine creates the named tun device and returns a +// Tailscale Engine running on it. func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (Engine, error) { if tunname == "" { return nil, fmt.Errorf("--tun name must not be blank") @@ -102,7 +103,7 @@ func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (En } logf("CreateTUN ok.") - e, err := NewUserspaceEngineAdvanced(logf, tundev, newUserspaceRouter, listenPort) + e, err := NewUserspaceEngineAdvanced(logf, tundev, router.New, listenPort) if err != nil { logf("NewUserspaceEngineAdv: %v", err) tundev.Close() @@ -111,6 +112,10 @@ func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (En return e, err } +// RouterGen is the signature for a function that creates a +// router.Router. +type RouterGen func(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (router.Router, error) + // NewUserspaceEngineAdvanced is like NewUserspaceEngine but takes a pre-created TUN device and allows specifing // a custom router constructor and listening port. func NewUserspaceEngineAdvanced(logf logger.Logf, tundev tun.Device, routerGen RouterGen, listenPort uint16) (Engine, error) { @@ -236,7 +241,7 @@ func newUserspaceEngineAdvanced(logf logger.Logf, tundev tun.Device, routerGen R e.wgdev.Close() return nil, err } - if err := e.router.SetRoutes(RouteSettings{Cfg: new(wgcfg.Config)}); err != nil { + if err := e.router.SetRoutes(router.RouteSettings{Cfg: new(wgcfg.Config)}); err != nil { e.wgdev.Close() return nil, err } @@ -375,7 +380,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, dnsDomains []string) error cidr.Mask = 10 // route the whole cgnat range } - rs := RouteSettings{ + rs := router.RouteSettings{ LocalAddr: cidr, Cfg: cfg, DNS: cfg.DNS, diff --git a/wgengine/watchdog_test.go b/wgengine/watchdog_test.go index d54ef7df1..a359b5ee7 100644 --- a/wgengine/watchdog_test.go +++ b/wgengine/watchdog_test.go @@ -10,6 +10,8 @@ "strings" "testing" "time" + + "tailscale.com/wgengine/router" ) func TestWatchdog(t *testing.T) { @@ -18,7 +20,7 @@ func TestWatchdog(t *testing.T) { t.Run("default watchdog does not fire", func(t *testing.T) { t.Parallel() tun := NewFakeTun() - e, err := NewUserspaceEngineAdvanced(t.Logf, tun, NewFakeRouter, 0) + e, err := NewUserspaceEngineAdvanced(t.Logf, tun, router.NewFake, 0) if err != nil { t.Fatal(err) } @@ -35,7 +37,7 @@ func TestWatchdog(t *testing.T) { t.Run("watchdog fires on blocked getStatus", func(t *testing.T) { t.Parallel() tun := NewFakeTun() - e, err := NewUserspaceEngineAdvanced(t.Logf, tun, NewFakeRouter, 0) + e, err := NewUserspaceEngineAdvanced(t.Logf, tun, router.NewFake, 0) if err != nil { t.Fatal(err) } diff --git a/wgengine/wgengine.go b/wgengine/wgengine.go index 518abfce1..1d1554683 100644 --- a/wgengine/wgengine.go +++ b/wgengine/wgengine.go @@ -6,15 +6,11 @@ import ( "errors" - "fmt" "time" - "github.com/tailscale/wireguard-go/device" - "github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/wgcfg" "tailscale.com/ipn/ipnstate" "tailscale.com/tailcfg" - "tailscale.com/types/logger" "tailscale.com/wgengine/filter" ) @@ -48,51 +44,6 @@ type Status struct { // NetInfoCallback is the type used by Engine.SetNetInfoCallback. type NetInfoCallback func(*tailcfg.NetInfo) -// RouteSettings is the full WireGuard config data (set of peers keys, -// IP, etc in wgcfg.Config) plus the things that WireGuard doesn't do -// itself, like DNS stuff. -type RouteSettings struct { - LocalAddr wgcfg.CIDR // TODO: why is this here? how does it differ from wgcfg.Config's info? - DNS []wgcfg.IP - DNSDomains []string - Cfg *wgcfg.Config -} - -// OnlyRelevantParts returns a string minimally describing the route settings. -func (rs *RouteSettings) OnlyRelevantParts() string { - var peers [][]wgcfg.CIDR - for _, p := range rs.Cfg.Peers { - peers = append(peers, p.AllowedIPs) - } - return fmt.Sprintf("%v %v %v %v", - rs.LocalAddr, rs.DNS, rs.DNSDomains, peers) -} - -// NewUserspaceRouter returns a new Router for the current platform, using the provided tun device. -func NewUserspaceRouter(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, error) { - return newUserspaceRouter(logf, wgdev, tundev) -} - -// RouterGen is the signature for the two funcs that create Router implementations: -// NewUserspaceRouter (which varies by operating system) and NewFakeRouter. -type RouterGen func(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, error) - -// Router is responsible for managing the system route table. -// -// There's only one instance, and one per-OS implementation. -type Router interface { - // Up brings the router up. - Up() error - - // SetRoutes is called regularly on network map updates. - // It's how you kernel route table entries are populated for - // each peer. - SetRoutes(RouteSettings) error - - // Close closes the router. - Close() error -} - // ErrNoChanges is returned by Engine.Reconfig if no changes were made. var ErrNoChanges = errors.New("no changes made to Engine config")