From 754fb9a8a8c18735befc2b26dd8263d658b3e7ec Mon Sep 17 00:00:00 2001 From: Claire Wang Date: Fri, 13 Oct 2023 14:13:41 -0400 Subject: [PATCH] tailcfg: add tailnet field to register request (#9675) Updates tailscale/corp#10967 Signed-off-by: Claire Wang --- control/controlclient/direct.go | 7 +++++++ tailcfg/tailcfg.go | 11 +++++++++++ tailcfg/tailcfg_clone.go | 1 + tailcfg/tailcfg_view.go | 2 ++ util/syspolicy/policy_keys.go | 2 +- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 81310e4be..80f6e919b 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -55,6 +55,7 @@ import ( "tailscale.com/util/clientmetric" "tailscale.com/util/multierr" "tailscale.com/util/singleflight" + "tailscale.com/util/syspolicy" "tailscale.com/util/systemd" ) @@ -566,6 +567,11 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new err = errors.New("hostinfo: BackendLogID missing") return regen, opt.URL, nil, err } + + tailnet, err := syspolicy.GetString(syspolicy.Tailnet, "") + if err != nil { + c.logf("unable to provide Tailnet field in register request. err: %v", err) + } now := c.clock.Now().Round(time.Second) request := tailcfg.RegisterRequest{ Version: 1, @@ -577,6 +583,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new Timestamp: &now, Ephemeral: (opt.Flags & LoginEphemeral) != 0, NodeKeySignature: nodeKeySignature, + Tailnet: tailnet, } if opt.Logout { request.Expiry = time.Unix(123, 0) // far in the past diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 2dcf8ab88..e7eac4a25 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -1100,6 +1100,17 @@ type RegisterRequest struct { Timestamp *time.Time `json:",omitempty"` // creation time of request to prevent replay DeviceCert []byte `json:",omitempty"` // X.509 certificate for client device Signature []byte `json:",omitempty"` // as described by SignatureType + + // Tailnet is an optional identifier specifying the name of the recommended or required + // network that the node should join. Its exact form should not be depended on; new + // forms are coming later. The identifier is generally a domain name (for an organization) + // or e-mail address (for a personal account on a shared e-mail provider). It is the same name + // used by the API, as described in /api.md#tailnet. + // If Tailnet begins with the prefix "required:" then the server should prevent logging in to a different + // network than the one specified. Otherwise, the server should recommend the specified network + // but still permit logging in to other networks. + // If empty, no recommendation is offered to the server and the login page should show all options. + Tailnet string `json:",omitempty"` } // RegisterResponse is returned by the server in response to a RegisterRequest. diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go index da5a11b77..c652fcb1f 100644 --- a/tailcfg/tailcfg_clone.go +++ b/tailcfg/tailcfg_clone.go @@ -362,6 +362,7 @@ var _RegisterRequestCloneNeedsRegeneration = RegisterRequest(struct { Timestamp *time.Time DeviceCert []byte Signature []byte + Tailnet string }{}) // Clone makes a deep copy of DERPHomeParams. diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go index 74991eb11..c374abf81 100644 --- a/tailcfg/tailcfg_view.go +++ b/tailcfg/tailcfg_view.go @@ -792,6 +792,7 @@ func (v RegisterRequestView) DeviceCert() views.ByteSlice[[]byte] { func (v RegisterRequestView) Signature() views.ByteSlice[[]byte] { return views.ByteSliceOf(v.ж.Signature) } +func (v RegisterRequestView) Tailnet() string { return v.ж.Tailnet } // A compilation failure here means this code must be regenerated, with the command at the top of this file. var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct { @@ -810,6 +811,7 @@ var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct { Timestamp *time.Time DeviceCert []byte Signature []byte + Tailnet string }{}) // View returns a readonly view of DERPHomeParams. diff --git a/util/syspolicy/policy_keys.go b/util/syspolicy/policy_keys.go index 80b266730..50ca39c73 100644 --- a/util/syspolicy/policy_keys.go +++ b/util/syspolicy/policy_keys.go @@ -9,6 +9,7 @@ const ( // Keys with a string value ControlURL Key = "LoginURL" // default ""; if blank, ipn uses ipn.DefaultControlURL. LogTarget Key = "LogTarget" // default ""; if blank logging uses logtail.DefaultHost. + Tailnet Key = "Tailnet" // default ""; if blank, no tailnet name is sent to the server. // Keys with a string value that specifies an option: "always", "never", "user-decides". // The default is "user-decides" unless otherwise stated. @@ -32,7 +33,6 @@ const ( // The default is 0 unless otherwise stated. LogSCMInteractions Key = "LogSCMInteractions" FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock" - // Boolean key that indicates if posture checking is enabled and the client shall gather // posture data. PostureChecking Key = "PostureChecking"