@ -42,6 +42,7 @@ import (
"tailscale.com/portlist"
"tailscale.com/portlist"
"tailscale.com/syncs"
"tailscale.com/syncs"
"tailscale.com/tailcfg"
"tailscale.com/tailcfg"
"tailscale.com/tka"
"tailscale.com/types/dnstype"
"tailscale.com/types/dnstype"
"tailscale.com/types/empty"
"tailscale.com/types/empty"
"tailscale.com/types/key"
"tailscale.com/types/key"
@ -146,6 +147,8 @@ type LocalBackend struct {
prefs * ipn . Prefs
prefs * ipn . Prefs
inServerMode bool
inServerMode bool
machinePrivKey key . MachinePrivate
machinePrivKey key . MachinePrivate
nlPrivKey key . NLPrivate
tka * tka . Authority
state ipn . State
state ipn . State
capFileSharing bool // whether netMap contains the file sharing capability
capFileSharing bool // whether netMap contains the file sharing capability
// hostinfo is mutated in-place while mu is held.
// hostinfo is mutated in-place while mu is held.
@ -997,6 +1000,9 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
return fmt . Errorf ( "initMachineKeyLocked: %w" , err )
return fmt . Errorf ( "initMachineKeyLocked: %w" , err )
}
}
}
}
if err := b . initNLKeyLocked ( ) ; err != nil {
return fmt . Errorf ( "initNLKeyLocked: %w" , err )
}
loggedOut := b . prefs . LoggedOut
loggedOut := b . prefs . LoggedOut
@ -1056,6 +1062,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
// but it won't take effect until the next Start().
// but it won't take effect until the next Start().
cc , err := b . getNewControlClientFunc ( ) ( controlclient . Options {
cc , err := b . getNewControlClientFunc ( ) ( controlclient . Options {
GetMachinePrivateKey : b . createGetMachinePrivateKeyFunc ( ) ,
GetMachinePrivateKey : b . createGetMachinePrivateKeyFunc ( ) ,
GetNLPublicKey : b . createGetNLPublicKeyFunc ( ) ,
Logf : logger . WithPrefix ( b . logf , "control: " ) ,
Logf : logger . WithPrefix ( b . logf , "control: " ) ,
Persist : * persistv ,
Persist : * persistv ,
ServerURL : b . serverURL ,
ServerURL : b . serverURL ,
@ -1515,6 +1522,21 @@ func (b *LocalBackend) createGetMachinePrivateKeyFunc() func() (key.MachinePriva
}
}
}
}
func ( b * LocalBackend ) createGetNLPublicKeyFunc ( ) func ( ) ( key . NLPublic , error ) {
var cache atomic . Value
return func ( ) ( key . NLPublic , error ) {
b . mu . Lock ( )
defer b . mu . Unlock ( )
if v , ok := cache . Load ( ) . ( key . NLPublic ) ; ok {
return v , nil
}
pub := b . nlPrivKey . Public ( )
cache . Store ( pub )
return pub , nil
}
}
// initMachineKeyLocked is called to initialize b.machinePrivKey.
// initMachineKeyLocked is called to initialize b.machinePrivKey.
//
//
// b.prefs must already be initialized.
// b.prefs must already be initialized.
@ -1573,6 +1595,45 @@ func (b *LocalBackend) initMachineKeyLocked() (err error) {
return nil
return nil
}
}
// initNLKeyLocked is called to initialize b.nlPrivKey.
//
// b.prefs must already be initialized.
// b.stateKey should be set too, but just for nicer log messages.
// b.mu must be held.
func ( b * LocalBackend ) initNLKeyLocked ( ) ( err error ) {
if ! b . nlPrivKey . IsZero ( ) {
// Already set.
return nil
}
keyText , err := b . store . ReadState ( ipn . NLKeyStateKey )
if err == nil {
if err := b . nlPrivKey . UnmarshalText ( keyText ) ; err != nil {
return fmt . Errorf ( "invalid key in %s key of %v: %w" , ipn . NLKeyStateKey , b . store , err )
}
if b . nlPrivKey . IsZero ( ) {
return fmt . Errorf ( "invalid zero key stored in %v key of %v" , ipn . NLKeyStateKey , b . store )
}
return nil
}
if err != ipn . ErrStateNotExist {
return fmt . Errorf ( "error reading %v key of %v: %w" , ipn . NLKeyStateKey , b . store , err )
}
// If we didn't find one already on disk, generate a new one.
b . logf ( "generating new network-lock key" )
b . nlPrivKey = key . NewNLPrivate ( )
keyText , _ = b . nlPrivKey . MarshalText ( )
if err := b . store . WriteState ( ipn . NLKeyStateKey , keyText ) ; err != nil {
b . logf ( "error writing network-lock key to store: %v" , err )
return err
}
b . logf ( "network-lock key written to store" )
return nil
}
// writeServerModeStartState stores the ServerModeStartKey value based on the current
// writeServerModeStartState stores the ServerModeStartKey value based on the current
// user and prefs. If userID is blank or prefs is blank, no work is done.
// user and prefs. If userID is blank or prefs is blank, no work is done.
//
//
@ -2437,6 +2498,14 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
return dcfg
return dcfg
}
}
// SetTailnetKeyAuthority sets the key authority which should be
// used for locked tailnets.
//
// It should only be called before the LocalBackend is used.
func ( b * LocalBackend ) SetTailnetKeyAuthority ( a * tka . Authority ) {
b . tka = a
}
// SetVarRoot sets the root directory of Tailscale's writable
// SetVarRoot sets the root directory of Tailscale's writable
// storage area . (e.g. "/var/lib/tailscale")
// storage area . (e.g. "/var/lib/tailscale")
//
//