Merge pull request #184 from safing/fix/profile-runtime

Fix layered profiles not readable via the API
This commit is contained in:
Daniel
2020-11-02 10:24:47 +01:00
committed by GitHub
4 changed files with 95 additions and 36 deletions

View File

@@ -16,18 +16,26 @@ var (
activeProfilesLock sync.RWMutex
)
// getActiveProfile returns a cached copy of an active profile and nil if it isn't found.
// getActiveProfile returns a cached copy of an active profile and
// nil if it isn't found.
func getActiveProfile(scopedID string) *Profile {
activeProfilesLock.RLock()
defer activeProfilesLock.RUnlock()
activeProfile, ok := activeProfiles[scopedID]
if ok {
activeProfile.MarkStillActive()
return activeProfile
return activeProfiles[scopedID]
}
// getAllActiveProfiles returns a slice of active profiles.
func getAllActiveProfiles() []*Profile {
activeProfilesLock.RLock()
defer activeProfilesLock.RUnlock()
result := make([]*Profile, 0, len(activeProfiles))
for _, p := range activeProfiles {
result = append(result, p)
}
return nil
return result
}
// findActiveProfile searched for an active local profile using the linked path.

View File

@@ -51,6 +51,8 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit
// Check if there already is an active and not outdated profile.
profile = getActiveProfile(scopedID)
if profile != nil {
profile.MarkStillActive()
if profile.outdated.IsSet() {
previousVersion = profile
} else {

View File

@@ -5,37 +5,70 @@ import (
"strings"
"github.com/safing/portbase/database/record"
"github.com/safing/portbase/log"
"github.com/safing/portbase/runtime"
)
const (
revisionProviderPrefix = "runtime:layeredProfile/"
revisionProviderPrefix = "layeredProfile/"
)
var (
errProfileNotActive = errors.New("profile not active")
errNoLayeredProfile = errors.New("profile has no layered profile")
errProfileNotActive = errors.New("profile not active")
errNoLayeredProfile = errors.New("profile has no layered profile")
pushLayeredProfile runtime.PushFunc = func(...record.Record) {}
)
func registerRevisionProvider() error {
_, err := runtime.DefaultRegistry.Register(
push, err := runtime.Register(
revisionProviderPrefix,
runtime.SimpleValueGetterFunc(getRevision),
runtime.SimpleValueGetterFunc(getRevisions),
)
return err
}
func getRevision(key string) ([]record.Record, error) {
key = strings.TrimPrefix(key, revisionProviderPrefix)
// Get active profile.
profile := getActiveProfile(key)
if profile == nil {
return nil, errProfileNotActive
if err != nil {
return err
}
pushLayeredProfile = push
return nil
}
func getRevisions(key string) ([]record.Record, error) {
key = strings.TrimPrefix(key, revisionProviderPrefix)
var profiles []*Profile
if key == "" {
profiles = getAllActiveProfiles()
} else {
// Get active profile.
profile := getActiveProfile(key)
if profile == nil {
return nil, errProfileNotActive
}
}
records := make([]record.Record, 0, len(profiles))
for _, p := range profiles {
layered, err := getProfileRevision(p)
if err != nil {
log.Warningf("failed to get layered profile for %s: %s", p.ID, err)
continue
}
records = append(records, layered)
}
return records, nil
}
// getProfileRevision returns the layered profile for p.
// It also updates the layered profile if required.
func getProfileRevision(p *Profile) (*LayeredProfile, error) {
// Get layered profile.
layeredProfile := profile.LayeredProfile()
layeredProfile := p.LayeredProfile()
if layeredProfile == nil {
return nil, errNoLayeredProfile
}
@@ -45,5 +78,5 @@ func getRevision(key string) ([]record.Record, error) {
layeredProfile.Update()
}
return []record.Record{layeredProfile}, nil
return layeredProfile, nil
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/safing/portbase/database/record"
"github.com/safing/portbase/log"
"github.com/safing/portbase/runtime"
"github.com/safing/portmaster/status"
@@ -31,19 +32,24 @@ type LayeredProfile struct {
// These functions give layered access to configuration options and require
// the layered profile to be read locked.
DisableAutoPermit config.BoolOption
BlockScopeLocal config.BoolOption
BlockScopeLAN config.BoolOption
BlockScopeInternet config.BoolOption
BlockP2P config.BoolOption
BlockInbound config.BoolOption
RemoveOutOfScopeDNS config.BoolOption
RemoveBlockedDNS config.BoolOption
FilterSubDomains config.BoolOption
FilterCNAMEs config.BoolOption
PreventBypassing config.BoolOption
DomainHeuristics config.BoolOption
UseSPN config.BoolOption
// TODO(ppacher): we need JSON tags here so the layeredProfile can be exposed
// via the API. If we ever switch away from JSON to something else supported
// by DSD this WILL BREAK!
DisableAutoPermit config.BoolOption `json:"-"`
BlockScopeLocal config.BoolOption `json:"-"`
BlockScopeLAN config.BoolOption `json:"-"`
BlockScopeInternet config.BoolOption `json:"-"`
BlockP2P config.BoolOption `json:"-"`
BlockInbound config.BoolOption `json:"-"`
RemoveOutOfScopeDNS config.BoolOption `json:"-"`
RemoveBlockedDNS config.BoolOption `json:"-"`
FilterSubDomains config.BoolOption `json:"-"`
FilterCNAMEs config.BoolOption `json:"-"`
PreventBypassing config.BoolOption `json:"-"`
DomainHeuristics config.BoolOption `json:"-"`
UseSPN config.BoolOption `json:"-"`
}
// NewLayeredProfile returns a new layered profile based on the given local profile.
@@ -118,7 +124,15 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile {
new.updateCaches()
new.SetKey(revisionProviderPrefix + localProfile.ID)
new.CreateMeta()
new.SetKey(runtime.DefaultRegistry.DatabaseName() + ":" + revisionProviderPrefix + localProfile.ID)
// Inform database subscribers about the new layered profile.
new.Lock()
defer new.Unlock()
pushLayeredProfile(new)
return new
}
@@ -223,6 +237,8 @@ func (lp *LayeredProfile) Update() (revisionCounter uint64) {
// bump revision counter
lp.RevisionCounter++
pushLayeredProfile(lp)
}
return lp.RevisionCounter