mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
184 lines
4.4 KiB
Go
184 lines
4.4 KiB
Go
package compat
|
|
|
|
import (
|
|
"errors"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/tevino/abool"
|
|
|
|
"github.com/safing/portmaster/base/log"
|
|
"github.com/safing/portmaster/service/mgr"
|
|
"github.com/safing/portmaster/service/netenv"
|
|
"github.com/safing/portmaster/service/resolver"
|
|
)
|
|
|
|
// Compat is the compatibility check module.
|
|
type Compat struct {
|
|
mgr *mgr.Manager
|
|
instance instance
|
|
|
|
selfcheckWorkerMgr *mgr.WorkerMgr
|
|
cleanNotifyThresholdWorkerMgr *mgr.WorkerMgr
|
|
|
|
states *mgr.StateMgr
|
|
}
|
|
|
|
// Manager returns the module manager.
|
|
func (u *Compat) Manager() *mgr.Manager {
|
|
return u.mgr
|
|
}
|
|
|
|
// States returns the module state manager.
|
|
func (u *Compat) States() *mgr.StateMgr {
|
|
return u.states
|
|
}
|
|
|
|
// Start starts the module.
|
|
func (u *Compat) Start() error {
|
|
return start()
|
|
}
|
|
|
|
// Stop stops the module.
|
|
func (u *Compat) Stop() error {
|
|
return stop()
|
|
}
|
|
|
|
var (
|
|
selfcheckTaskRetryAfter = 15 * time.Second
|
|
|
|
// selfCheckIsFailing holds whether or not the self-check is currently
|
|
// failing. This helps other failure systems to not make noise when there is
|
|
// an underlying failure.
|
|
selfCheckIsFailing = abool.New()
|
|
|
|
// selfcheckFails counts how often the self check failed successively.
|
|
// selfcheckFails is not locked as it is only accessed by the self-check task.
|
|
selfcheckFails int
|
|
|
|
// selfcheckNetworkChangedFlag is used to track changed to the network for
|
|
// the self-check.
|
|
selfcheckNetworkChangedFlag = netenv.GetNetworkChangedFlag()
|
|
)
|
|
|
|
// selfcheckFailThreshold holds the threshold of how many times the selfcheck
|
|
// must fail before it is reported.
|
|
const selfcheckFailThreshold = 10
|
|
|
|
func init() {
|
|
// Workaround resolver integration.
|
|
// See resolver/compat.go for details.
|
|
resolver.CompatDNSCheckInternalDomainScope = DNSCheckInternalDomainScope
|
|
resolver.CompatSelfCheckIsFailing = SelfCheckIsFailing
|
|
resolver.CompatSubmitDNSCheckDomain = SubmitDNSCheckDomain
|
|
}
|
|
|
|
func prep() error {
|
|
return registerAPIEndpoints()
|
|
}
|
|
|
|
func start() error {
|
|
startNotify()
|
|
|
|
selfcheckNetworkChangedFlag.Refresh()
|
|
module.selfcheckWorkerMgr.Repeat(5 * time.Minute).Delay(selfcheckTaskRetryAfter)
|
|
module.cleanNotifyThresholdWorkerMgr.Repeat(1 * time.Hour)
|
|
|
|
module.instance.NetEnv().EventNetworkChange.AddCallback("trigger compat self-check", func(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {
|
|
module.selfcheckWorkerMgr.Delay(selfcheckTaskRetryAfter)
|
|
return false, nil
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func stop() error {
|
|
// selfcheckTask.Cancel()
|
|
// selfcheckTask = nil
|
|
|
|
return nil
|
|
}
|
|
|
|
func selfcheckTaskFunc(wc *mgr.WorkerCtx) error {
|
|
// Create tracing logger.
|
|
ctx, tracer := log.AddTracer(wc.Ctx())
|
|
defer tracer.Submit()
|
|
tracer.Tracef("compat: running self-check")
|
|
|
|
// Run selfcheck and return if successful.
|
|
issue, err := selfcheck(ctx)
|
|
switch {
|
|
case err == nil:
|
|
// Successful.
|
|
tracer.Debugf("compat: self-check successful")
|
|
case errors.Is(err, errSelfcheckSkipped):
|
|
// Skipped.
|
|
tracer.Debugf("compat: %s", err)
|
|
case issue == nil:
|
|
// Internal error.
|
|
tracer.Warningf("compat: %s", err)
|
|
case selfcheckNetworkChangedFlag.IsSet():
|
|
// The network changed, ignore the issue.
|
|
default:
|
|
// The self-check failed.
|
|
|
|
// Set state and increase counter.
|
|
selfCheckIsFailing.Set()
|
|
selfcheckFails++
|
|
|
|
// Log and notify.
|
|
tracer.Errorf("compat: %s", err)
|
|
if selfcheckFails >= selfcheckFailThreshold {
|
|
issue.notify(err)
|
|
}
|
|
|
|
// Retry quicker when failed.
|
|
module.selfcheckWorkerMgr.Delay(selfcheckTaskRetryAfter)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Reset self-check state.
|
|
selfcheckNetworkChangedFlag.Refresh()
|
|
selfCheckIsFailing.UnSet()
|
|
selfcheckFails = 0
|
|
resetSystemIssue()
|
|
|
|
return nil
|
|
}
|
|
|
|
// SelfCheckIsFailing returns whether the self check is currently failing.
|
|
// This returns true after the first check fails, and does not wait for the
|
|
// failing threshold to be met.
|
|
func SelfCheckIsFailing() bool {
|
|
return selfCheckIsFailing.IsSet()
|
|
}
|
|
|
|
var (
|
|
module *Compat
|
|
shimLoaded atomic.Bool
|
|
)
|
|
|
|
// New returns a new Compat module.
|
|
func New(instance instance) (*Compat, error) {
|
|
if !shimLoaded.CompareAndSwap(false, true) {
|
|
return nil, errors.New("only one instance allowed")
|
|
}
|
|
m := mgr.New("Compat")
|
|
module = &Compat{
|
|
mgr: m,
|
|
instance: instance,
|
|
|
|
selfcheckWorkerMgr: m.NewWorkerMgr("compatibility self-check", selfcheckTaskFunc, nil),
|
|
cleanNotifyThresholdWorkerMgr: m.NewWorkerMgr("clean notify thresholds", cleanNotifyThreshold, nil),
|
|
|
|
states: mgr.NewStateMgr(m),
|
|
}
|
|
if err := prep(); err != nil {
|
|
return nil, err
|
|
}
|
|
return module, nil
|
|
}
|
|
|
|
type instance interface {
|
|
NetEnv() *netenv.NetEnv
|
|
}
|