mirror of
https://github.com/safing/portmaster
synced 2025-09-02 10:39:22 +00:00
Merge pull request #263 from safing/fix/bulk-prompt-responses
Fix bulk profile updates via prompts
This commit is contained in:
commit
46eb588182
1 changed files with 51 additions and 8 deletions
|
@ -50,6 +50,10 @@ type promptProfile struct {
|
||||||
func prompt(ctx context.Context, conn *network.Connection, pkt packet.Packet) {
|
func prompt(ctx context.Context, conn *network.Connection, pkt packet.Packet) {
|
||||||
// Create notification.
|
// Create notification.
|
||||||
n := createPrompt(ctx, conn, pkt)
|
n := createPrompt(ctx, conn, pkt)
|
||||||
|
if n == nil {
|
||||||
|
// createPrompt returns nil when no further action should be taken.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get decision timeout and make sure it does not exceed the ask timeout.
|
// Get decision timeout and make sure it does not exceed the ask timeout.
|
||||||
timeout := decisionTimeout
|
timeout := decisionTimeout
|
||||||
|
@ -85,12 +89,12 @@ func createPrompt(ctx context.Context, conn *network.Connection, pkt packet.Pack
|
||||||
expires := time.Now().Add(time.Duration(askTimeout()) * time.Second).Unix()
|
expires := time.Now().Add(time.Duration(askTimeout()) * time.Second).Unix()
|
||||||
|
|
||||||
// Get local profile.
|
// Get local profile.
|
||||||
profile := conn.Process().Profile()
|
layeredProfile := conn.Process().Profile()
|
||||||
if profile == nil {
|
if layeredProfile == nil {
|
||||||
log.Tracer(ctx).Warningf("filter: tried creating prompt for connection without profile")
|
log.Tracer(ctx).Warningf("filter: tried creating prompt for connection without profile")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
localProfile := profile.LocalProfile()
|
localProfile := layeredProfile.LocalProfile()
|
||||||
if localProfile == nil {
|
if localProfile == nil {
|
||||||
log.Tracer(ctx).Warningf("filter: tried creating prompt for connection without local profile")
|
log.Tracer(ctx).Warningf("filter: tried creating prompt for connection without local profile")
|
||||||
return
|
return
|
||||||
|
@ -125,9 +129,38 @@ func createPrompt(ctx context.Context, conn *network.Connection, pkt packet.Pack
|
||||||
|
|
||||||
// If there already is a notification, just update the expiry.
|
// If there already is a notification, just update the expiry.
|
||||||
if n != nil {
|
if n != nil {
|
||||||
n.Update(expires)
|
// Get notification state and action.
|
||||||
log.Tracer(ctx).Debugf("filter: updated existing prompt notification")
|
n.Lock()
|
||||||
return
|
state := n.State
|
||||||
|
action := n.SelectedActionID
|
||||||
|
n.Unlock()
|
||||||
|
|
||||||
|
// If the notification is still active, extend and return.
|
||||||
|
// This can can happen because user input (prompts changing the endpoint
|
||||||
|
// lists) can happen any time - also between checking the endpoint lists
|
||||||
|
// and now.
|
||||||
|
if state == notifications.Active {
|
||||||
|
n.Update(expires)
|
||||||
|
log.Tracer(ctx).Debugf("filter: updated existing prompt notification")
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// The notification is not active anymore, let's check if there is an
|
||||||
|
// action we can perform.
|
||||||
|
// If there already is an action defined, we won't be fast enough to
|
||||||
|
// receive the action with n.Response(), so we take direct action here.
|
||||||
|
if action != "" {
|
||||||
|
switch action {
|
||||||
|
case allowDomainAll, allowDomainDistinct, allowIP, allowServingIP:
|
||||||
|
conn.Accept("permitted via prompt", profile.CfgOptionEndpointsKey)
|
||||||
|
default: // deny
|
||||||
|
conn.Deny("blocked via prompt", profile.CfgOptionEndpointsKey)
|
||||||
|
}
|
||||||
|
return nil // Do not take further action.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue to create a new notification because the previous one is not
|
||||||
|
// active and not actionable.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference relevant data for save function
|
// Reference relevant data for save function
|
||||||
|
@ -209,11 +242,19 @@ func createPrompt(ctx context.Context, conn *network.Connection, pkt packet.Pack
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// promptSavingLock makes sure that only one prompt is saved at a time.
|
||||||
|
// Should prompts be persisted in bulk, the next save process might load an
|
||||||
|
// outdated profile and save it, losing config data.
|
||||||
|
var promptSavingLock sync.Mutex
|
||||||
|
|
||||||
func saveResponse(p *profile.Profile, entity *intel.Entity, promptResponse string) error {
|
func saveResponse(p *profile.Profile, entity *intel.Entity, promptResponse string) error {
|
||||||
if promptResponse == cancelPrompt {
|
if promptResponse == cancelPrompt {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
promptSavingLock.Lock()
|
||||||
|
defer promptSavingLock.Unlock()
|
||||||
|
|
||||||
// Update the profile if necessary.
|
// Update the profile if necessary.
|
||||||
if p.IsOutdated() {
|
if p.IsOutdated() {
|
||||||
var err error
|
var err error
|
||||||
|
@ -264,10 +305,12 @@ func saveResponse(p *profile.Profile, entity *intel.Entity, promptResponse strin
|
||||||
switch promptResponse {
|
switch promptResponse {
|
||||||
case allowServingIP, blockServingIP:
|
case allowServingIP, blockServingIP:
|
||||||
p.AddServiceEndpoint(ep.String())
|
p.AddServiceEndpoint(ep.String())
|
||||||
log.Infof("filter: added incoming rule to profile %s: %q", p, ep.String())
|
log.Infof("filter: added incoming rule to profile %s (LP Rev. %d): %q",
|
||||||
|
p, p.LayeredProfile().RevisionCnt(), ep.String())
|
||||||
default:
|
default:
|
||||||
p.AddEndpoint(ep.String())
|
p.AddEndpoint(ep.String())
|
||||||
log.Infof("filter: added outgoing rule to profile %s: %q", p, ep.String())
|
log.Infof("filter: added outgoing rule to profile %s (LP Rev. %d): %q",
|
||||||
|
p, p.LayeredProfile().RevisionCnt(), ep.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Add table
Reference in a new issue