control/controlclient: add Noise client

Updates #3488

Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
Maisem Ali
2022-03-07 15:32:53 -08:00
committed by Maisem Ali
parent 26f27a620a
commit 0f31a0fc76
3 changed files with 196 additions and 3 deletions

View File

@ -27,6 +27,7 @@ import (
"time"
"go4.org/mem"
"golang.org/x/sync/singleflight"
"inet.af/netaddr"
"tailscale.com/control/controlknobs"
"tailscale.com/envknob"
@ -73,6 +74,9 @@ type Direct struct {
serverKey key.MachinePublic // original ("legacy") nacl crypto_box-based public key
serverNoiseKey key.MachinePublic
sfGroup singleflight.Group // protects noiseClient creation.
noiseClient *noiseClient
persist persist.Persist
authKey string
tryingNewKey key.NodePrivate
@ -203,6 +207,19 @@ func NewDirect(opts Options) (*Direct, error) {
return c, nil
}
// Close closes the underlying Noise connection(s).
func (c *Direct) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.noiseClient != nil {
if err := c.noiseClient.Close(); err != nil {
return err
}
}
c.noiseClient = nil
return nil
}
// SetHostinfo clones the provided Hostinfo and remembers it for the
// next update. It reports whether the Hostinfo has changed.
func (c *Direct) SetHostinfo(hi *tailcfg.Hostinfo) bool {
@ -1204,6 +1221,39 @@ func sleepAsRequested(ctx context.Context, logf logger.Logf, timeoutReset chan<-
}
}
// getNoiseClient returns the noise client, creating one if one doesn't exist.
func (c *Direct) getNoiseClient() (*noiseClient, error) {
c.mu.Lock()
serverNoiseKey := c.serverNoiseKey
nc := c.noiseClient
c.mu.Unlock()
if serverNoiseKey.IsZero() {
return nil, errors.New("zero serverNoiseKey")
}
if nc != nil {
return nc, nil
}
np, err, _ := c.sfGroup.Do("noise", func() (interface{}, error) {
k, err := c.getMachinePrivKey()
if err != nil {
return nil, err
}
nc, err = newNoiseClient(k, serverNoiseKey, c.serverURL)
if err != nil {
return nil, err
}
c.mu.Lock()
defer c.mu.Unlock()
c.noiseClient = nc
return nc, nil
})
if err != nil {
return nil, err
}
return np.(*noiseClient), nil
}
// SetDNS sends the SetDNSRequest request to the control plane server,
// requesting a DNS record be created or updated.
func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) (err error) {