|
|
|
@ -261,15 +261,14 @@ const (
|
|
|
|
|
func (c *Direct) TryLogout(ctx context.Context) error {
|
|
|
|
|
c.logf("direct.TryLogout()")
|
|
|
|
|
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
|
mustRegen, newURL, err := c.doLogin(ctx, loginOpt{Logout: true})
|
|
|
|
|
c.logf("TryLogout control response: mustRegen=%v, newURL=%v, err=%v", mustRegen, newURL, err)
|
|
|
|
|
|
|
|
|
|
// TODO(crawshaw): Tell the server. This node key should be
|
|
|
|
|
// immediately invalidated.
|
|
|
|
|
//if !c.persist.PrivateNodeKey.IsZero() {
|
|
|
|
|
//}
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
c.persist = persist.Persist{}
|
|
|
|
|
return nil
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Direct) TryLogin(ctx context.Context, t *tailcfg.Oauth2Token, flags LoginFlags) (url string, err error) {
|
|
|
|
@ -298,10 +297,11 @@ func (c *Direct) doLoginOrRegen(ctx context.Context, opt loginOpt) (newURL strin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type loginOpt struct {
|
|
|
|
|
Token *tailcfg.Oauth2Token
|
|
|
|
|
Flags LoginFlags
|
|
|
|
|
Regen bool
|
|
|
|
|
URL string
|
|
|
|
|
Token *tailcfg.Oauth2Token
|
|
|
|
|
Flags LoginFlags
|
|
|
|
|
Regen bool
|
|
|
|
|
URL string
|
|
|
|
|
Logout bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, newURL string, err error) {
|
|
|
|
@ -324,14 +324,18 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
regen := opt.Regen
|
|
|
|
|
if expired {
|
|
|
|
|
c.logf("Old key expired -> regen=true")
|
|
|
|
|
systemd.Status("key expired; run 'tailscale up' to authenticate")
|
|
|
|
|
regen = true
|
|
|
|
|
}
|
|
|
|
|
if (opt.Flags & LoginInteractive) != 0 {
|
|
|
|
|
c.logf("LoginInteractive -> regen=true")
|
|
|
|
|
regen = true
|
|
|
|
|
if opt.Logout {
|
|
|
|
|
c.logf("logging out...")
|
|
|
|
|
} else {
|
|
|
|
|
if expired {
|
|
|
|
|
c.logf("Old key expired -> regen=true")
|
|
|
|
|
systemd.Status("key expired; run 'tailscale up' to authenticate")
|
|
|
|
|
regen = true
|
|
|
|
|
}
|
|
|
|
|
if (opt.Flags & LoginInteractive) != 0 {
|
|
|
|
|
c.logf("LoginInteractive -> regen=true")
|
|
|
|
|
regen = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.logf("doLogin(regen=%v, hasUrl=%v)", regen, opt.URL != "")
|
|
|
|
@ -348,8 +352,12 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var oldNodeKey wgkey.Key
|
|
|
|
|
if opt.URL != "" {
|
|
|
|
|
} else if regen || persist.PrivateNodeKey.IsZero() {
|
|
|
|
|
switch {
|
|
|
|
|
case opt.Logout:
|
|
|
|
|
tryingNewKey = persist.PrivateNodeKey
|
|
|
|
|
case opt.URL != "":
|
|
|
|
|
// Nothing.
|
|
|
|
|
case regen || persist.PrivateNodeKey.IsZero():
|
|
|
|
|
c.logf("Generating a new nodekey.")
|
|
|
|
|
persist.OldPrivateNodeKey = persist.PrivateNodeKey
|
|
|
|
|
key, err := wgkey.NewPrivate()
|
|
|
|
@ -358,7 +366,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
return regen, opt.URL, err
|
|
|
|
|
}
|
|
|
|
|
tryingNewKey = key
|
|
|
|
|
} else {
|
|
|
|
|
default:
|
|
|
|
|
// Try refreshing the current key first
|
|
|
|
|
tryingNewKey = persist.PrivateNodeKey
|
|
|
|
|
}
|
|
|
|
@ -367,6 +375,9 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if tryingNewKey.IsZero() {
|
|
|
|
|
if opt.Logout {
|
|
|
|
|
return false, "", errors.New("no nodekey to log out")
|
|
|
|
|
}
|
|
|
|
|
log.Fatalf("tryingNewKey is empty, give up")
|
|
|
|
|
}
|
|
|
|
|
if backendLogID == "" {
|
|
|
|
@ -382,6 +393,9 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
Followup: opt.URL,
|
|
|
|
|
Timestamp: &now,
|
|
|
|
|
}
|
|
|
|
|
if opt.Logout {
|
|
|
|
|
request.Expiry = time.Unix(123, 0) // far in the past
|
|
|
|
|
}
|
|
|
|
|
c.logf("RegisterReq: onode=%v node=%v fup=%v",
|
|
|
|
|
request.OldNodeKey.ShortString(),
|
|
|
|
|
request.NodeKey.ShortString(), opt.URL != "")
|
|
|
|
@ -403,6 +417,11 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
c.logf("RegisterReq sign error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if debugRegister {
|
|
|
|
|
j, _ := json.MarshalIndent(request, "", "\t")
|
|
|
|
|
c.logf("RegisterRequest: %s", j)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bodyData, err := encode(request, &serverKey, &machinePrivKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return regen, opt.URL, err
|
|
|
|
@ -431,6 +450,11 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
|
|
|
|
|
c.logf("error decoding RegisterResponse with server key %s and machine key %s: %v", serverKey, machinePrivKey.Public(), err)
|
|
|
|
|
return regen, opt.URL, fmt.Errorf("register request: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if debugRegister {
|
|
|
|
|
j, _ := json.MarshalIndent(resp, "", "\t")
|
|
|
|
|
c.logf("RegisterResponse: %s", j)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log without PII:
|
|
|
|
|
c.logf("RegisterReq: got response; nodeKeyExpired=%v, machineAuthorized=%v; authURL=%v",
|
|
|
|
|
resp.NodeKeyExpired, resp.MachineAuthorized, resp.AuthURL != "")
|
|
|
|
@ -902,7 +926,10 @@ func decode(res *http.Response, v interface{}, serverKey *wgkey.Key, mkey *wgkey
|
|
|
|
|
return decodeMsg(msg, v, serverKey, mkey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var debugMap, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_MAP"))
|
|
|
|
|
var (
|
|
|
|
|
debugMap, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_MAP"))
|
|
|
|
|
debugRegister, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_REGISTER"))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var jsonEscapedZero = []byte(`\u0000`)
|
|
|
|
|
|
|
|
|
|