wgengine/router: split out from wgengine.

The router implementations are logically separate, with their own API.

Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
David Anderson 2020-04-30 13:20:09 -07:00 committed by Dave Anderson
parent ee3395e63a
commit 1ac570def7
16 changed files with 98 additions and 85 deletions

View File

@ -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")

View File

@ -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)
}

View File

@ -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.
;;
*)

View File

@ -3,7 +3,7 @@
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
*/
package wgengine
package router
import (
"bytes"

57
wgengine/router/router.go Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -4,7 +4,7 @@
// +build linux darwin
package wgengine
package router
// SetRoutesFunc applies the given route settings to the OS network
// stack.

View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)
}

View File

@ -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")