2022-09-01 01:09:44 +00:00
package tailnet
import (
"context"
2022-11-13 17:33:05 +00:00
"errors"
2022-09-01 01:09:44 +00:00
"fmt"
2023-04-20 22:58:22 +00:00
"io"
2022-09-01 01:09:44 +00:00
"net"
2023-03-21 18:43:20 +00:00
"net/http"
2022-09-01 01:09:44 +00:00
"net/netip"
2023-08-08 17:56:08 +00:00
"os"
2023-02-10 22:59:24 +00:00
"reflect"
2023-04-20 22:58:22 +00:00
"strconv"
2022-09-01 01:09:44 +00:00
"sync"
"time"
2022-11-15 18:59:22 +00:00
"github.com/cenkalti/backoff/v4"
2022-09-01 01:09:44 +00:00
"github.com/google/uuid"
"go4.org/netipx"
"golang.org/x/xerrors"
2023-04-18 22:53:11 +00:00
"gvisor.dev/gvisor/pkg/tcpip"
2022-09-01 01:09:44 +00:00
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate"
2023-02-10 03:43:18 +00:00
"tailscale.com/net/connstats"
2022-09-01 01:09:44 +00:00
"tailscale.com/net/dns"
"tailscale.com/net/netns"
"tailscale.com/net/tsdial"
"tailscale.com/net/tstun"
"tailscale.com/tailcfg"
"tailscale.com/types/ipproto"
"tailscale.com/types/key"
tslogger "tailscale.com/types/logger"
2022-11-18 22:46:53 +00:00
"tailscale.com/types/netlogtype"
2022-09-01 01:09:44 +00:00
"tailscale.com/types/netmap"
"tailscale.com/wgengine"
"tailscale.com/wgengine/filter"
"tailscale.com/wgengine/magicsock"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netstack"
"tailscale.com/wgengine/router"
"tailscale.com/wgengine/wgcfg/nmcfg"
2022-11-18 22:46:53 +00:00
"cdr.dev/slog"
2022-11-01 20:56:33 +00:00
"github.com/coder/coder/coderd/database"
2022-09-01 01:09:44 +00:00
"github.com/coder/coder/cryptorand"
)
2023-04-18 22:53:11 +00:00
const (
WorkspaceAgentSSHPort = 1
WorkspaceAgentReconnectingPTYPort = 2
WorkspaceAgentSpeedtestPort = 3
)
2023-08-08 17:56:08 +00:00
// EnvMagicsockDebugLogging enables super-verbose logging for the magicsock
// internals. A logger must be supplied to the connection with the debug level
// enabled.
//
// With this disabled, you still get a lot of output if you have a valid logger
// with the debug level enabled.
const EnvMagicsockDebugLogging = "CODER_MAGICSOCK_DEBUG_LOGGING"
2022-09-01 01:09:44 +00:00
func init ( ) {
2022-11-18 22:46:53 +00:00
// Globally disable network namespacing. All networking happens in
// userspace.
2022-09-01 01:09:44 +00:00
netns . SetEnabled ( false )
}
type Options struct {
2023-03-21 18:43:20 +00:00
Addresses [ ] netip . Prefix
DERPMap * tailcfg . DERPMap
DERPHeader * http . Header
2022-09-01 01:09:44 +00:00
2022-10-17 13:43:30 +00:00
// BlockEndpoints specifies whether P2P endpoints are blocked.
// If so, only DERPs can establish connections.
BlockEndpoints bool
Logger slog . Logger
2023-04-03 16:20:19 +00:00
ListenPort uint16
2022-09-01 01:09:44 +00:00
}
// NewConn constructs a new Wireguard server that will accept connections from the addresses provided.
2023-02-24 11:11:28 +00:00
func NewConn ( options * Options ) ( conn * Conn , err error ) {
2022-09-01 01:09:44 +00:00
if options == nil {
options = & Options { }
}
if len ( options . Addresses ) == 0 {
return nil , xerrors . New ( "At least one IP range must be provided" )
}
if options . DERPMap == nil {
return nil , xerrors . New ( "DERPMap must be provided" )
}
2023-02-10 03:43:18 +00:00
2022-09-01 01:09:44 +00:00
nodePrivateKey := key . NewNode ( )
nodePublicKey := nodePrivateKey . Public ( )
netMap := & netmap . NetworkMap {
2022-12-18 23:50:06 +00:00
DERPMap : options . DERPMap ,
2022-09-01 01:09:44 +00:00
NodeKey : nodePublicKey ,
PrivateKey : nodePrivateKey ,
Addresses : options . Addresses ,
PacketFilter : [ ] filter . Match { {
// Allow any protocol!
IPProto : [ ] ipproto . Proto { ipproto . TCP , ipproto . UDP , ipproto . ICMPv4 , ipproto . ICMPv6 , ipproto . SCTP } ,
// Allow traffic sourced from anywhere.
Srcs : [ ] netip . Prefix {
netip . PrefixFrom ( netip . AddrFrom4 ( [ 4 ] byte { } ) , 0 ) ,
netip . PrefixFrom ( netip . AddrFrom16 ( [ 16 ] byte { } ) , 0 ) ,
} ,
// Allow traffic to route anywhere.
Dsts : [ ] filter . NetPortRange {
{
Net : netip . PrefixFrom ( netip . AddrFrom4 ( [ 4 ] byte { } ) , 0 ) ,
Ports : filter . PortRange {
First : 0 ,
Last : 65535 ,
} ,
} ,
{
Net : netip . PrefixFrom ( netip . AddrFrom16 ( [ 16 ] byte { } ) , 0 ) ,
Ports : filter . PortRange {
First : 0 ,
Last : 65535 ,
} ,
} ,
} ,
Caps : [ ] filter . CapMatch { } ,
} } ,
}
nodeID , err := cryptorand . Int63 ( )
if err != nil {
return nil , xerrors . Errorf ( "generate node id: %w" , err )
}
// This is used by functions below to identify the node via key
netMap . SelfNode = & tailcfg . Node {
ID : tailcfg . NodeID ( nodeID ) ,
Key : nodePublicKey ,
Addresses : options . Addresses ,
AllowedIPs : options . Addresses ,
}
2023-07-26 21:46:22 +00:00
wireguardMonitor , err := monitor . New ( Logger ( options . Logger . Named ( "net.wgmonitor" ) ) )
2022-09-01 01:09:44 +00:00
if err != nil {
return nil , xerrors . Errorf ( "create wireguard link monitor: %w" , err )
}
2023-02-24 11:11:28 +00:00
defer func ( ) {
if err != nil {
wireguardMonitor . Close ( )
}
} ( )
2022-09-01 01:09:44 +00:00
2023-07-12 22:37:31 +00:00
IP ( )
2022-09-01 01:09:44 +00:00
dialer := & tsdial . Dialer {
2023-07-26 21:46:22 +00:00
Logf : Logger ( options . Logger . Named ( "net.tsdial" ) ) ,
2022-09-01 01:09:44 +00:00
}
2023-07-26 21:46:22 +00:00
wireguardEngine , err := wgengine . NewUserspaceEngine ( Logger ( options . Logger . Named ( "net.wgengine" ) ) , wgengine . Config {
2022-09-01 01:09:44 +00:00
LinkMonitor : wireguardMonitor ,
Dialer : dialer ,
2023-04-03 16:20:19 +00:00
ListenPort : options . ListenPort ,
2022-09-01 01:09:44 +00:00
} )
if err != nil {
return nil , xerrors . Errorf ( "create wgengine: %w" , err )
}
2023-02-24 11:11:28 +00:00
defer func ( ) {
if err != nil {
wireguardEngine . Close ( )
}
} ( )
2022-09-01 01:09:44 +00:00
dialer . UseNetstackForIP = func ( ip netip . Addr ) bool {
_ , ok := wireguardEngine . PeerForIP ( ip )
return ok
}
// This is taken from Tailscale:
// https://github.com/tailscale/tailscale/blob/0f05b2c13ff0c305aa7a1655fa9c17ed969d65be/tsnet/tsnet.go#L247-L255
wireguardInternals , ok := wireguardEngine . ( wgengine . InternalsGetter )
if ! ok {
return nil , xerrors . Errorf ( "wireguard engine isn't the correct type %T" , wireguardEngine )
}
tunDevice , magicConn , dnsManager , ok := wireguardInternals . GetInternals ( )
if ! ok {
2022-11-18 22:46:53 +00:00
return nil , xerrors . New ( "get wireguard internals" )
2022-09-01 01:09:44 +00:00
}
2023-03-21 18:43:20 +00:00
if options . DERPHeader != nil {
magicConn . SetDERPHeader ( options . DERPHeader . Clone ( ) )
}
2022-09-01 01:09:44 +00:00
2023-08-08 17:56:08 +00:00
if v , ok := os . LookupEnv ( EnvMagicsockDebugLogging ) ; ok {
vBool , err := strconv . ParseBool ( v )
if err != nil {
options . Logger . Debug ( context . Background ( ) , fmt . Sprintf ( "magicsock debug logging disabled due to invalid value %s=%q, use true or false" , EnvMagicsockDebugLogging , v ) )
} else {
magicConn . SetDebugLoggingEnabled ( vBool )
options . Logger . Debug ( context . Background ( ) , fmt . Sprintf ( "magicsock debug logging set by %s=%t" , EnvMagicsockDebugLogging , vBool ) )
}
} else {
options . Logger . Debug ( context . Background ( ) , fmt . Sprintf ( "magicsock debug logging disabled, use %s=true to enable" , EnvMagicsockDebugLogging ) )
}
2022-09-01 01:09:44 +00:00
// Update the keys for the magic connection!
err = magicConn . SetPrivateKey ( nodePrivateKey )
if err != nil {
return nil , xerrors . Errorf ( "set node private key: %w" , err )
}
netMap . SelfNode . DiscoKey = magicConn . DiscoPublicKey ( )
netStack , err := netstack . Create (
2023-07-26 21:46:22 +00:00
Logger ( options . Logger . Named ( "net.netstack" ) ) ,
2023-07-12 22:37:31 +00:00
tunDevice ,
wireguardEngine ,
magicConn ,
dialer ,
dnsManager ,
)
2022-09-01 01:09:44 +00:00
if err != nil {
return nil , xerrors . Errorf ( "create netstack: %w" , err )
}
2023-07-12 22:37:31 +00:00
2022-09-01 01:09:44 +00:00
dialer . NetstackDialTCP = func ( ctx context . Context , dst netip . AddrPort ) ( net . Conn , error ) {
return netStack . DialContextTCP ( ctx , dst )
}
netStack . ProcessLocalIPs = true
wireguardEngine = wgengine . NewWatchdog ( wireguardEngine )
wireguardEngine . SetDERPMap ( options . DERPMap )
netMapCopy := * netMap
2023-02-25 08:06:38 +00:00
options . Logger . Debug ( context . Background ( ) , "updating network map" )
2022-09-01 01:09:44 +00:00
wireguardEngine . SetNetworkMap ( & netMapCopy )
localIPSet := netipx . IPSetBuilder { }
for _ , addr := range netMap . Addresses {
localIPSet . AddPrefix ( addr )
}
localIPs , _ := localIPSet . IPSet ( )
logIPSet := netipx . IPSetBuilder { }
logIPs , _ := logIPSet . IPSet ( )
2023-07-12 22:37:31 +00:00
wireguardEngine . SetFilter ( filter . New (
netMap . PacketFilter ,
localIPs ,
logIPs ,
nil ,
2023-07-26 21:46:22 +00:00
Logger ( options . Logger . Named ( "net.packet-filter" ) ) ,
2023-07-12 22:37:31 +00:00
) )
2022-09-23 17:10:47 +00:00
dialContext , dialCancel := context . WithCancel ( context . Background ( ) )
2022-09-01 01:09:44 +00:00
server := & Conn {
2023-03-01 22:18:14 +00:00
blockEndpoints : options . BlockEndpoints ,
dialContext : dialContext ,
dialCancel : dialCancel ,
closed : make ( chan struct { } ) ,
logger : options . Logger ,
magicConn : magicConn ,
dialer : dialer ,
listeners : map [ listenKey ] * listener { } ,
peerMap : map [ tailcfg . NodeID ] * tailcfg . Node { } ,
lastDERPForcedWebsockets : map [ int ] string { } ,
tunDevice : tunDevice ,
netMap : netMap ,
netStack : netStack ,
wireguardMonitor : wireguardMonitor ,
2022-09-01 16:41:47 +00:00
wireguardRouter : & router . Config {
LocalAddrs : netMap . Addresses ,
} ,
wireguardEngine : wireguardEngine ,
2022-09-01 01:09:44 +00:00
}
2023-02-24 11:11:28 +00:00
defer func ( ) {
if err != nil {
_ = server . Close ( )
}
} ( )
2023-07-12 22:37:31 +00:00
2022-09-22 20:22:49 +00:00
wireguardEngine . SetStatusCallback ( func ( s * wgengine . Status , err error ) {
2023-06-20 10:30:45 +00:00
server . logger . Debug ( context . Background ( ) , "wireguard status" , slog . F ( "status" , s ) , slog . Error ( err ) )
2022-09-22 20:22:49 +00:00
if err != nil {
return
}
server . lastMutex . Lock ( )
2022-09-26 15:16:04 +00:00
if s . AsOf . Before ( server . lastStatus ) {
// Don't process outdated status!
server . lastMutex . Unlock ( )
return
}
server . lastStatus = s . AsOf
2023-02-10 22:59:24 +00:00
if endpointsEqual ( s . LocalAddrs , server . lastEndpoints ) {
// No need to update the node if nothing changed!
server . lastMutex . Unlock ( )
return
2022-09-22 20:22:49 +00:00
}
2023-02-10 22:59:24 +00:00
server . lastEndpoints = append ( [ ] tailcfg . Endpoint { } , s . LocalAddrs ... )
2022-09-22 20:22:49 +00:00
server . lastMutex . Unlock ( )
server . sendNode ( )
} )
2023-07-12 22:37:31 +00:00
2022-09-22 20:22:49 +00:00
wireguardEngine . SetNetInfoCallback ( func ( ni * tailcfg . NetInfo ) {
2022-11-13 17:33:05 +00:00
server . logger . Debug ( context . Background ( ) , "netinfo callback" , slog . F ( "netinfo" , ni ) )
2022-09-22 20:22:49 +00:00
server . lastMutex . Lock ( )
2023-02-10 22:59:24 +00:00
if reflect . DeepEqual ( server . lastNetInfo , ni ) {
2022-11-01 20:28:34 +00:00
server . lastMutex . Unlock ( )
return
}
2023-02-10 22:59:24 +00:00
server . lastNetInfo = ni . Clone ( )
2022-09-22 20:22:49 +00:00
server . lastMutex . Unlock ( )
server . sendNode ( )
} )
2023-07-12 22:37:31 +00:00
2023-03-01 22:18:14 +00:00
magicConn . SetDERPForcedWebsocketCallback ( func ( region int , reason string ) {
server . logger . Debug ( context . Background ( ) , "derp forced websocket" , slog . F ( "region" , region ) , slog . F ( "reason" , reason ) )
server . lastMutex . Lock ( )
if server . lastDERPForcedWebsockets [ region ] == reason {
server . lastMutex . Unlock ( )
return
}
server . lastDERPForcedWebsockets [ region ] = reason
server . lastMutex . Unlock ( )
server . sendNode ( )
} )
2023-07-12 22:37:31 +00:00
2023-04-20 22:58:22 +00:00
netStack . ForwardTCPIn = server . forwardTCP
netStack . ForwardTCPSockOpts = server . forwardTCPSockOpts
2023-02-24 11:11:28 +00:00
err = netStack . Start ( nil )
if err != nil {
return nil , xerrors . Errorf ( "start netstack: %w" , err )
}
2022-09-01 01:09:44 +00:00
return server , nil
}
2023-07-12 22:37:31 +00:00
func maskUUID ( uid uuid . UUID ) uuid . UUID {
// This is Tailscale's ephemeral service prefix. This can be changed easily
// later-on, because all of our nodes are ephemeral.
2022-09-01 01:09:44 +00:00
// fd7a:115c:a1e0
uid [ 0 ] = 0xfd
uid [ 1 ] = 0x7a
uid [ 2 ] = 0x11
uid [ 3 ] = 0x5c
uid [ 4 ] = 0xa1
uid [ 5 ] = 0xe0
2023-07-12 22:37:31 +00:00
return uid
}
// IP generates a random IP with a static service prefix.
func IP ( ) netip . Addr {
uid := maskUUID ( uuid . New ( ) )
2022-09-01 01:09:44 +00:00
return netip . AddrFrom16 ( uid )
}
2023-07-12 22:37:31 +00:00
// IP generates a new IP from a UUID.
func IPFromUUID ( uid uuid . UUID ) netip . Addr {
return netip . AddrFrom16 ( maskUUID ( uid ) )
}
2022-09-01 01:09:44 +00:00
// Conn is an actively listening Wireguard connection.
type Conn struct {
2022-10-17 13:43:30 +00:00
dialContext context . Context
dialCancel context . CancelFunc
mutex sync . Mutex
closed chan struct { }
logger slog . Logger
blockEndpoints bool
2022-09-01 01:09:44 +00:00
2023-04-18 22:53:11 +00:00
dialer * tsdial . Dialer
tunDevice * tstun . Wrapper
peerMap map [ tailcfg . NodeID ] * tailcfg . Node
netMap * netmap . NetworkMap
netStack * netstack . Impl
magicConn * magicsock . Conn
wireguardMonitor * monitor . Mon
wireguardRouter * router . Config
wireguardEngine wgengine . Engine
listeners map [ listenKey ] * listener
2022-09-01 01:09:44 +00:00
2022-09-22 20:22:49 +00:00
lastMutex sync . Mutex
nodeSending bool
nodeChanged bool
2022-09-01 01:09:44 +00:00
// It's only possible to store these values via status functions,
// so the values must be stored for retrieval later on.
2023-03-01 22:18:14 +00:00
lastStatus time . Time
lastEndpoints [ ] tailcfg . Endpoint
lastDERPForcedWebsockets map [ int ] string
lastNetInfo * tailcfg . NetInfo
nodeCallback func ( node * Node )
2023-02-10 03:43:18 +00:00
trafficStats * connstats . Statistics
2022-09-01 01:09:44 +00:00
}
2023-08-08 17:56:08 +00:00
func ( c * Conn ) MagicsockSetDebugLoggingEnabled ( enabled bool ) {
c . magicConn . SetDebugLoggingEnabled ( enabled )
}
2023-07-12 22:37:31 +00:00
func ( c * Conn ) SetAddresses ( ips [ ] netip . Prefix ) error {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
c . netMap . Addresses = ips
netMapCopy := * c . netMap
c . logger . Debug ( context . Background ( ) , "updating network map" )
c . wireguardEngine . SetNetworkMap ( & netMapCopy )
err := c . reconfig ( )
if err != nil {
return xerrors . Errorf ( "reconfig: %w" , err )
}
return nil
}
func ( c * Conn ) Addresses ( ) [ ] netip . Prefix {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
return c . netMap . Addresses
}
2022-09-01 01:09:44 +00:00
func ( c * Conn ) SetNodeCallback ( callback func ( node * Node ) ) {
2022-09-22 20:22:49 +00:00
c . lastMutex . Lock ( )
c . nodeCallback = callback
c . lastMutex . Unlock ( )
c . sendNode ( )
2022-09-01 01:09:44 +00:00
}
// SetDERPMap updates the DERPMap of a connection.
func ( c * Conn ) SetDERPMap ( derpMap * tailcfg . DERPMap ) {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
2022-09-11 21:45:49 +00:00
c . logger . Debug ( context . Background ( ) , "updating derp map" , slog . F ( "derp_map" , derpMap ) )
2022-09-01 01:09:44 +00:00
c . wireguardEngine . SetDERPMap ( derpMap )
2023-02-24 16:16:29 +00:00
c . netMap . DERPMap = derpMap
netMapCopy := * c . netMap
2023-02-25 08:06:38 +00:00
c . logger . Debug ( context . Background ( ) , "updating network map" )
2023-02-24 16:16:29 +00:00
c . wireguardEngine . SetNetworkMap ( & netMapCopy )
2022-09-01 01:09:44 +00:00
}
2023-06-21 22:02:05 +00:00
// SetBlockEndpoints sets whether or not to block P2P endpoints. This setting
// will only apply to new peers.
func ( c * Conn ) SetBlockEndpoints ( blockEndpoints bool ) {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
c . blockEndpoints = blockEndpoints
}
2023-03-14 14:46:47 +00:00
// SetDERPRegionDialer updates the dialer to use for connecting to DERP regions.
func ( c * Conn ) SetDERPRegionDialer ( dialer func ( ctx context . Context , region * tailcfg . DERPRegion ) net . Conn ) {
c . magicConn . SetDERPRegionDialer ( dialer )
}
2022-09-01 01:09:44 +00:00
// UpdateNodes connects with a set of peers. This can be constantly updated,
2023-02-24 16:16:29 +00:00
// and peers will continually be reconnected as necessary. If replacePeers is
// true, all peers will be removed before adding the new ones.
//
//nolint:revive // Complains about replacePeers.
func ( c * Conn ) UpdateNodes ( nodes [ ] * Node , replacePeers bool ) error {
2022-09-01 01:09:44 +00:00
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
status := c . Status ( )
2023-02-24 16:16:29 +00:00
if replacePeers {
c . netMap . Peers = [ ] * tailcfg . Node { }
c . peerMap = map [ tailcfg . NodeID ] * tailcfg . Node { }
}
2022-09-01 01:09:44 +00:00
for _ , peer := range c . netMap . Peers {
2022-09-26 15:16:04 +00:00
peerStatus , ok := status . Peer [ peer . Key ]
if ! ok {
continue
2022-09-01 01:09:44 +00:00
}
2022-09-26 15:16:04 +00:00
// If this peer was added in the last 5 minutes, assume it
// could still be active.
if time . Since ( peer . Created ) < 5 * time . Minute {
continue
}
// We double-check that it's safe to remove by ensuring no
// handshake has been sent in the past 5 minutes as well. Connections that
// are actively exchanging IP traffic will handshake every 2 minutes.
if time . Since ( peerStatus . LastHandshake ) < 5 * time . Minute {
continue
}
delete ( c . peerMap , peer . ID )
2022-09-01 01:09:44 +00:00
}
2023-07-12 22:37:31 +00:00
2022-09-01 01:09:44 +00:00
for _ , node := range nodes {
2023-02-24 16:16:29 +00:00
// If no preferred DERP is provided, we can't reach the node.
if node . PreferredDERP == 0 {
c . logger . Debug ( context . Background ( ) , "no preferred DERP, skipping node" , slog . F ( "node" , node ) )
continue
}
2022-10-17 13:43:30 +00:00
c . logger . Debug ( context . Background ( ) , "adding node" , slog . F ( "node" , node ) )
2022-09-01 16:41:47 +00:00
peerStatus , ok := status . Peer [ node . Key ]
2022-09-06 21:27:59 +00:00
peerNode := & tailcfg . Node {
2022-09-01 01:09:44 +00:00
ID : node . ID ,
2022-09-06 21:27:59 +00:00
Created : time . Now ( ) ,
2022-09-01 01:09:44 +00:00
Key : node . Key ,
DiscoKey : node . DiscoKey ,
Addresses : node . Addresses ,
AllowedIPs : node . AllowedIPs ,
Endpoints : node . Endpoints ,
DERP : fmt . Sprintf ( "%s:%d" , tailcfg . DerpMagicIP , node . PreferredDERP ) ,
Hostinfo : hostinfo . New ( ) . View ( ) ,
2022-09-01 16:41:47 +00:00
// Starting KeepAlive messages at the initialization
// of a connection cause it to hang for an unknown
// reason. TODO: @kylecarbs debug this!
KeepAlive : ok && peerStatus . Active ,
2022-09-01 01:09:44 +00:00
}
2022-10-17 13:43:30 +00:00
if c . blockEndpoints {
peerNode . Endpoints = nil
}
2022-09-26 15:16:04 +00:00
c . peerMap [ node . ID ] = peerNode
2022-09-01 01:09:44 +00:00
}
2023-07-12 22:37:31 +00:00
2022-09-26 15:16:04 +00:00
c . netMap . Peers = make ( [ ] * tailcfg . Node , 0 , len ( c . peerMap ) )
for _ , peer := range c . peerMap {
c . netMap . Peers = append ( c . netMap . Peers , peer . Clone ( ) )
2022-09-01 01:09:44 +00:00
}
2023-07-12 22:37:31 +00:00
2022-09-01 16:41:47 +00:00
netMapCopy := * c . netMap
2023-02-25 08:06:38 +00:00
c . logger . Debug ( context . Background ( ) , "updating network map" )
2022-09-01 16:41:47 +00:00
c . wireguardEngine . SetNetworkMap ( & netMapCopy )
2023-07-12 22:37:31 +00:00
err := c . reconfig ( )
if err != nil {
return xerrors . Errorf ( "reconfig: %w" , err )
}
return nil
}
func ( c * Conn ) reconfig ( ) error {
2023-07-26 21:46:22 +00:00
cfg , err := nmcfg . WGCfg ( c . netMap , Logger ( c . logger . Named ( "net.wgconfig" ) ) , netmap . AllowSingleHosts , "" )
2022-09-01 01:09:44 +00:00
if err != nil {
return xerrors . Errorf ( "update wireguard config: %w" , err )
}
2023-07-12 22:37:31 +00:00
2022-09-01 01:09:44 +00:00
err = c . wireguardEngine . Reconfig ( cfg , c . wireguardRouter , & dns . Config { } , & tailcfg . Debug { } )
if err != nil {
2022-09-22 20:22:49 +00:00
if c . isClosed ( ) {
return nil
}
2022-11-13 17:33:05 +00:00
if errors . Is ( err , wgengine . ErrNoChanges ) {
return nil
}
2022-09-01 01:09:44 +00:00
return xerrors . Errorf ( "reconfig: %w" , err )
}
2023-07-12 22:37:31 +00:00
2022-09-01 01:09:44 +00:00
return nil
}
2023-03-02 14:06:00 +00:00
// NodeAddresses returns the addresses of a node from the NetworkMap.
func ( c * Conn ) NodeAddresses ( publicKey key . NodePublic ) ( [ ] netip . Prefix , bool ) {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
for _ , node := range c . netMap . Peers {
if node . Key == publicKey {
return node . Addresses , true
}
}
return nil , false
}
2022-09-01 01:09:44 +00:00
// Status returns the current ipnstate of a connection.
func ( c * Conn ) Status ( ) * ipnstate . Status {
2023-02-10 03:43:18 +00:00
sb := & ipnstate . StatusBuilder { WantPeers : true }
2022-09-01 16:41:47 +00:00
c . wireguardEngine . UpdateStatus ( sb )
2022-09-01 01:09:44 +00:00
return sb . Status ( )
}
2022-11-13 17:33:05 +00:00
// Ping sends a Disco ping to the Wireguard engine.
2022-12-18 23:50:06 +00:00
// The bool returned is true if the ping was performed P2P.
2023-02-13 16:38:00 +00:00
func ( c * Conn ) Ping ( ctx context . Context , ip netip . Addr ) ( time . Duration , bool , * ipnstate . PingResult , error ) {
2022-11-13 17:33:05 +00:00
errCh := make ( chan error , 1 )
2022-12-18 23:50:06 +00:00
prChan := make ( chan * ipnstate . PingResult , 1 )
2022-11-13 17:33:05 +00:00
go c . wireguardEngine . Ping ( ip , tailcfg . PingDisco , func ( pr * ipnstate . PingResult ) {
if pr . Err != "" {
errCh <- xerrors . New ( pr . Err )
return
}
2022-12-18 23:50:06 +00:00
prChan <- pr
2022-11-13 17:33:05 +00:00
} )
select {
case err := <- errCh :
2023-02-13 16:38:00 +00:00
return 0 , false , nil , err
2022-11-13 17:33:05 +00:00
case <- ctx . Done ( ) :
2023-02-13 16:38:00 +00:00
return 0 , false , nil , ctx . Err ( )
2022-12-18 23:50:06 +00:00
case pr := <- prChan :
2023-02-13 16:38:00 +00:00
return time . Duration ( pr . LatencySeconds * float64 ( time . Second ) ) , pr . Endpoint != "" , pr , nil
2022-11-13 17:33:05 +00:00
}
}
2022-12-18 23:50:06 +00:00
// DERPMap returns the currently set DERP mapping.
func ( c * Conn ) DERPMap ( ) * tailcfg . DERPMap {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
return c . netMap . DERPMap
}
2023-06-21 22:02:05 +00:00
// BlockEndpoints returns whether or not P2P is blocked.
func ( c * Conn ) BlockEndpoints ( ) bool {
c . mutex . Lock ( )
defer c . mutex . Unlock ( )
return c . blockEndpoints
}
2022-11-13 17:33:05 +00:00
// AwaitReachable pings the provided IP continually until the
// address is reachable. It's the callers responsibility to provide
// a timeout, otherwise this function will block forever.
func ( c * Conn ) AwaitReachable ( ctx context . Context , ip netip . Addr ) bool {
2022-11-15 18:59:22 +00:00
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( ) // Cancel all pending pings on exit.
completedCtx , completed := context . WithCancel ( context . Background ( ) )
defer completed ( )
2022-11-13 17:33:05 +00:00
run := func ( ) {
2022-11-15 18:59:22 +00:00
// Safety timeout, initially we'll have around 10-20 goroutines
// running in parallel. The exponential backoff will converge
// around ~1 ping / 30s, this means we'll have around 10-20
// goroutines pending towards the end as well.
ctx , cancel := context . WithTimeout ( ctx , 5 * time . Minute )
defer cancel ( )
2023-02-13 16:38:00 +00:00
_ , _ , _ , err := c . Ping ( ctx , ip )
2022-11-13 17:33:05 +00:00
if err == nil {
completed ( )
}
}
2022-11-15 18:59:22 +00:00
eb := backoff . NewExponentialBackOff ( )
eb . MaxElapsedTime = 0
eb . InitialInterval = 50 * time . Millisecond
eb . MaxInterval = 30 * time . Second
// Consume the first interval since
// we'll fire off a ping immediately.
_ = eb . NextBackOff ( )
t := backoff . NewTicker ( eb )
defer t . Stop ( )
2022-11-13 17:33:05 +00:00
go run ( )
for {
select {
case <- completedCtx . Done ( ) :
return true
2022-11-15 18:59:22 +00:00
case <- t . C :
2022-11-13 17:33:05 +00:00
// Pings can take a while, so we can run multiple
// in parallel to return ASAP.
go run ( )
case <- ctx . Done ( ) :
return false
}
}
2022-09-01 01:09:44 +00:00
}
// Closed is a channel that ends when the connection has
// been closed.
func ( c * Conn ) Closed ( ) <- chan struct { } {
return c . closed
}
// Close shuts down the Wireguard connection.
func ( c * Conn ) Close ( ) error {
c . mutex . Lock ( )
select {
case <- c . closed :
2022-09-12 17:46:45 +00:00
c . mutex . Unlock ( )
2022-09-01 01:09:44 +00:00
return nil
default :
}
2022-09-12 17:46:45 +00:00
close ( c . closed )
c . mutex . Unlock ( )
2023-02-24 11:11:28 +00:00
var wg sync . WaitGroup
defer wg . Wait ( )
if c . trafficStats != nil {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
_ = c . trafficStats . Shutdown ( ctx )
} ( )
}
2022-09-01 01:09:44 +00:00
_ = c . netStack . Close ( )
2023-02-24 11:11:28 +00:00
c . dialCancel ( )
2022-09-01 01:09:44 +00:00
_ = c . wireguardMonitor . Close ( )
2023-02-24 11:11:28 +00:00
_ = c . dialer . Close ( )
// Stops internals, e.g. tunDevice, magicConn and dnsManager.
2022-09-01 01:09:44 +00:00
c . wireguardEngine . Close ( )
2023-02-24 11:11:28 +00:00
c . mutex . Lock ( )
for _ , l := range c . listeners {
_ = l . closeNoLock ( )
2023-02-10 03:43:18 +00:00
}
2023-02-24 11:11:28 +00:00
c . listeners = nil
c . mutex . Unlock ( )
2022-09-01 01:09:44 +00:00
return nil
}
2022-09-12 17:46:45 +00:00
func ( c * Conn ) isClosed ( ) bool {
select {
case <- c . closed :
return true
default :
return false
}
}
2022-09-22 20:22:49 +00:00
func ( c * Conn ) sendNode ( ) {
c . lastMutex . Lock ( )
defer c . lastMutex . Unlock ( )
if c . nodeSending {
c . nodeChanged = true
return
}
2022-12-18 23:50:06 +00:00
node := c . selfNode ( )
2023-05-04 10:30:57 +00:00
// Conn.UpdateNodes will skip any nodes that don't have the PreferredDERP
// set to non-zero, since we cannot reach nodes without DERP for discovery.
// Therefore, there is no point in sending the node without this, and we can
// save ourselves from churn in the tailscale/wireguard layer.
if node . PreferredDERP == 0 {
c . logger . Debug ( context . Background ( ) , "skipped sending node; no PreferredDERP" , slog . F ( "node" , node ) )
return
}
2022-09-22 20:22:49 +00:00
nodeCallback := c . nodeCallback
if nodeCallback == nil {
return
}
c . nodeSending = true
go func ( ) {
2022-11-13 17:33:05 +00:00
c . logger . Debug ( context . Background ( ) , "sending node" , slog . F ( "node" , node ) )
2022-09-22 20:22:49 +00:00
nodeCallback ( node )
c . lastMutex . Lock ( )
c . nodeSending = false
if c . nodeChanged {
c . nodeChanged = false
c . lastMutex . Unlock ( )
c . sendNode ( )
return
}
c . lastMutex . Unlock ( )
} ( )
}
2022-12-18 23:50:06 +00:00
// Node returns the last node that was sent to the node callback.
func ( c * Conn ) Node ( ) * Node {
c . lastMutex . Lock ( )
defer c . lastMutex . Unlock ( )
return c . selfNode ( )
}
func ( c * Conn ) selfNode ( ) * Node {
2023-02-10 22:59:24 +00:00
endpoints := make ( [ ] string , 0 , len ( c . lastEndpoints ) )
for _ , addr := range c . lastEndpoints {
endpoints = append ( endpoints , addr . Addr . String ( ) )
}
var preferredDERP int
var derpLatency map [ string ] float64
2023-03-07 03:29:41 +00:00
derpForcedWebsocket := make ( map [ int ] string , 0 )
2023-02-10 22:59:24 +00:00
if c . lastNetInfo != nil {
preferredDERP = c . lastNetInfo . PreferredDERP
derpLatency = c . lastNetInfo . DERPLatency
2023-03-07 03:29:41 +00:00
for k , v := range c . lastDERPForcedWebsockets {
derpForcedWebsocket [ k ] = v
}
2023-02-10 22:59:24 +00:00
}
2022-12-18 23:50:06 +00:00
node := & Node {
2023-03-01 22:18:14 +00:00
ID : c . netMap . SelfNode . ID ,
AsOf : database . Now ( ) ,
Key : c . netMap . SelfNode . Key ,
Addresses : c . netMap . SelfNode . Addresses ,
AllowedIPs : c . netMap . SelfNode . AllowedIPs ,
DiscoKey : c . magicConn . DiscoPublicKey ( ) ,
Endpoints : endpoints ,
PreferredDERP : preferredDERP ,
DERPLatency : derpLatency ,
DERPForcedWebsocket : derpForcedWebsocket ,
2022-12-18 23:50:06 +00:00
}
2023-06-26 15:01:50 +00:00
c . mutex . Lock ( )
2022-12-18 23:50:06 +00:00
if c . blockEndpoints {
node . Endpoints = nil
}
2023-06-26 15:01:50 +00:00
c . mutex . Unlock ( )
2022-12-18 23:50:06 +00:00
return node
}
2022-09-01 01:09:44 +00:00
// This and below is taken _mostly_ verbatim from Tailscale:
// https://github.com/tailscale/tailscale/blob/c88bd53b1b7b2fcf7ba302f2e53dd1ce8c32dad4/tsnet/tsnet.go#L459-L494
2023-04-18 22:53:11 +00:00
// Listen listens for connections only on the Tailscale network.
2022-09-01 01:09:44 +00:00
func ( c * Conn ) Listen ( network , addr string ) ( net . Listener , error ) {
host , port , err := net . SplitHostPort ( addr )
if err != nil {
2023-04-18 22:53:11 +00:00
return nil , xerrors . Errorf ( "tailnet: split host port for listen: %w" , err )
2022-09-01 01:09:44 +00:00
}
lk := listenKey { network , host , port }
ln := & listener {
s : c ,
key : lk ,
addr : addr ,
2022-09-12 17:46:45 +00:00
closed : make ( chan struct { } ) ,
conn : make ( chan net . Conn ) ,
2022-09-01 01:09:44 +00:00
}
c . mutex . Lock ( )
2022-09-12 17:46:45 +00:00
if c . isClosed ( ) {
c . mutex . Unlock ( )
return nil , xerrors . New ( "closed" )
}
2022-09-01 01:09:44 +00:00
if c . listeners == nil {
c . listeners = map [ listenKey ] * listener { }
}
if _ , ok := c . listeners [ lk ] ; ok {
c . mutex . Unlock ( )
2023-04-18 22:53:11 +00:00
return nil , xerrors . Errorf ( "tailnet: listener already open for %s, %s" , network , addr )
2022-09-01 01:09:44 +00:00
}
c . listeners [ lk ] = ln
c . mutex . Unlock ( )
return ln , nil
}
func ( c * Conn ) DialContextTCP ( ctx context . Context , ipp netip . AddrPort ) ( * gonet . TCPConn , error ) {
return c . netStack . DialContextTCP ( ctx , ipp )
}
func ( c * Conn ) DialContextUDP ( ctx context . Context , ipp netip . AddrPort ) ( * gonet . UDPConn , error ) {
return c . netStack . DialContextUDP ( ctx , ipp )
}
2023-04-20 22:58:22 +00:00
func ( c * Conn ) forwardTCP ( conn net . Conn , port uint16 ) {
2022-09-01 01:09:44 +00:00
c . mutex . Lock ( )
2023-04-20 22:58:22 +00:00
ln , ok := c . listeners [ listenKey { "tcp" , "" , fmt . Sprint ( port ) } ]
2022-09-01 01:09:44 +00:00
c . mutex . Unlock ( )
if ! ok {
2023-04-20 22:58:22 +00:00
c . forwardTCPToLocal ( conn , port )
return
}
t := time . NewTimer ( time . Second )
defer t . Stop ( )
select {
case ln . conn <- conn :
return
case <- ln . closed :
case <- c . closed :
case <- t . C :
2022-09-01 01:09:44 +00:00
}
2023-04-20 22:58:22 +00:00
_ = conn . Close ( )
}
func ( * Conn ) forwardTCPSockOpts ( port uint16 ) [ ] tcpip . SettableSocketOption {
opts := [ ] tcpip . SettableSocketOption { }
2023-04-18 22:53:11 +00:00
// See: https://github.com/tailscale/tailscale/blob/c7cea825aea39a00aca71ea02bab7266afc03e7c/wgengine/netstack/netstack.go#L888
2023-04-20 22:58:22 +00:00
if port == WorkspaceAgentSSHPort || port == 22 {
2023-06-16 13:22:18 +00:00
opt := tcpip . KeepaliveIdleOption ( 72 * time . Hour + time . Minute ) // Default ssh-max-timeout is 72h, so let's add some extra time.
2023-04-18 22:53:11 +00:00
opts = append ( opts , & opt )
}
2023-04-20 22:58:22 +00:00
return opts
}
func ( c * Conn ) forwardTCPToLocal ( conn net . Conn , port uint16 ) {
defer conn . Close ( )
dialAddrStr := net . JoinHostPort ( "127.0.0.1" , strconv . Itoa ( int ( port ) ) )
var stdDialer net . Dialer
server , err := stdDialer . DialContext ( c . dialContext , "tcp" , dialAddrStr )
if err != nil {
c . logger . Debug ( c . dialContext , "dial local port" , slog . F ( "port" , port ) , slog . Error ( err ) )
return
}
defer server . Close ( )
connClosed := make ( chan error , 2 )
go func ( ) {
_ , err := io . Copy ( server , conn )
connClosed <- err
} ( )
go func ( ) {
_ , err := io . Copy ( conn , server )
connClosed <- err
} ( )
select {
case err = <- connClosed :
case <- c . closed :
return
}
if err != nil {
c . logger . Debug ( c . dialContext , "proxy connection closed with error" , slog . Error ( err ) )
}
c . logger . Debug ( c . dialContext , "forwarded connection closed" , slog . F ( "local_addr" , dialAddrStr ) )
2022-09-01 01:09:44 +00:00
}
2023-02-10 03:43:18 +00:00
// SetConnStatsCallback sets a callback to be called after maxPeriod or
// maxConns, whichever comes first. Multiple calls overwrites the callback.
func ( c * Conn ) SetConnStatsCallback ( maxPeriod time . Duration , maxConns int , dump func ( start , end time . Time , virtual , physical map [ netlogtype . Connection ] netlogtype . Counts ) ) {
connStats := connstats . NewStatistics ( maxPeriod , maxConns , dump )
2023-02-24 11:11:28 +00:00
shutdown := func ( s * connstats . Statistics ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
_ = s . Shutdown ( ctx )
}
2023-02-10 03:43:18 +00:00
c . mutex . Lock ( )
2023-02-24 11:11:28 +00:00
if c . isClosed ( ) {
c . mutex . Unlock ( )
shutdown ( connStats )
return
}
2023-02-10 03:43:18 +00:00
old := c . trafficStats
c . trafficStats = connStats
c . mutex . Unlock ( )
// Make sure to shutdown the old callback.
if old != nil {
2023-02-24 11:11:28 +00:00
shutdown ( old )
2023-02-10 03:43:18 +00:00
}
c . tunDevice . SetStatistics ( connStats )
2022-11-18 22:46:53 +00:00
}
2023-04-26 18:01:49 +00:00
func ( c * Conn ) MagicsockServeHTTPDebug ( w http . ResponseWriter , r * http . Request ) {
c . magicConn . ServeHTTPDebug ( w , r )
}
2022-09-01 01:09:44 +00:00
type listenKey struct {
network string
host string
port string
}
type listener struct {
2022-09-12 17:46:45 +00:00
s * Conn
key listenKey
addr string
conn chan net . Conn
closed chan struct { }
2022-09-01 01:09:44 +00:00
}
func ( ln * listener ) Accept ( ) ( net . Conn , error ) {
2022-09-12 17:46:45 +00:00
var c net . Conn
select {
case c = <- ln . conn :
case <- ln . closed :
2023-04-18 22:53:11 +00:00
return nil , xerrors . Errorf ( "tailnet: %w" , net . ErrClosed )
2022-09-01 01:09:44 +00:00
}
return c , nil
}
func ( ln * listener ) Addr ( ) net . Addr { return addr { ln } }
func ( ln * listener ) Close ( ) error {
ln . s . mutex . Lock ( )
defer ln . s . mutex . Unlock ( )
return ln . closeNoLock ( )
}
func ( ln * listener ) closeNoLock ( ) error {
if v , ok := ln . s . listeners [ ln . key ] ; ok && v == ln {
delete ( ln . s . listeners , ln . key )
2022-09-12 17:46:45 +00:00
close ( ln . closed )
2022-09-01 01:09:44 +00:00
}
return nil
}
type addr struct { ln * listener }
func ( a addr ) Network ( ) string { return a . ln . key . network }
func ( a addr ) String ( ) string { return a . ln . addr }
// Logger converts the Tailscale logging function to use slog.
func Logger ( logger slog . Logger ) tslogger . Logf {
return tslogger . Logf ( func ( format string , args ... any ) {
2023-02-24 11:11:28 +00:00
slog . Helper ( )
2022-09-01 01:09:44 +00:00
logger . Debug ( context . Background ( ) , fmt . Sprintf ( format , args ... ) )
} )
}
2023-02-10 22:59:24 +00:00
func endpointsEqual ( x , y [ ] tailcfg . Endpoint ) bool {
if len ( x ) != len ( y ) {
return false
}
for i := range x {
if x [ i ] != y [ i ] {
return false
}
}
return true
}