From 888b33918a8946bf7e92d2419b4550536edf77b4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 15 Feb 2022 14:35:28 +0100 Subject: [PATCH] Fix deleting profiles --- firewall/prompt.go | 2 +- process/find.go | 2 +- process/profile.go | 2 +- profile/database.go | 22 +++++++++------ profile/get.go | 58 +++++++++++++++++++++++++------------- profile/profile-layered.go | 4 +-- profile/profile.go | 25 ++++++++++++++++ profile/special.go | 6 ++++ 8 files changed, 89 insertions(+), 32 deletions(-) diff --git a/firewall/prompt.go b/firewall/prompt.go index 5b3b07a4..0356516a 100644 --- a/firewall/prompt.go +++ b/firewall/prompt.go @@ -259,7 +259,7 @@ func saveResponse(p *profile.Profile, entity *intel.Entity, promptResponse strin // Update the profile if necessary. if p.IsOutdated() { var err error - p, err = profile.GetProfile(p.Source, p.ID, p.LinkedPath) + p, err = profile.GetProfile(p.Source, p.ID, p.LinkedPath, false) if err != nil { return err } diff --git a/process/find.go b/process/find.go index 5ce75574..832c17a7 100644 --- a/process/find.go +++ b/process/find.go @@ -64,7 +64,7 @@ func GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err } // Get the (linked) local profile. - networkHostProfile, err := profile.GetProfile(profile.SourceNetwork, remoteIP.String(), "") + networkHostProfile, err := profile.GetProfile(profile.SourceNetwork, remoteIP.String(), "", false) if err != nil { return nil, err } diff --git a/process/profile.go b/process/profile.go index 4a3a3865..d440756b 100644 --- a/process/profile.go +++ b/process/profile.go @@ -81,7 +81,7 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) { } // Get the (linked) local profile. - localProfile, err := profile.GetProfile(profile.SourceLocal, profileID, p.Path) + localProfile, err := profile.GetProfile(profile.SourceLocal, profileID, p.Path, false) if err != nil { return false, err } diff --git a/profile/database.go b/profile/database.go index 3ddd9aea..709aaa5a 100644 --- a/profile/database.go +++ b/profile/database.go @@ -61,25 +61,31 @@ func startProfileUpdateChecker() error { // Get active profile. activeProfile := getActiveProfile(strings.TrimPrefix(r.Key(), profilesDBPath)) if activeProfile == nil { + // Don't do any additional actions if the profile is not active. continue profileFeed } - // If the record is being deleted, but there is an active profile, + // If the record is being deleted, reset the profile. // create an empty profile instead. if r.Meta().IsDeleted() { - newProfile := New( + newProfile, err := GetProfile( activeProfile.Source, activeProfile.ID, activeProfile.LinkedPath, - nil, + true, ) - // Copy some metadata from the old profile. - newProfile.Name = activeProfile.Name - // Save the new profile. - err := newProfile.Save() if err != nil { - log.Errorf("profile: failed to save new profile for profile reset: %s", err) + log.Errorf("profile: failed to create new profile after reset: %s", err) + } else { + // Copy metadata from the old profile. + newProfile.copyMetadataFrom(activeProfile) + // Save the new profile. + err := newProfile.Save() + if err != nil { + log.Errorf("profile: failed to save new profile after reset: %s", err) + } } + // Set to outdated, so it is loaded in the layered profiles. activeProfile.outdated.Set() } diff --git a/profile/get.go b/profile/get.go index de4c25e8..f2cb39b2 100644 --- a/profile/get.go +++ b/profile/get.go @@ -17,7 +17,7 @@ var getProfileLock sync.Mutex // linkedPath parameters whenever available. The linkedPath is used as the key // for locking concurrent requests, so it must be supplied if available. // If linkedPath is not supplied, source and id make up the key instead. -func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit +func GetProfile(source profileSource, id, linkedPath string, reset bool) ( //nolint:gocognit profile *Profile, err error, ) { @@ -40,28 +40,23 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit if profile != nil { profile.MarkStillActive() - if profile.outdated.IsSet() { + if profile.outdated.IsSet() || reset { previousVersion = profile } else { return profile, nil } } + // Get from database. - profile, err = getProfile(scopedID) - - // Check if the request is for a special profile that may need a reset. - if err == nil && specialProfileNeedsReset(profile) { - // Trigger creation of special profile. - err = database.ErrNotFound - } - - // If we cannot find a profile, check if the request is for a special - // profile we can create. - if errors.Is(err, database.ErrNotFound) { - profile = getSpecialProfile(id, linkedPath) - if profile != nil { - err = nil + if !reset { + profile, err = getProfile(scopedID) + // Check if the profile is special and needs a reset. + if err == nil && specialProfileNeedsReset(profile) { + profile = getSpecialProfile(id, linkedPath) } + } else { + // Simulate missing profile to create new one. + err = database.ErrNotFound } case linkedPath != "": @@ -70,23 +65,48 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit // the linked path. profile = findActiveProfile(linkedPath) if profile != nil { - if profile.outdated.IsSet() { + if profile.outdated.IsSet() || reset { previousVersion = profile } else { return profile, nil } } + // Get from database. - profile, err = findProfile(linkedPath) + if !reset { + profile, err = findProfile(linkedPath) + // Check if the profile is special and needs a reset. + if err == nil && specialProfileNeedsReset(profile) { + profile = getSpecialProfile(id, linkedPath) + } + } else { + // Simulate missing profile to create new one. + err = database.ErrNotFound + } default: return nil, errors.New("cannot fetch profile without ID or path") } + + // Create new profile if none was found. + if errors.Is(err, database.ErrNotFound) { + err = nil + + // Check if there is a special profile for this ID. + profile = getSpecialProfile(id, linkedPath) + + // If not, create a standard profile. + if profile == nil { + profile = New(SourceLocal, id, linkedPath, nil) + } + } + + // If there was a non-recoverable error, return here. if err != nil { return nil, err } - // Process profiles coming directly from the database. + // Process profiles are coming directly from the database or are new. // As we don't use any caching, these will be new objects. // Add a layeredProfile to local and network profiles. diff --git a/profile/profile-layered.go b/profile/profile-layered.go index b67e1bca..ffb77bd2 100644 --- a/profile/profile-layered.go +++ b/profile/profile-layered.go @@ -239,9 +239,9 @@ func (lp *LayeredProfile) Update() (revisionCounter uint64) { if layer.outdated.IsSet() { changed = true // update layer - newLayer, err := GetProfile(layer.Source, layer.ID, layer.LinkedPath) + newLayer, err := GetProfile(layer.Source, layer.ID, layer.LinkedPath, false) if err != nil { - log.Errorf("profiles: failed to update profile %s", layer.ScopedID()) + log.Errorf("profiles: failed to update profile %s: %s", layer.ScopedID(), err) } else { lp.layers[i] = newLayer } diff --git a/profile/profile.go b/profile/profile.go index f23dafa2..dd7ae25f 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -445,6 +445,31 @@ func (profile *Profile) UpdateMetadata(binaryPath string) (changed bool) { return changed } +func (profile *Profile) copyMetadataFrom(otherProfile *Profile) (changed bool) { + if profile.Name != otherProfile.Name { + profile.Name = otherProfile.Name + changed = true + } + if profile.Description != otherProfile.Description { + profile.Description = otherProfile.Description + changed = true + } + if profile.Homepage != otherProfile.Homepage { + profile.Homepage = otherProfile.Homepage + changed = true + } + if profile.Icon != otherProfile.Icon { + profile.Icon = otherProfile.Icon + changed = true + } + if profile.IconType != otherProfile.IconType { + profile.IconType = otherProfile.IconType + changed = true + } + + return +} + // updateMetadataFromSystem updates the profile metadata with data from the // operating system and saves it afterwards. func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error { diff --git a/profile/special.go b/profile/special.go index cd04cc0d..13e9b5a9 100644 --- a/profile/special.go +++ b/profile/special.go @@ -36,6 +36,8 @@ In order to respect the app settings of the actual application, DNS requests fro - Outgoing Rules (without global rules) - Block Bypassing - Filter Lists + +If you think you might have messed up the settings of the System DNS Client, just delete the profile below to reset it to the defaults. ` // PortmasterProfileID is the profile ID used for the Portmaster Core itself. @@ -193,6 +195,10 @@ func getSpecialProfile(profileID, linkedPath string) *Profile { // check if the special profile has not been changed by the user and if not, // check if the profile is outdated and can be upgraded. func specialProfileNeedsReset(profile *Profile) bool { + if profile == nil { + return false + } + switch { case profile.Source != SourceLocal: // Special profiles live in the local scope only.