Restructure modules (#1572)

* 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>
This commit is contained in:
Daniel Hååvi
2024-08-09 17:15:48 +02:00
committed by GitHub
parent 10a77498f4
commit 80664d1a27
647 changed files with 37690 additions and 3366 deletions

View File

@@ -8,10 +8,10 @@ import (
"strings"
"time"
"github.com/safing/portbase/api"
"github.com/safing/portbase/config"
"github.com/safing/portbase/database/query"
"github.com/safing/portbase/utils/debug"
"github.com/safing/portmaster/base/api"
"github.com/safing/portmaster/base/config"
"github.com/safing/portmaster/base/database/query"
"github.com/safing/portmaster/base/utils/debug"
"github.com/safing/portmaster/service/network/state"
"github.com/safing/portmaster/service/process"
"github.com/safing/portmaster/service/resolver"
@@ -23,7 +23,6 @@ func registerAPIEndpoints() error {
if err := api.RegisterEndpoint(api.Endpoint{
Path: "debug/network",
Read: api.PermitUser,
BelongsTo: module,
DataFunc: debugInfo,
Name: "Get Network Debug Information",
Description: "Returns network debugging information, similar to debug/core, but with connection data.",
@@ -52,9 +51,8 @@ func registerAPIEndpoints() error {
}
if err := api.RegisterEndpoint(api.Endpoint{
Path: "debug/network/state",
Read: api.PermitUser,
BelongsTo: module,
Path: "debug/network/state",
Read: api.PermitUser,
StructFunc: func(ar *api.Request) (i interface{}, err error) {
return state.GetInfo(), nil
},
@@ -79,8 +77,7 @@ func debugInfo(ar *api.Request) (data []byte, err error) {
di.AddVersionInfo()
di.AddPlatformInfo(ar.Context())
// Errors and unexpected logs.
di.AddLastReportedModuleError()
// Unexpected logs.
di.AddLastUnexpectedLogs()
// Network Connections.

View File

@@ -1,10 +1,10 @@
package network
import (
"context"
"time"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/network/packet"
"github.com/safing/portmaster/service/network/state"
"github.com/safing/portmaster/service/process"
@@ -31,21 +31,21 @@ const (
cleanerTickDuration = 5 * time.Second
)
func connectionCleaner(ctx context.Context) error {
ticker := module.NewSleepyTicker(cleanerTickDuration, 0)
func connectionCleaner(ctx *mgr.WorkerCtx) error {
module.connectionCleanerTicker = mgr.NewSleepyTicker(cleanerTickDuration, 0)
defer module.connectionCleanerTicker.Stop()
for {
select {
case <-ctx.Done():
ticker.Stop()
return nil
case <-ticker.Wait():
case <-module.connectionCleanerTicker.Wait():
// clean connections and processes
activePIDs := cleanConnections()
process.CleanProcessStorage(activePIDs)
// clean udp connection states
state.CleanUDPStates(ctx)
state.CleanUDPStates(ctx.Ctx())
}
}
}
@@ -53,7 +53,7 @@ func connectionCleaner(ctx context.Context) error {
func cleanConnections() (activePIDs map[int]struct{}) {
activePIDs = make(map[int]struct{})
_ = module.RunMicroTask("clean connections", 0, func(ctx context.Context) error {
_ = module.mgr.Do("clean connections", func(ctx *mgr.WorkerCtx) error {
now := time.Now().UTC()
nowUnix := now.Unix()
ignoreNewer := nowUnix - 2

View File

@@ -11,9 +11,9 @@ import (
"github.com/tevino/abool"
"github.com/safing/portbase/database/record"
"github.com/safing/portbase/log"
"github.com/safing/portbase/notifications"
"github.com/safing/portmaster/base/database/record"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/base/notifications"
"github.com/safing/portmaster/service/intel"
"github.com/safing/portmaster/service/netenv"
"github.com/safing/portmaster/service/network/netutils"
@@ -814,221 +814,6 @@ func (conn *Connection) delete() {
}
}
// SetFirewallHandler sets the firewall handler for this link, and starts a
// worker to handle the packets.
// The caller needs to hold a lock on the connection.
// Cannot be called with "nil" handler. Call StopFirewallHandler() instead.
func (conn *Connection) SetFirewallHandler(handler FirewallHandler) {
if handler == nil {
return
}
// Initialize packet queue, if needed.
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
if !conn.pktQueueActive {
conn.pktQueue = make(chan packet.Packet, 100)
conn.pktQueueActive = true
}
// Start packet handler worker when new handler is set.
if conn.firewallHandler == nil {
module.StartWorker("packet handler", conn.packetHandlerWorker)
}
// Set new handler.
conn.firewallHandler = handler
}
// UpdateFirewallHandler sets the firewall handler if it already set and the
// given handler is not nil.
// The caller needs to hold a lock on the connection.
func (conn *Connection) UpdateFirewallHandler(handler FirewallHandler) {
if handler != nil && conn.firewallHandler != nil {
conn.firewallHandler = handler
}
}
// StopFirewallHandler unsets the firewall handler and stops the handler worker.
// The caller needs to hold a lock on the connection.
func (conn *Connection) StopFirewallHandler() {
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
// Unset the firewall handler to revert to the default handler.
conn.firewallHandler = nil
// Signal the packet handler worker that it can stop.
if conn.pktQueueActive {
close(conn.pktQueue)
conn.pktQueueActive = false
}
// Unset the packet queue so that it can be freed.
conn.pktQueue = nil
}
// HandlePacket queues packet of Link for handling.
func (conn *Connection) HandlePacket(pkt packet.Packet) {
// Update last seen timestamp.
conn.lastSeen.Store(time.Now().Unix())
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
// execute handler or verdict
if conn.pktQueueActive {
select {
case conn.pktQueue <- pkt:
default:
log.Debugf(
"filter: dropping packet %s, as there is no space in the connection's handling queue",
pkt,
)
_ = pkt.Drop()
}
} else {
// Run default handler.
defaultFirewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
}
}
var infoOnlyPacketsActive = abool.New()
// packetHandlerWorker sequentially handles queued packets.
func (conn *Connection) packetHandlerWorker(ctx context.Context) error {
// Copy packet queue, so we can remove the reference from the connection
// when we stop the firewall handler.
var pktQueue chan packet.Packet
func() {
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
pktQueue = conn.pktQueue
}()
// pktSeq counts the seen packets.
var pktSeq int
for {
select {
case pkt := <-pktQueue:
if pkt == nil {
return nil
}
pktSeq++
// Attempt to optimize packet handling order by handling info-only packets first.
switch {
case pktSeq > 1:
// Order correction is only for first packet.
case pkt.InfoOnly():
// Correct order only if first packet is not info-only.
// We have observed a first packet that is info-only.
// Info-only packets seem to be active and working.
infoOnlyPacketsActive.Set()
case pkt.ExpectInfo():
// Packet itself tells us that we should expect an info-only packet.
fallthrough
case infoOnlyPacketsActive.IsSet() && pkt.IsOutbound():
// Info-only packets are active and the packet is outbound.
// The probability is high that we will also get an info-only packet for this connection.
// TODO: Do not do this for forwarded packets in the future.
// DEBUG:
// log.Debugf("filter: waiting for info only packet in order to pull forward: %s", pkt)
select {
case infoPkt := <-pktQueue:
if infoPkt != nil {
// DEBUG:
// log.Debugf("filter: packet #%d [pulled forward] info=%v PID=%d packet: %s", pktSeq, infoPkt.InfoOnly(), infoPkt.Info().PID, pkt)
packetHandlerHandleConn(ctx, conn, infoPkt)
pktSeq++
}
case <-time.After(1 * time.Millisecond):
}
}
// DEBUG:
// switch {
// case pkt.Info().Inbound:
// log.Debugf("filter: packet #%d info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// case pktSeq == 1 && !pkt.InfoOnly():
// log.Warningf("filter: packet #%d [should be info only!] info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// case pktSeq >= 2 && pkt.InfoOnly():
// log.Errorf("filter: packet #%d [should not be info only!] info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// default:
// log.Debugf("filter: packet #%d info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// }
packetHandlerHandleConn(ctx, conn, pkt)
case <-ctx.Done():
return nil
}
}
}
func packetHandlerHandleConn(ctx context.Context, conn *Connection, pkt packet.Packet) {
conn.Lock()
defer conn.Unlock()
// Check if we should use the default handler.
// The default handler is only for fully decided
// connections and just applying the verdict.
// There is no logging for these packets.
if conn.firewallHandler == nil {
// Run default handler.
defaultFirewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
return
}
// Create tracing context.
// Add context tracer and set context on packet.
traceCtx, tracer := log.AddTracer(ctx)
if tracer != nil {
// The trace is submitted in `network.Connection.packetHandler()`.
tracer.Tracef("filter: handling packet: %s", pkt)
}
pkt.SetCtx(traceCtx)
// Handle packet with set handler.
conn.firewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
// Log result and submit trace, when there are any changes.
if conn.saveWhenFinished {
switch {
case conn.DataIsComplete():
tracer.Infof("filter: connection %s %s: %s", conn, conn.VerdictVerb(), conn.Reason.Msg)
case conn.Verdict != VerdictUndecided:
tracer.Debugf("filter: connection %s fast-tracked", pkt)
default:
tracer.Debugf("filter: gathered data on connection %s", conn)
}
// Submit trace logs.
tracer.Submit()
}
// Push changes, if there are any.
if conn.saveWhenFinished {
conn.saveWhenFinished = false
conn.Save()
}
}
// GetActiveInspectors returns the list of active inspectors.
func (conn *Connection) GetActiveInspectors() []bool {
return conn.activeInspectors

View File

@@ -0,0 +1,227 @@
package network
import (
"context"
"time"
"github.com/tevino/abool"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/network/packet"
)
// SetFirewallHandler sets the firewall handler for this link, and starts a
// worker to handle the packets.
// The caller needs to hold a lock on the connection.
// Cannot be called with "nil" handler. Call StopFirewallHandler() instead.
func (conn *Connection) SetFirewallHandler(handler FirewallHandler) {
if handler == nil {
return
}
// Initialize packet queue, if needed.
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
if !conn.pktQueueActive {
conn.pktQueue = make(chan packet.Packet, 100)
conn.pktQueueActive = true
}
// Start packet handler worker when new handler is set.
if conn.firewallHandler == nil {
module.mgr.Go("packet handler", conn.packetHandlerWorker)
}
// Set new handler.
conn.firewallHandler = handler
}
// UpdateFirewallHandler sets the firewall handler if it already set and the
// given handler is not nil.
// The caller needs to hold a lock on the connection.
func (conn *Connection) UpdateFirewallHandler(handler FirewallHandler) {
if handler != nil && conn.firewallHandler != nil {
conn.firewallHandler = handler
}
}
// StopFirewallHandler unsets the firewall handler and stops the handler worker.
// The caller needs to hold a lock on the connection.
func (conn *Connection) StopFirewallHandler() {
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
// Unset the firewall handler to revert to the default handler.
conn.firewallHandler = nil
// Signal the packet handler worker that it can stop.
if conn.pktQueueActive {
close(conn.pktQueue)
conn.pktQueueActive = false
}
// Unset the packet queue so that it can be freed.
conn.pktQueue = nil
}
// HandlePacket queues packet of Link for handling.
func (conn *Connection) HandlePacket(pkt packet.Packet) {
// Update last seen timestamp.
conn.lastSeen.Store(time.Now().Unix())
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
// execute handler or verdict
if conn.pktQueueActive {
select {
case conn.pktQueue <- pkt:
default:
log.Debugf(
"filter: dropping packet %s, as there is no space in the connection's handling queue",
pkt,
)
_ = pkt.Drop()
}
} else {
// Run default handler.
defaultFirewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
}
}
var infoOnlyPacketsActive = abool.New()
// packetHandlerWorker sequentially handles queued packets.
func (conn *Connection) packetHandlerWorker(ctx *mgr.WorkerCtx) error {
// Copy packet queue, so we can remove the reference from the connection
// when we stop the firewall handler.
var pktQueue chan packet.Packet
func() {
conn.pktQueueLock.Lock()
defer conn.pktQueueLock.Unlock()
pktQueue = conn.pktQueue
}()
// pktSeq counts the seen packets.
var pktSeq int
for {
select {
case pkt := <-pktQueue:
if pkt == nil {
return nil
}
pktSeq++
// Attempt to optimize packet handling order by handling info-only packets first.
switch {
case pktSeq > 1:
// Order correction is only for first packet.
case pkt.InfoOnly():
// Correct order only if first packet is not info-only.
// We have observed a first packet that is info-only.
// Info-only packets seem to be active and working.
infoOnlyPacketsActive.Set()
case pkt.ExpectInfo():
// Packet itself tells us that we should expect an info-only packet.
fallthrough
case infoOnlyPacketsActive.IsSet() && pkt.IsOutbound():
// Info-only packets are active and the packet is outbound.
// The probability is high that we will also get an info-only packet for this connection.
// TODO: Do not do this for forwarded packets in the future.
// DEBUG:
// log.Debugf("filter: waiting for info only packet in order to pull forward: %s", pkt)
select {
case infoPkt := <-pktQueue:
if infoPkt != nil {
// DEBUG:
// log.Debugf("filter: packet #%d [pulled forward] info=%v PID=%d packet: %s", pktSeq, infoPkt.InfoOnly(), infoPkt.Info().PID, pkt)
packetHandlerHandleConn(ctx.Ctx(), conn, infoPkt)
pktSeq++
}
case <-time.After(1 * time.Millisecond):
}
}
// DEBUG:
// switch {
// case pkt.Info().Inbound:
// log.Debugf("filter: packet #%d info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// case pktSeq == 1 && !pkt.InfoOnly():
// log.Warningf("filter: packet #%d [should be info only!] info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// case pktSeq >= 2 && pkt.InfoOnly():
// log.Errorf("filter: packet #%d [should not be info only!] info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// default:
// log.Debugf("filter: packet #%d info=%v PID=%d packet: %s", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)
// }
packetHandlerHandleConn(ctx.Ctx(), conn, pkt)
case <-ctx.Done():
return nil
}
}
}
func packetHandlerHandleConn(ctx context.Context, conn *Connection, pkt packet.Packet) {
conn.Lock()
defer conn.Unlock()
// Check if we should use the default handler.
// The default handler is only for fully decided
// connections and just applying the verdict.
// There is no logging for these packets.
if conn.firewallHandler == nil {
// Run default handler.
defaultFirewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
return
}
// Create tracing context.
// Add context tracer and set context on packet.
traceCtx, tracer := log.AddTracer(ctx)
if tracer != nil {
// The trace is submitted in `network.Connection.packetHandler()`.
tracer.Tracef("filter: handling packet: %s", pkt)
}
pkt.SetCtx(traceCtx)
// Handle packet with set handler.
conn.firewallHandler(conn, pkt)
// Record metrics.
packetHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)
// Log result and submit trace, when there are any changes.
if conn.saveWhenFinished {
switch {
case conn.DataIsComplete():
tracer.Infof("filter: connection %s %s: %s", conn, conn.VerdictVerb(), conn.Reason.Msg)
case conn.Verdict != VerdictUndecided:
tracer.Debugf("filter: connection %s fast-tracked", pkt)
default:
tracer.Debugf("filter: gathered data on connection %s", conn)
}
// Submit trace logs.
tracer.Submit()
}
// Push changes, if there are any.
if conn.saveWhenFinished {
conn.saveWhenFinished = false
conn.Save()
}
}

View File

@@ -1,16 +1,16 @@
package network
import (
"context"
"fmt"
"strconv"
"strings"
"github.com/safing/portbase/database"
"github.com/safing/portbase/database/iterator"
"github.com/safing/portbase/database/query"
"github.com/safing/portbase/database/record"
"github.com/safing/portbase/database/storage"
"github.com/safing/portmaster/base/database"
"github.com/safing/portmaster/base/database/iterator"
"github.com/safing/portmaster/base/database/query"
"github.com/safing/portmaster/base/database/record"
"github.com/safing/portmaster/base/database/storage"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/process"
)
@@ -110,7 +110,7 @@ func (s *StorageInterface) Get(key string) (record.Record, error) {
func (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {
it := iterator.New()
module.StartWorker("connection query", func(_ context.Context) error {
module.mgr.Go("connection query", func(_ *mgr.WorkerCtx) error {
s.processQuery(q, it)
return nil
})

View File

@@ -10,7 +10,8 @@ import (
"github.com/miekg/dns"
"golang.org/x/exp/slices"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/nameserver/nsutil"
"github.com/safing/portmaster/service/network/packet"
"github.com/safing/portmaster/service/process"
@@ -173,15 +174,15 @@ func SaveOpenDNSRequest(q *resolver.Query, rrCache *resolver.RRCache, conn *Conn
openDNSRequests[key] = conn
}
func openDNSRequestWriter(ctx context.Context) error {
ticker := module.NewSleepyTicker(writeOpenDNSRequestsTickDuration, 0)
defer ticker.Stop()
func openDNSRequestWriter(ctx *mgr.WorkerCtx) error {
module.dnsRequestTicker = mgr.NewSleepyTicker(writeOpenDNSRequestsTickDuration, 0)
defer module.dnsRequestTicker.Stop()
for {
select {
case <-ctx.Done():
return nil
case <-ticker.Wait():
case <-module.dnsRequestTicker.Wait():
writeOpenDNSRequestsToDB()
}
}

View File

@@ -10,7 +10,7 @@ import (
"sync"
"unsafe"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/network/socket"
"golang.org/x/sys/windows"

View File

@@ -1,9 +1,9 @@
package network
import (
"github.com/safing/portbase/api"
"github.com/safing/portbase/config"
"github.com/safing/portbase/metrics"
"github.com/safing/portmaster/base/api"
"github.com/safing/portmaster/base/config"
"github.com/safing/portmaster/base/metrics"
"github.com/safing/portmaster/service/process"
)

View File

@@ -2,33 +2,57 @@ package network
import (
"context"
"errors"
"fmt"
"strings"
"sync"
"sync/atomic"
"github.com/safing/portbase/log"
"github.com/safing/portbase/modules"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/netenv"
"github.com/safing/portmaster/service/network/state"
"github.com/safing/portmaster/service/profile"
)
var (
module *modules.Module
defaultFirewallHandler FirewallHandler
)
// Events.
var (
const (
ConnectionReattributedEvent = "connection re-attributed"
)
func init() {
module = modules.Register("network", prep, start, nil, "base", "netenv", "processes")
module.RegisterEvent(ConnectionReattributedEvent, false)
type Network struct {
mgr *mgr.Manager
instance instance
dnsRequestTicker *mgr.SleepyTicker
connectionCleanerTicker *mgr.SleepyTicker
EventConnectionReattributed *mgr.EventMgr[string]
}
func (n *Network) Manager() *mgr.Manager {
return n.mgr
}
func (n *Network) Start() error {
return start()
}
func (n *Network) Stop() error {
return nil
}
func (n *Network) SetSleep(enabled bool) {
if n.dnsRequestTicker != nil {
n.dnsRequestTicker.SetSleep(enabled)
}
if n.connectionCleanerTicker != nil {
n.connectionCleanerTicker.SetSleep(enabled)
}
}
var defaultFirewallHandler FirewallHandler
// SetDefaultFirewallHandler sets the default firewall handler.
func SetDefaultFirewallHandler(handler FirewallHandler) {
if defaultFirewallHandler == nil {
@@ -55,17 +79,9 @@ func start() error {
return err
}
module.StartServiceWorker("clean connections", 0, connectionCleaner)
module.StartServiceWorker("write open dns requests", 0, openDNSRequestWriter)
if err := module.RegisterEventHook(
"profiles",
profile.DeletedEvent,
"re-attribute connections from deleted profile",
reAttributeConnections,
); err != nil {
return err
}
module.mgr.Go("clean connections", connectionCleaner)
module.mgr.Go("write open dns requests", openDNSRequestWriter)
module.instance.Profile().EventDelete.AddCallback("re-attribute connections from deleted profile", reAttributeConnections)
return nil
}
@@ -74,14 +90,10 @@ var reAttributionLock sync.Mutex
// reAttributeConnections finds all connections of a deleted profile and re-attributes them.
// Expected event data: scoped profile ID.
func reAttributeConnections(_ context.Context, eventData any) error {
profileID, ok := eventData.(string)
if !ok {
return fmt.Errorf("event data is not a string: %v", eventData)
}
func reAttributeConnections(_ *mgr.WorkerCtx, profileID string) (bool, error) {
profileSource, profileID, ok := strings.Cut(profileID, "/")
if !ok {
return fmt.Errorf("event data does not seem to be a scoped profile ID: %v", eventData)
return false, fmt.Errorf("event data does not seem to be a scoped profile ID: %v", profileID)
}
// Hold a lock for re-attribution, to prevent simultaneous processing of the
@@ -114,7 +126,7 @@ func reAttributeConnections(_ context.Context, eventData any) error {
}
tracer.Infof("filter: re-attributed %d connections", reAttributed)
return nil
return false, nil
}
func reAttributeConnection(ctx context.Context, conn *Connection, profileID, profileSource string) (reAttributed bool) {
@@ -144,8 +156,36 @@ func reAttributeConnection(ctx context.Context, conn *Connection, profileID, pro
conn.Save()
// Trigger event for re-attribution.
module.TriggerEvent(ConnectionReattributedEvent, conn.ID)
module.EventConnectionReattributed.Submit(conn.ID)
log.Tracer(ctx).Debugf("filter: re-attributed %s to %s", conn, conn.process.PrimaryProfileID)
return true
}
var (
module *Network
shimLoaded atomic.Bool
)
// New returns a new Network module.
func New(instance instance) (*Network, error) {
if !shimLoaded.CompareAndSwap(false, true) {
return nil, errors.New("only one instance allowed")
}
m := mgr.New("Network")
module = &Network{
mgr: m,
instance: instance,
EventConnectionReattributed: mgr.NewEventMgr[string](ConnectionReattributedEvent, m),
}
if err := prep(); err != nil {
return nil, err
}
return module, nil
}
type instance interface {
Profile() *profile.ProfileModule
}

View File

@@ -84,6 +84,10 @@ func GetIPScope(ip net.IP) IPScope { //nolint:gocognit
}
} else if len(ip) == net.IPv6len {
// IPv6
// TODO: Add IPv6 RFC5771 test / doc networks
// 2001:db8::/32
// 3fff::/20
switch {
case ip.Equal(net.IPv6zero):
return Invalid
@@ -153,7 +157,7 @@ func GetBroadcastAddress(ip net.IP, netMask net.IPMask) net.IP {
// Merge to broadcast address
n := len(ip)
broadcastAddress := make(net.IP, n)
for i := 0; i < n; i++ {
for i := range n {
broadcastAddress[i] = ip[i] | ^mask[i]
}
return broadcastAddress

View File

@@ -1,8 +1,8 @@
package network
import (
"github.com/safing/portbase/log"
"github.com/safing/portbase/rng"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/base/rng"
)
// GetUnusedLocalPort returns a local port of the specified protocol that is
@@ -13,7 +13,7 @@ func GetUnusedLocalPort(protocol uint8) (port uint16, ok bool) {
// Try up to 1000 times to find an unused port.
nextPort:
for i := 0; i < tries; i++ {
for i := range tries {
// Generate random port between 10000 and 65535
rN, err := rng.Number(55535)
if err != nil {

View File

@@ -8,7 +8,7 @@ import (
"os"
"strconv"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/network/socket"
)

View File

@@ -11,8 +11,8 @@ import (
"syscall"
"time"
"github.com/safing/portbase/log"
"github.com/safing/portbase/utils"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/base/utils"
)
var (

View File

@@ -12,7 +12,7 @@ import (
"strings"
"unicode"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/network/socket"
)

View File

@@ -3,7 +3,7 @@ package state
import (
"sync"
"github.com/safing/portbase/database/record"
"github.com/safing/portmaster/base/database/record"
"github.com/safing/portmaster/service/netenv"
"github.com/safing/portmaster/service/network/socket"
)

View File

@@ -6,7 +6,7 @@ package state
import (
"time"
"github.com/safing/portbase/config"
"github.com/safing/portmaster/base/config"
"github.com/safing/portmaster/service/network/socket"
)

View File

@@ -6,8 +6,8 @@ import (
"sync/atomic"
"time"
"github.com/safing/portbase/log"
"github.com/safing/portbase/utils"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/base/utils"
"github.com/safing/portmaster/service/network/socket"
)

View File

@@ -8,8 +8,8 @@ import (
"sync/atomic"
"time"
"github.com/safing/portbase/log"
"github.com/safing/portbase/utils"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/base/utils"
"github.com/safing/portmaster/service/netenv"
"github.com/safing/portmaster/service/network/packet"
"github.com/safing/portmaster/service/network/socket"