// 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 wgengine import ( "fmt" "net" "time" "github.com/tailscale/wireguard-go/device" "github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/wgcfg" "tailscale.com/tailcfg" "tailscale.com/types/logger" "tailscale.com/wgengine/filter" ) // ByteCount is the number of bytes that have been sent or received. // // TODO: why is this a type? remove? // TODO: document whether it's payload bytes only or if it includes framing overhead. type ByteCount int64 type PeerStatus struct { TxBytes, RxBytes ByteCount LastHandshake time.Time NodeKey tailcfg.NodeKey } // Status is the Engine status. type Status struct { Peers []PeerStatus LocalAddrs []string // TODO(crawshaw): []wgcfg.Endpoint? } // StatusCallback is the type of status callbacks used by // Engine.SetStatusCallback. // // Exactly one of Status or error is non-nil. type StatusCallback func(*Status, error) // 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 []net.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 } // Engine is the Tailscale WireGuard engine interface. type Engine interface { // Reconfig reconfigures WireGuard and makes sure it's running. // This also handles setting up any kernel routes. // // The provided DNS domains are not part of wgcfg.Config, as // WireGuard itself doesn't care about such things. // // This is called whenever the tailcontrol (control plane) // sends an updated network map. Reconfig(cfg *wgcfg.Config, dnsDomains []string) error // SetFilter updates the packet filter. SetFilter(*filter.Filter) // SetStatusCallback sets the function to call when the // WireGuard status changes. SetStatusCallback(StatusCallback) // RequestStatus requests a WireGuard status update right // away, sent to the callback registered via SetStatusCallback. RequestStatus() // Close shuts down this wireguard instance, remove any routes // it added, etc. To bring it up again later, you'll need a // new Engine. Close() // Wait waits until the Engine's Close method is called or the // engine aborts with an error. You don't have to call this. // TODO: return an error? Wait() // LinkChange informs the engine that the system network // link has changed. The isExpensive parameter is set on links // where sending packets uses substantial power or money, // such as mobile data on a phone. LinkChange(isExpensive bool) }