Browse Source

tailcfg: add tailnet field to register request (#9675)

Updates tailscale/corp#10967

Signed-off-by: Claire Wang <[email protected]>
Claire Wang 2 years ago
parent
commit
754fb9a8a8

+ 7 - 0
control/controlclient/direct.go

@@ -55,6 +55,7 @@ import (
 	"tailscale.com/util/clientmetric"
 	"tailscale.com/util/clientmetric"
 	"tailscale.com/util/multierr"
 	"tailscale.com/util/multierr"
 	"tailscale.com/util/singleflight"
 	"tailscale.com/util/singleflight"
+	"tailscale.com/util/syspolicy"
 	"tailscale.com/util/systemd"
 	"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")
 		err = errors.New("hostinfo: BackendLogID missing")
 		return regen, opt.URL, nil, err
 		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)
 	now := c.clock.Now().Round(time.Second)
 	request := tailcfg.RegisterRequest{
 	request := tailcfg.RegisterRequest{
 		Version:          1,
 		Version:          1,
@@ -577,6 +583,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
 		Timestamp:        &now,
 		Timestamp:        &now,
 		Ephemeral:        (opt.Flags & LoginEphemeral) != 0,
 		Ephemeral:        (opt.Flags & LoginEphemeral) != 0,
 		NodeKeySignature: nodeKeySignature,
 		NodeKeySignature: nodeKeySignature,
+		Tailnet:          tailnet,
 	}
 	}
 	if opt.Logout {
 	if opt.Logout {
 		request.Expiry = time.Unix(123, 0) // far in the past
 		request.Expiry = time.Unix(123, 0) // far in the past

+ 11 - 0
tailcfg/tailcfg.go

@@ -1100,6 +1100,17 @@ type RegisterRequest struct {
 	Timestamp     *time.Time    `json:",omitempty"` // creation time of request to prevent replay
 	Timestamp     *time.Time    `json:",omitempty"` // creation time of request to prevent replay
 	DeviceCert    []byte        `json:",omitempty"` // X.509 certificate for client device
 	DeviceCert    []byte        `json:",omitempty"` // X.509 certificate for client device
 	Signature     []byte        `json:",omitempty"` // as described by SignatureType
 	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.
 // RegisterResponse is returned by the server in response to a RegisterRequest.

+ 1 - 0
tailcfg/tailcfg_clone.go

@@ -362,6 +362,7 @@ var _RegisterRequestCloneNeedsRegeneration = RegisterRequest(struct {
 	Timestamp        *time.Time
 	Timestamp        *time.Time
 	DeviceCert       []byte
 	DeviceCert       []byte
 	Signature        []byte
 	Signature        []byte
+	Tailnet          string
 }{})
 }{})
 
 
 // Clone makes a deep copy of DERPHomeParams.
 // Clone makes a deep copy of DERPHomeParams.

+ 2 - 0
tailcfg/tailcfg_view.go

@@ -792,6 +792,7 @@ func (v RegisterRequestView) DeviceCert() views.ByteSlice[[]byte] {
 func (v RegisterRequestView) Signature() views.ByteSlice[[]byte] {
 func (v RegisterRequestView) Signature() views.ByteSlice[[]byte] {
 	return views.ByteSliceOf(v.ж.Signature)
 	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.
 // A compilation failure here means this code must be regenerated, with the command at the top of this file.
 var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct {
 var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct {
@@ -810,6 +811,7 @@ var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct {
 	Timestamp        *time.Time
 	Timestamp        *time.Time
 	DeviceCert       []byte
 	DeviceCert       []byte
 	Signature        []byte
 	Signature        []byte
+	Tailnet          string
 }{})
 }{})
 
 
 // View returns a readonly view of DERPHomeParams.
 // View returns a readonly view of DERPHomeParams.

+ 1 - 1
util/syspolicy/policy_keys.go

@@ -9,6 +9,7 @@ const (
 	// Keys with a string value
 	// Keys with a string value
 	ControlURL Key = "LoginURL"  // default ""; if blank, ipn uses ipn.DefaultControlURL.
 	ControlURL Key = "LoginURL"  // default ""; if blank, ipn uses ipn.DefaultControlURL.
 	LogTarget  Key = "LogTarget" // default ""; if blank logging uses logtail.DefaultHost.
 	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".
 	// Keys with a string value that specifies an option: "always", "never", "user-decides".
 	// The default is "user-decides" unless otherwise stated.
 	// The default is "user-decides" unless otherwise stated.
@@ -32,7 +33,6 @@ const (
 	// The default is 0 unless otherwise stated.
 	// The default is 0 unless otherwise stated.
 	LogSCMInteractions      Key = "LogSCMInteractions"
 	LogSCMInteractions      Key = "LogSCMInteractions"
 	FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock"
 	FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock"
-
 	// Boolean key that indicates if posture checking is enabled and the client shall gather
 	// Boolean key that indicates if posture checking is enabled and the client shall gather
 	// posture data.
 	// posture data.
 	PostureChecking Key = "PostureChecking"
 	PostureChecking Key = "PostureChecking"