ipn/ipnlocal: add tailnet MagicDNS name to ipn.LoginProfile

Start backfilling MagicDNS suffixes on LoginProfiles.

Updates #9286

Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
pull/9455/head
Sonia Appasamy 1 year ago committed by Sonia Appasamy
parent 0d991249e1
commit 258f16f84b

@ -1038,7 +1038,7 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
// Perform all mutations of prefs based on the netmap here. // Perform all mutations of prefs based on the netmap here.
if prefsChanged { if prefsChanged {
// Prefs will be written out if stale; this is not safe unless locked or cloned. // Prefs will be written out if stale; this is not safe unless locked or cloned.
if err := b.pm.SetPrefs(prefs.View()); err != nil { if err := b.pm.SetPrefs(prefs.View(), st.NetMap.MagicDNSSuffix()); err != nil {
b.logf("Failed to save new controlclient state: %v", err) b.logf("Failed to save new controlclient state: %v", err)
} }
} }
@ -1089,7 +1089,7 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
b.mu.Lock() b.mu.Lock()
prefs.WantRunning = false prefs.WantRunning = false
p := prefs.View() p := prefs.View()
if err := b.pm.SetPrefs(p); err != nil { if err := b.pm.SetPrefs(p, st.NetMap.MagicDNSSuffix()); err != nil {
b.logf("Failed to save new controlclient state: %v", err) b.logf("Failed to save new controlclient state: %v", err)
} }
b.mu.Unlock() b.mu.Unlock()
@ -1484,7 +1484,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
newPrefs := opts.UpdatePrefs.Clone() newPrefs := opts.UpdatePrefs.Clone()
newPrefs.Persist = oldPrefs.Persist().AsStruct() newPrefs.Persist = oldPrefs.Persist().AsStruct()
pv := newPrefs.View() pv := newPrefs.View()
if err := b.pm.SetPrefs(pv); err != nil { if err := b.pm.SetPrefs(pv, b.netMap.MagicDNSSuffix()); err != nil {
b.logf("failed to save UpdatePrefs state: %v", err) b.logf("failed to save UpdatePrefs state: %v", err)
} }
b.setAtomicValuesFromPrefsLocked(pv) b.setAtomicValuesFromPrefsLocked(pv)
@ -2358,7 +2358,7 @@ func (b *LocalBackend) migrateStateLocked(prefs *ipn.Prefs) (err error) {
// Backend owns the state, but frontend is trying to migrate // Backend owns the state, but frontend is trying to migrate
// state into the backend. // state into the backend.
b.logf("importing frontend prefs into backend store; frontend prefs: %s", prefs.Pretty()) b.logf("importing frontend prefs into backend store; frontend prefs: %s", prefs.Pretty())
if err := b.pm.SetPrefs(prefs.View()); err != nil { if err := b.pm.SetPrefs(prefs.View(), b.netMap.MagicDNSSuffix()); err != nil {
return fmt.Errorf("store.WriteState: %v", err) return fmt.Errorf("store.WriteState: %v", err)
} }
} }
@ -2906,7 +2906,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) ipn
} }
prefs := newp.View() prefs := newp.View()
if err := b.pm.SetPrefs(prefs); err != nil { if err := b.pm.SetPrefs(prefs, b.netMap.MagicDNSSuffix()); err != nil {
b.logf("failed to save new controlclient state: %v", err) b.logf("failed to save new controlclient state: %v", err)
} }
b.lastProfileID = b.pm.CurrentProfile().ID b.lastProfileID = b.pm.CurrentProfile().ID

@ -578,7 +578,7 @@ func (b *LocalBackend) NetworkLockForceLocalDisable() error {
newPrefs := b.pm.CurrentPrefs().AsStruct().Clone() // .Persist should always be initialized here. newPrefs := b.pm.CurrentPrefs().AsStruct().Clone() // .Persist should always be initialized here.
newPrefs.Persist.DisallowedTKAStateIDs = append(newPrefs.Persist.DisallowedTKAStateIDs, stateID) newPrefs.Persist.DisallowedTKAStateIDs = append(newPrefs.Persist.DisallowedTKAStateIDs, stateID)
if err := b.pm.SetPrefs(newPrefs.View()); err != nil { if err := b.pm.SetPrefs(newPrefs.View(), b.netMap.MagicDNSSuffix()); err != nil {
return fmt.Errorf("saving prefs: %w", err) return fmt.Errorf("saving prefs: %w", err)
} }

@ -151,7 +151,7 @@ func TestTKAEnablementFlow(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
b := LocalBackend{ b := LocalBackend{
capTailnetLock: true, capTailnetLock: true,
varRoot: temp, varRoot: temp,
@ -191,7 +191,7 @@ func TestTKADisablementFlow(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
temp := t.TempDir() temp := t.TempDir()
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID)) tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID))
@ -383,7 +383,7 @@ func TestTKASync(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
// Setup the tka authority on the control plane. // Setup the tka authority on the control plane.
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2} key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
@ -605,7 +605,7 @@ func TestTKADisable(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
temp := t.TempDir() temp := t.TempDir()
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID)) tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID))
@ -696,7 +696,7 @@ func TestTKASign(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
// Make a fake TKA authority, to seed local state. // Make a fake TKA authority, to seed local state.
disablementSecret := bytes.Repeat([]byte{0xa5}, 32) disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
@ -785,7 +785,7 @@ func TestTKAForceDisable(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
temp := t.TempDir() temp := t.TempDir()
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID)) tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID))
@ -880,7 +880,7 @@ func TestTKAAffectedSigs(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
// Make a fake TKA authority, to seed local state. // Make a fake TKA authority, to seed local state.
disablementSecret := bytes.Repeat([]byte{0xa5}, 32) disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
@ -1013,7 +1013,7 @@ func TestTKARecoverCompromisedKeyFlow(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: nlPriv, NetworkLockKey: nlPriv,
}, },
}).View())) }).View(), ""))
// Make a fake TKA authority, to seed local state. // Make a fake TKA authority, to seed local state.
disablementSecret := bytes.Repeat([]byte{0xa5}, 32) disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
@ -1104,7 +1104,7 @@ func TestTKARecoverCompromisedKeyFlow(t *testing.T) {
PrivateNodeKey: nodePriv, PrivateNodeKey: nodePriv,
NetworkLockKey: cosignPriv, NetworkLockKey: cosignPriv,
}, },
}).View())) }).View(), ""))
b := LocalBackend{ b := LocalBackend{
varRoot: temp, varRoot: temp,
logf: t.Logf, logf: t.Logf,

@ -660,7 +660,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
}, },
}).View()) }).View(), "")
if !h.ps.b.OfferingExitNode() { if !h.ps.b.OfferingExitNode() {
t.Fatal("unexpectedly not offering exit node") t.Fatal("unexpectedly not offering exit node")
} }

@ -206,7 +206,12 @@ func init() {
// SetPrefs sets the current profile's prefs to the provided value. // SetPrefs sets the current profile's prefs to the provided value.
// It also saves the prefs to the StateStore. It stores a copy of the // It also saves the prefs to the StateStore. It stores a copy of the
// provided prefs, which may be accessed via CurrentPrefs. // provided prefs, which may be accessed via CurrentPrefs.
func (pm *profileManager) SetPrefs(prefsIn ipn.PrefsView) error { //
// If tailnetMagicDNSName is provided non-empty, it will be used to
// enrich the profile with the tailnet's MagicDNS name. The MagicDNS
// name cannot be pulled from prefsIn directly because it is not saved
// on ipn.Prefs (since it's not a field that is configurable by nodes).
func (pm *profileManager) SetPrefs(prefsIn ipn.PrefsView, tailnetMagicDNSName string) error {
prefs := prefsIn.AsStruct() prefs := prefsIn.AsStruct()
newPersist := prefs.Persist newPersist := prefs.Persist
if newPersist == nil || newPersist.NodeID == "" || newPersist.UserProfile.LoginName == "" { if newPersist == nil || newPersist.NodeID == "" || newPersist.UserProfile.LoginName == "" {
@ -250,6 +255,9 @@ func (pm *profileManager) SetPrefs(prefsIn ipn.PrefsView) error {
cp.ControlURL = prefs.ControlURL cp.ControlURL = prefs.ControlURL
cp.UserProfile = newPersist.UserProfile cp.UserProfile = newPersist.UserProfile
cp.NodeID = newPersist.NodeID cp.NodeID = newPersist.NodeID
if tailnetMagicDNSName != "" {
cp.TailnetMagicDNSName = tailnetMagicDNSName
}
pm.knownProfiles[cp.ID] = cp pm.knownProfiles[cp.ID] = cp
pm.currentProfile = cp pm.currentProfile = cp
if err := pm.writeKnownProfiles(); err != nil { if err := pm.writeKnownProfiles(); err != nil {
@ -589,7 +597,7 @@ func (pm *profileManager) migrateFromLegacyPrefs() error {
return fmt.Errorf("load legacy prefs: %w", err) return fmt.Errorf("load legacy prefs: %w", err)
} }
pm.dlogf("loaded legacy preferences; sentinel=%q", sentinel) pm.dlogf("loaded legacy preferences; sentinel=%q", sentinel)
if err := pm.SetPrefs(prefs); err != nil { if err := pm.SetPrefs(prefs, ""); err != nil {
metricMigrationError.Add(1) metricMigrationError.Add(1)
return fmt.Errorf("migrating _daemon profile: %w", err) return fmt.Errorf("migrating _daemon profile: %w", err)
} }

@ -41,7 +41,7 @@ func TestProfileCurrentUserSwitch(t *testing.T) {
LoginName: loginName, LoginName: loginName,
}, },
} }
if err := pm.SetPrefs(p.View()); err != nil { if err := pm.SetPrefs(p.View(), ""); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return p.View() return p.View()
@ -96,7 +96,7 @@ func TestProfileList(t *testing.T) {
LoginName: loginName, LoginName: loginName,
}, },
} }
if err := pm.SetPrefs(p.View()); err != nil { if err := pm.SetPrefs(p.View(), ""); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return p.View() return p.View()
@ -157,7 +157,7 @@ func TestProfileDupe(t *testing.T) {
reauth := func(pm *profileManager, p *persist.Persist) { reauth := func(pm *profileManager, p *persist.Persist) {
prefs := ipn.NewPrefs() prefs := ipn.NewPrefs()
prefs.Persist = p prefs.Persist = p
must.Do(pm.SetPrefs(prefs.View())) must.Do(pm.SetPrefs(prefs.View(), ""))
} }
login := func(pm *profileManager, p *persist.Persist) { login := func(pm *profileManager, p *persist.Persist) {
pm.NewProfile() pm.NewProfile()
@ -379,7 +379,7 @@ func TestProfileManagement(t *testing.T) {
}, },
NodeID: nid, NodeID: nid,
} }
if err := pm.SetPrefs(p.View()); err != nil { if err := pm.SetPrefs(p.View(), ""); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return p.View() return p.View()
@ -506,7 +506,7 @@ func TestProfileManagementWindows(t *testing.T) {
}, },
NodeID: tailcfg.StableNodeID(strconv.Itoa(int(id))), NodeID: tailcfg.StableNodeID(strconv.Itoa(int(id))),
} }
if err := pm.SetPrefs(p.View()); err != nil { if err := pm.SetPrefs(p.View(), ""); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return p.View() return p.View()

@ -923,7 +923,7 @@ func TestEditPrefsHasNoKeys(t *testing.T) {
LegacyFrontendPrivateMachineKey: key.NewMachine(), LegacyFrontendPrivateMachineKey: key.NewMachine(),
}, },
}).View()) }).View(), "")
if p := b.pm.CurrentPrefs().Persist(); !p.Valid() || p.PrivateNodeKey().IsZero() { if p := b.pm.CurrentPrefs().Persist(); !p.Valid() || p.PrivateNodeKey().IsZero() {
t.Fatalf("PrivateNodeKey not set") t.Fatalf("PrivateNodeKey not set")
} }

@ -755,6 +755,14 @@ type LoginProfile struct {
// It is filled in from the UserProfile.LoginName field. // It is filled in from the UserProfile.LoginName field.
Name string Name string
// TailnetMagicDNSName is filled with the MagicDNS suffix for this
// profile's node (even if MagicDNS isn't necessarily in use).
// It will neither start nor end with a period.
//
// TailnetMagicDNSName is only filled from 2023-09-09 forward,
// and will only get backfilled when a profile is the current profile.
TailnetMagicDNSName string
// Key is the StateKey under which the profile is stored. // Key is the StateKey under which the profile is stored.
// It is assigned once at profile creation time and never changes. // It is assigned once at profile creation time and never changes.
Key StateKey Key StateKey

@ -171,6 +171,9 @@ func MagicDNSSuffixOfNodeName(nodeName string) string {
// //
// It will neither start nor end with a period. // It will neither start nor end with a period.
func (nm *NetworkMap) MagicDNSSuffix() string { func (nm *NetworkMap) MagicDNSSuffix() string {
if nm == nil {
return ""
}
return MagicDNSSuffixOfNodeName(nm.Name) return MagicDNSSuffixOfNodeName(nm.Name)
} }

Loading…
Cancel
Save