Move from LinkedPath to Fingerprints and PresentationPath

This commit is contained in:
Daniel
2022-10-03 22:10:43 +02:00
parent e1e6a40498
commit 59f776ce2f
9 changed files with 699 additions and 253 deletions

View File

@@ -1,9 +1,12 @@
package profile
import (
"errors"
"time"
"github.com/safing/portbase/database"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/status"
)
const (
@@ -74,6 +77,73 @@ If you think you might have messed up the settings of the System DNS Client, jus
PortmasterNotifierProfileDescription = `This is the Portmaster UI Tray Notifier.`
)
// GetSpecialProfile fetches a special profile. This function ensures that the loaded profile
// is shared among all callers. Always provide all available data points.
func GetSpecialProfile(id string, path string) ( //nolint:gocognit
profile *Profile,
err error,
) {
// Check if we have an ID.
if id == "" {
return nil, errors.New("cannot get special profile without ID")
}
scopedID := makeScopedID(SourceLocal, id)
// Globally lock getting a profile.
// This does not happen too often, and it ensures we really have integrity
// and no race conditions.
getProfileLock.Lock()
defer getProfileLock.Unlock()
// Check if there already is an active profile.
var previousVersion *Profile
profile = getActiveProfile(scopedID)
if profile != nil {
// Mark active and return if not outdated.
if profile.outdated.IsNotSet() {
profile.MarkStillActive()
return profile, nil
}
// If outdated, get from database.
previousVersion = profile
}
// Get special profile from DB and check if it needs a reset.
profile, err = getProfile(scopedID)
if err != nil {
if !errors.Is(err, database.ErrNotFound) {
log.Warningf("profile: failed to get special profile %s: %s", id, err)
}
profile = createSpecialProfile(id, path)
} else if specialProfileNeedsReset(profile) {
log.Debugf("profile: resetting special profile %s", id)
profile = createSpecialProfile(id, path)
}
if profile == nil {
return nil, errors.New("given ID is not a special profile ID")
}
// Prepare profile for first use.
// If we are refetching, assign the layered profile from the previous version.
// The internal references will be updated when the layered profile checks for updates.
if previousVersion != nil && previousVersion.layeredProfile != nil {
profile.layeredProfile = previousVersion.layeredProfile
}
// Profiles must have a layered profile, create a new one if it
// does not yet exist.
if profile.layeredProfile == nil {
profile.layeredProfile = NewLayeredProfile(profile)
}
// Add the profile to the currently active profiles.
addActiveProfile(profile)
return profile, nil
}
func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (ok, changed bool) {
// Get new profile name and check if profile is applicable to special handling.
var newProfileName, newDescription string
@@ -115,35 +185,45 @@ func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (ok, chan
changed = true
}
// Update LinkedPath to new value.
if profile.LinkedPath != binaryPath {
profile.LinkedPath = binaryPath
// Update PresentationPath to new value.
if profile.PresentationPath != binaryPath {
profile.PresentationPath = binaryPath
changed = true
}
return true, changed
}
func getSpecialProfile(profileID, linkedPath string) *Profile {
func createSpecialProfile(profileID string, path string) *Profile {
switch profileID {
case UnidentifiedProfileID:
return New(SourceLocal, UnidentifiedProfileID, linkedPath, nil)
return New(&Profile{
ID: UnidentifiedProfileID,
Source: SourceLocal,
PresentationPath: path,
})
case SystemProfileID:
return New(SourceLocal, SystemProfileID, linkedPath, nil)
return New(&Profile{
ID: SystemProfileID,
Source: SourceLocal,
PresentationPath: path,
})
case SystemResolverProfileID:
systemResolverProfile := New(
SourceLocal,
SystemResolverProfileID,
linkedPath,
map[string]interface{}{
return New(&Profile{
ID: SystemResolverProfileID,
Source: SourceLocal,
PresentationPath: path,
Config: map[string]interface{}{
// Explicitly setting the default action to "permit" will improve the
// user experience for people who set the global default to "prompt".
// Resolved domain from the system resolver are checked again when
// attributed to a connection of a regular process. Otherwise, users
// would see two connection prompts for the same domain.
CfgOptionDefaultActionKey: "permit",
// Explicitly allow incoming connections.
CfgOptionBlockInboundKey: status.SecurityLevelOff,
// Explicitly allow localhost and answers to multicast protocols that
// are commonly used by system resolvers.
// TODO: When the Portmaster gains the ability to attribute multicast
@@ -154,6 +234,7 @@ func getSpecialProfile(profileID, linkedPath string) *Profile {
"+ LAN UDP/5353", // Allow inbound mDNS requests and multicast replies.
"+ LAN UDP/5355", // Allow inbound LLMNR requests and multicast replies.
"+ LAN UDP/1900", // Allow inbound SSDP requests and multicast replies.
"- *", // Deny everything else.
},
// Explicitly disable all filter lists, as these will be checked later
// with the attributed connection. As this is the system resolver, this
@@ -161,44 +242,44 @@ func getSpecialProfile(profileID, linkedPath string) *Profile {
// the system resolver is used. Users who want to
CfgOptionFilterListsKey: []string{},
},
)
return systemResolverProfile
})
case PortmasterProfileID:
profile := New(SourceLocal, PortmasterProfileID, linkedPath, nil)
profile.Internal = true
return profile
return New(&Profile{
ID: PortmasterProfileID,
Source: SourceLocal,
PresentationPath: path,
Internal: true,
})
case PortmasterAppProfileID:
profile := New(
SourceLocal,
PortmasterAppProfileID,
linkedPath,
map[string]interface{}{
return New(&Profile{
ID: PortmasterAppProfileID,
Source: SourceLocal,
PresentationPath: path,
Config: map[string]interface{}{
CfgOptionDefaultActionKey: "block",
CfgOptionEndpointsKey: []string{
"+ Localhost",
"+ .safing.io",
},
},
)
profile.Internal = true
return profile
Internal: true,
})
case PortmasterNotifierProfileID:
profile := New(
SourceLocal,
PortmasterNotifierProfileID,
linkedPath,
map[string]interface{}{
return New(&Profile{
ID: PortmasterNotifierProfileID,
Source: SourceLocal,
PresentationPath: path,
Config: map[string]interface{}{
CfgOptionDefaultActionKey: "block",
CfgOptionEndpointsKey: []string{
"+ Localhost",
},
},
)
profile.Internal = true
return profile
Internal: true,
})
default:
return nil