feat(WIP): add pause and resume functionality for Portmaster/SPN

https://github.com/safing/portmaster/issues/2050
This commit is contained in:
Alexandr Stelnykovych
2025-10-24 18:15:27 +03:00
parent 287c498bf1
commit c063bda700
9 changed files with 404 additions and 10 deletions

View File

@@ -34,6 +34,11 @@ func startInterception(packets chan packet.Packet) error {
// stop starts the interception.
func stopInterception() error {
// TODO: stop ebpf workers gracefully
// E.g.:
// module.mgr.Cancel()
// <-m.Done()
return StopNfqueueInterception()
}

View File

@@ -12,9 +12,7 @@ import (
var (
packetMetricsDestination string
metrics = &packetMetrics{
done: make(chan struct{}),
}
metrics = &packetMetrics{}
)
func init() {
@@ -40,6 +38,10 @@ func (pm *packetMetrics) record(tp *tracedPacket, verdict string) {
pm.l.Lock()
defer pm.l.Unlock()
if pm.done == nil {
return
}
pm.records = append(pm.records, &performanceRecord{
start: start,
duration: duration,
@@ -48,6 +50,18 @@ func (pm *packetMetrics) record(tp *tracedPacket, verdict string) {
}(tp.start.UnixNano(), time.Since(tp.start))
}
func (pm *packetMetrics) stop() {
pm.l.Lock()
defer pm.l.Unlock()
if pm.done == nil {
return
}
close(pm.done)
pm.done = nil
}
func (pm *packetMetrics) writeMetrics() {
if packetMetricsDestination == "" {
return
@@ -62,9 +76,14 @@ func (pm *packetMetrics) writeMetrics() {
_ = f.Close()
}()
pm.l.Lock()
pm.done = make(chan struct{})
done := pm.done
pm.l.Unlock()
for {
select {
case <-pm.done:
case <-done:
return
case <-time.After(time.Second * 5):
}

View File

@@ -40,6 +40,7 @@ var (
BandwidthUpdates = make(chan *packet.BandwidthUpdate, 1000)
disableInterception bool
isStarted atomic.Bool
)
func init() {
@@ -53,6 +54,10 @@ func start() error {
return nil
}
if !isStarted.CompareAndSwap(false, true) {
return nil // already running
}
inputPackets := Packets
if packetMetricsDestination != "" {
go metrics.writeMetrics()
@@ -64,7 +69,16 @@ func start() error {
}()
}
return startInterception(inputPackets)
err := startInterception(inputPackets)
if err != nil {
log.Errorf("interception: failed to start module: %q", err)
log.Debug("interception: cleaning up after failed start...")
if e := stopInterception(); e != nil {
log.Debugf("interception: error cleaning up after failed start: %q", e.Error())
}
isStarted.Store(false)
}
return err
}
// Stop starts the interception.
@@ -73,7 +87,11 @@ func stop() error {
return nil
}
close(metrics.done)
if !isStarted.CompareAndSwap(true, false) {
return nil // not running
}
metrics.stop()
if err := stopInterception(); err != nil {
log.Errorf("failed to stop interception module: %s", err)
}