wgengine/router: split out from wgengine.

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

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/348/head
David Anderson 5 years ago committed by Dave Anderson
parent ee3395e63a
commit 1ac570def7

@ -14,6 +14,7 @@ import (
"log" "log"
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
"runtime"
"github.com/apenwarr/fixconsole" "github.com/apenwarr/fixconsole"
"github.com/pborman/getopt/v2" "github.com/pborman/getopt/v2"
@ -33,10 +34,18 @@ import (
// later, the global state key doesn't look like a username. // later, the global state key doesn't look like a username.
const globalStateKey = "_daemon" const globalStateKey = "_daemon"
var defaultTunName = "tailscale0"
func init() {
if runtime.GOOS == "openbsd" {
defaultTunName = "tun"
}
}
func main() { func main() {
fake := getopt.BoolLong("fake", 0, "fake tunnel+routing instead of tuntap") fake := getopt.BoolLong("fake", 0, "fake tunnel+routing instead of tuntap")
debug := getopt.StringLong("debug", 0, "", "Address of debug server") 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)") listenport := getopt.Uint16Long("port", 'p', magicsock.DefaultPort, "WireGuard port (0=autoselect)")
statepath := getopt.StringLong("state", 0, paths.DefaultTailscaledStateFile(), "Path of state file") statepath := getopt.StringLong("state", 0, paths.DefaultTailscaledStateFile(), "Path of state file")
socketpath := getopt.StringLong("socket", 's', paths.DefaultTailscaledSocket(), "Path of the service unix socket") socketpath := getopt.StringLong("socket", 's', paths.DefaultTailscaledSocket(), "Path of the service unix socket")

@ -24,6 +24,7 @@ import (
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/magicsock"
"tailscale.com/wgengine/router"
"tailscale.io/control" // not yet released "tailscale.io/control" // not yet released
) )
@ -196,7 +197,7 @@ func newNode(t *testing.T, prefix string, https *httptest.Server) testNode {
} }
tun := tuntest.NewChannelTUN() 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 { if err != nil {
t.Fatalf("NewFakeEngine: %v\n", err) t.Fatalf("NewFakeEngine: %v\n", err)
} }

@ -35,7 +35,7 @@ for file in $(find $1 -name '*.go'); do
$1/tempfork/*) $1/tempfork/*)
# Skip, tempfork of third-party code # Skip, tempfork of third-party code
;; ;;
$1/wgengine/ifconfig_windows.go) $1/wgengine/router/ifconfig_windows.go)
# WireGuard copyright. # WireGuard copyright.
;; ;;
*) *)

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

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

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"github.com/tailscale/wireguard-go/device" "github.com/tailscale/wireguard-go/device"
@ -10,8 +10,6 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
const DefaultTunName = "tailscale0"
type darwinRouter struct { type darwinRouter struct {
tunname string tunname string
} }

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

@ -4,7 +4,7 @@
// +build !windows,!linux,!darwin,!openbsd,!freebsd // +build !windows,!linux,!darwin,!openbsd,!freebsd
package wgengine package router
import ( import (
"github.com/tailscale/wireguard-go/device" "github.com/tailscale/wireguard-go/device"
@ -12,8 +12,6 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
const DefaultTunName = "tailscale0"
func newUserspaceRouter(logf logger.Logf, tunname string, dev *device.Device, tuntap tun.Device, netChanged func()) Router { func newUserspaceRouter(logf logger.Logf, tunname string, dev *device.Device, tuntap tun.Device, netChanged func()) Router {
return NewFakeRouter(logf, tunname, dev, tuntap, netChanged) return NewFakeRouter(logf, tunname, dev, tuntap, netChanged)
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"github.com/tailscale/wireguard-go/device" "github.com/tailscale/wireguard-go/device"
@ -10,9 +10,9 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
// NewFakeRouter returns a new fake Router implementation whose // NewFakeRouter returns a Router that does nothing when called and
// implementation does nothing and always returns nil errors. // always returns nil errors.
func NewFakeRouter(logf logger.Logf, _ *device.Device, _ tun.Device) (Router, error) { func NewFake(logf logger.Logf, _ *device.Device, _ tun.Device) (Router, error) {
return fakeRouter{logf: logf}, nil return fakeRouter{logf: logf}, nil
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"fmt" "fmt"
@ -20,8 +20,6 @@ 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
const DefaultTunName = "tailscale0"
type freebsdRouter struct { type freebsdRouter struct {
logf logger.Logf logf logger.Logf
tunname string tunname string

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"bytes" "bytes"
@ -22,8 +22,6 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
const DefaultTunName = "tailscale0"
type linuxRouter struct { type linuxRouter struct {
logf func(fmt string, args ...interface{}) logf func(fmt string, args ...interface{})
tunname string tunname string

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"bytes" "bytes"
@ -25,8 +25,6 @@ import (
// There is an experimental kernel version in the works for OpenBSD: // There is an experimental kernel version in the works for OpenBSD:
// https://git.zx2c4.com/wireguard-openbsd. // https://git.zx2c4.com/wireguard-openbsd.
const DefaultTunName = "tun"
type openbsdRouter struct { type openbsdRouter struct {
logf logger.Logf logf logger.Logf
tunname string tunname string

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package wgengine package router
import ( import (
"log" "log"
@ -13,8 +13,6 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
const DefaultTunName = "tailscale0"
type winRouter struct { type winRouter struct {
logf func(fmt string, args ...interface{}) logf func(fmt string, args ...interface{})
tunname string tunname string

@ -32,6 +32,7 @@ import (
"tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/magicsock"
"tailscale.com/wgengine/monitor" "tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/packet" "tailscale.com/wgengine/packet"
"tailscale.com/wgengine/router"
) )
// minimalMTU is the MTU we set on tailscale's tuntap // minimalMTU is the MTU we set on tailscale's tuntap
@ -50,7 +51,7 @@ type userspaceEngine struct {
waitCh chan struct{} waitCh chan struct{}
tundev tun.Device tundev tun.Device
wgdev *device.Device wgdev *device.Device
router Router router router.Router
magicConn *magicsock.Conn magicConn *magicsock.Conn
linkMon *monitor.Mon linkMon *monitor.Mon
@ -82,11 +83,11 @@ func (l *Loggify) Write(b []byte) (int, error) {
func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16) (Engine, error) { func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16) (Engine, error) {
logf("Starting userspace wireguard engine (FAKE tuntap device).") logf("Starting userspace wireguard engine (FAKE tuntap device).")
tun := NewFakeTun() 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 // NewUserspaceEngine creates the named tun device and returns a
// running on it. // Tailscale Engine running on it.
func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (Engine, error) { func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (Engine, error) {
if tunname == "" { if tunname == "" {
return nil, fmt.Errorf("--tun name must not be blank") 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.") logf("CreateTUN ok.")
e, err := NewUserspaceEngineAdvanced(logf, tundev, newUserspaceRouter, listenPort) e, err := NewUserspaceEngineAdvanced(logf, tundev, router.New, listenPort)
if err != nil { if err != nil {
logf("NewUserspaceEngineAdv: %v", err) logf("NewUserspaceEngineAdv: %v", err)
tundev.Close() tundev.Close()
@ -111,6 +112,10 @@ func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (En
return e, err 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 // NewUserspaceEngineAdvanced is like NewUserspaceEngine but takes a pre-created TUN device and allows specifing
// a custom router constructor and listening port. // a custom router constructor and listening port.
func NewUserspaceEngineAdvanced(logf logger.Logf, tundev tun.Device, routerGen RouterGen, listenPort uint16) (Engine, error) { 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() e.wgdev.Close()
return nil, err 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() e.wgdev.Close()
return nil, err 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 cidr.Mask = 10 // route the whole cgnat range
} }
rs := RouteSettings{ rs := router.RouteSettings{
LocalAddr: cidr, LocalAddr: cidr,
Cfg: cfg, Cfg: cfg,
DNS: cfg.DNS, DNS: cfg.DNS,

@ -10,6 +10,8 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"tailscale.com/wgengine/router"
) )
func TestWatchdog(t *testing.T) { 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.Run("default watchdog does not fire", func(t *testing.T) {
t.Parallel() t.Parallel()
tun := NewFakeTun() tun := NewFakeTun()
e, err := NewUserspaceEngineAdvanced(t.Logf, tun, NewFakeRouter, 0) e, err := NewUserspaceEngineAdvanced(t.Logf, tun, router.NewFake, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -35,7 +37,7 @@ func TestWatchdog(t *testing.T) {
t.Run("watchdog fires on blocked getStatus", func(t *testing.T) { t.Run("watchdog fires on blocked getStatus", func(t *testing.T) {
t.Parallel() t.Parallel()
tun := NewFakeTun() tun := NewFakeTun()
e, err := NewUserspaceEngineAdvanced(t.Logf, tun, NewFakeRouter, 0) e, err := NewUserspaceEngineAdvanced(t.Logf, tun, router.NewFake, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -6,15 +6,11 @@ package wgengine
import ( import (
"errors" "errors"
"fmt"
"time" "time"
"github.com/tailscale/wireguard-go/device"
"github.com/tailscale/wireguard-go/tun"
"github.com/tailscale/wireguard-go/wgcfg" "github.com/tailscale/wireguard-go/wgcfg"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
) )
@ -48,51 +44,6 @@ type StatusCallback func(*Status, error)
// NetInfoCallback is the type used by Engine.SetNetInfoCallback. // NetInfoCallback is the type used by Engine.SetNetInfoCallback.
type NetInfoCallback func(*tailcfg.NetInfo) 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. // ErrNoChanges is returned by Engine.Reconfig if no changes were made.
var ErrNoChanges = errors.New("no changes made to Engine config") var ErrNoChanges = errors.New("no changes made to Engine config")

Loading…
Cancel
Save