Merge branch 'develop' into feature/new-installer
This commit is contained in:
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
type ETWSession struct {
|
||||
i integration.ETWFunctions
|
||||
i *integration.ETWFunctions
|
||||
|
||||
shutdownGuard atomic.Bool
|
||||
shutdownMutex sync.Mutex
|
||||
@@ -23,7 +23,10 @@ type ETWSession struct {
|
||||
}
|
||||
|
||||
// NewSession creates new ETW event listener and initilizes it. This is a low level interface, make sure to call DestorySession when you are done using it.
|
||||
func NewSession(etwInterface integration.ETWFunctions, callback func(domain string, result string)) (*ETWSession, error) {
|
||||
func NewSession(etwInterface *integration.ETWFunctions, callback func(domain string, result string)) (*ETWSession, error) {
|
||||
if etwInterface == nil {
|
||||
return nil, fmt.Errorf("etw interface was nil")
|
||||
}
|
||||
etwSession := &ETWSession{
|
||||
i: etwInterface,
|
||||
}
|
||||
@@ -47,7 +50,7 @@ func NewSession(etwInterface integration.ETWFunctions, callback func(domain stri
|
||||
// Initialize session.
|
||||
err := etwSession.i.InitializeSession(etwSession.state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialzie session: %q", err)
|
||||
return nil, fmt.Errorf("failed to initialize session: %q", err)
|
||||
}
|
||||
|
||||
return etwSession, nil
|
||||
@@ -65,6 +68,10 @@ func (l *ETWSession) IsRunning() bool {
|
||||
|
||||
// FlushTrace flushes the trace buffer.
|
||||
func (l *ETWSession) FlushTrace() error {
|
||||
if l.i == nil {
|
||||
return fmt.Errorf("session not initialized")
|
||||
}
|
||||
|
||||
l.shutdownMutex.Lock()
|
||||
defer l.shutdownMutex.Unlock()
|
||||
|
||||
@@ -83,6 +90,9 @@ func (l *ETWSession) StopTrace() error {
|
||||
|
||||
// DestroySession closes the session and frees the allocated memory. Listener cannot be used after this function is called.
|
||||
func (l *ETWSession) DestroySession() error {
|
||||
if l.i == nil {
|
||||
return fmt.Errorf("session not initialized")
|
||||
}
|
||||
l.shutdownMutex.Lock()
|
||||
defer l.shutdownMutex.Unlock()
|
||||
|
||||
|
||||
@@ -23,22 +23,38 @@ func newListener(module *DNSMonitor) (*Listener, error) {
|
||||
ResolverInfo.Source = resolver.ServerSourceETW
|
||||
|
||||
listener := &Listener{}
|
||||
var err error
|
||||
// Initialize new dns event session.
|
||||
listener.etw, err = NewSession(module.instance.OSIntegration().GetETWInterface(), listener.processEvent)
|
||||
err := initializeSessions(module, listener)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Listen for event if the dll has been loaded
|
||||
module.instance.OSIntegration().OnInitializedEvent.AddCallback("loader-listener", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {
|
||||
err = initializeSessions(module, listener)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Start listening for events.
|
||||
module.mgr.Go("etw-dns-event-listener", func(w *mgr.WorkerCtx) error {
|
||||
return listener.etw.StartTrace()
|
||||
})
|
||||
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
func initializeSessions(module *DNSMonitor, listener *Listener) error {
|
||||
var err error
|
||||
listener.etw, err = NewSession(module.instance.OSIntegration().GetETWInterface(), listener.processEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Start listener
|
||||
module.mgr.Go("etw-dns-event-listener", func(w *mgr.WorkerCtx) error {
|
||||
return listener.etw.StartTrace()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Listener) flush() error {
|
||||
if l.etw == nil {
|
||||
return fmt.Errorf("etw not initialized")
|
||||
}
|
||||
return l.etw.FlushTrace()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ type ETWFunctions struct {
|
||||
stopOldSession *windows.Proc
|
||||
}
|
||||
|
||||
func initializeETW(dll *windows.DLL) (ETWFunctions, error) {
|
||||
var functions ETWFunctions
|
||||
func initializeETW(dll *windows.DLL) (*ETWFunctions, error) {
|
||||
functions := &ETWFunctions{}
|
||||
var err error
|
||||
functions.createState, err = dll.FindProc("PM_ETWCreateState")
|
||||
if err != nil {
|
||||
|
||||
@@ -5,23 +5,54 @@ package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/service/mgr"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type OSSpecific struct {
|
||||
dll *windows.DLL
|
||||
etwFunctions ETWFunctions
|
||||
etwFunctions *ETWFunctions
|
||||
}
|
||||
|
||||
// Initialize loads the dll and finds all the needed functions from it.
|
||||
func (i *OSIntegration) Initialize() error {
|
||||
// Try to load dll
|
||||
err := i.loadDLL()
|
||||
if err != nil {
|
||||
log.Errorf("integration: failed to load dll: %s", err)
|
||||
|
||||
callbackLock := sync.Mutex{}
|
||||
// listen for event from the updater and try to load again if any.
|
||||
i.instance.BinaryUpdates().EventResourcesUpdated.AddCallback("core-dll-loader", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {
|
||||
// Make sure no multiple callas are executed at the same time.
|
||||
callbackLock.Lock()
|
||||
defer callbackLock.Unlock()
|
||||
|
||||
// Try to load again.
|
||||
err = i.loadDLL()
|
||||
if err != nil {
|
||||
log.Errorf("integration: failed to load dll: %s", err)
|
||||
} else {
|
||||
log.Info("integration: initialize successful after updater event")
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
|
||||
} else {
|
||||
log.Info("integration: initialize successful")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *OSIntegration) loadDLL() error {
|
||||
// Find path to the dll.
|
||||
file, err := i.instance.BinaryUpdates().GetFile("portmaster-core.dll")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load the DLL.
|
||||
i.os.dll, err = windows.LoadDLL(file.Path())
|
||||
if err != nil {
|
||||
@@ -34,6 +65,9 @@ func (i *OSIntegration) Initialize() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify listeners
|
||||
i.OnInitializedEvent.Submit(struct{}{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -45,7 +79,7 @@ func (i *OSIntegration) CleanUp() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetETWInterface return struct containing all the ETW related functions.
|
||||
func (i *OSIntegration) GetETWInterface() ETWFunctions {
|
||||
// GetETWInterface return struct containing all the ETW related functions, and nil if it was not loaded yet
|
||||
func (i *OSIntegration) GetETWInterface() *ETWFunctions {
|
||||
return i.os.etwFunctions
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import (
|
||||
|
||||
// OSIntegration module provides special integration with the OS.
|
||||
type OSIntegration struct {
|
||||
m *mgr.Manager
|
||||
states *mgr.StateMgr
|
||||
m *mgr.Manager
|
||||
|
||||
OnInitializedEvent *mgr.EventMgr[struct{}]
|
||||
|
||||
//nolint:unused
|
||||
os OSSpecific
|
||||
@@ -20,10 +21,9 @@ type OSIntegration struct {
|
||||
func New(instance instance) (*OSIntegration, error) {
|
||||
m := mgr.New("OSIntegration")
|
||||
module := &OSIntegration{
|
||||
m: m,
|
||||
states: m.NewStateMgr(),
|
||||
|
||||
instance: instance,
|
||||
m: m,
|
||||
OnInitializedEvent: mgr.NewEventMgr[struct{}]("on-initialized", m),
|
||||
instance: instance,
|
||||
}
|
||||
|
||||
return module, nil
|
||||
|
||||
@@ -49,7 +49,7 @@ var (
|
||||
var cache = database.NewInterface(&database.Options{
|
||||
Local: true,
|
||||
Internal: true,
|
||||
CacheSize: 2 ^ 8,
|
||||
CacheSize: 256,
|
||||
})
|
||||
|
||||
// getFileFunc is the function used to get a file from
|
||||
|
||||
@@ -4,7 +4,7 @@ import "time"
|
||||
|
||||
// SleepyTicker is wrapper over time.Ticker that respects the sleep mode of the module.
|
||||
type SleepyTicker struct {
|
||||
ticker time.Ticker
|
||||
ticker *time.Ticker
|
||||
normalDuration time.Duration
|
||||
sleepDuration time.Duration
|
||||
sleepMode bool
|
||||
@@ -16,7 +16,7 @@ type SleepyTicker struct {
|
||||
// If sleepDuration is set to 0 ticker will not tick during sleep.
|
||||
func NewSleepyTicker(normalDuration time.Duration, sleepDuration time.Duration) *SleepyTicker {
|
||||
st := &SleepyTicker{
|
||||
ticker: *time.NewTicker(normalDuration),
|
||||
ticker: time.NewTicker(normalDuration),
|
||||
normalDuration: normalDuration,
|
||||
sleepDuration: sleepDuration,
|
||||
sleepMode: false,
|
||||
|
||||
57
service/mgr/sleepyticker_test.go
Normal file
57
service/mgr/sleepyticker_test.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package mgr
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSleepyTickerStop(t *testing.T) {
|
||||
normalDuration := 100 * time.Millisecond
|
||||
sleepDuration := 200 * time.Millisecond
|
||||
|
||||
st := NewSleepyTicker(normalDuration, sleepDuration)
|
||||
st.Stop() // no panic expected here
|
||||
}
|
||||
|
||||
func TestSleepyTicker(t *testing.T) {
|
||||
normalDuration := 100 * time.Millisecond
|
||||
sleepDuration := 200 * time.Millisecond
|
||||
|
||||
st := NewSleepyTicker(normalDuration, sleepDuration)
|
||||
|
||||
// Test normal mode
|
||||
select {
|
||||
case <-st.Wait():
|
||||
// Expected tick
|
||||
case <-time.After(normalDuration + 50*time.Millisecond):
|
||||
t.Error("expected tick in normal mode")
|
||||
}
|
||||
|
||||
// Test sleep mode
|
||||
st.SetSleep(true)
|
||||
select {
|
||||
case <-st.Wait():
|
||||
// Expected tick
|
||||
case <-time.After(sleepDuration + 50*time.Millisecond):
|
||||
t.Error("expected tick in sleep mode")
|
||||
}
|
||||
|
||||
// Test sleep mode with sleepDuration == 0
|
||||
st = NewSleepyTicker(normalDuration, 0)
|
||||
st.SetSleep(true)
|
||||
select {
|
||||
case <-st.Wait():
|
||||
t.Error("did not expect tick when sleepDuration is 0")
|
||||
case <-time.After(normalDuration):
|
||||
// Expected no tick
|
||||
}
|
||||
|
||||
// Test stopping the ticker
|
||||
st.Stop()
|
||||
select {
|
||||
case <-st.Wait():
|
||||
t.Error("did not expect tick after stopping the ticker")
|
||||
case <-time.After(normalDuration):
|
||||
// Expected no tick
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/safing/portmaster/base/config"
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
"github.com/safing/portmaster/service/netquery/orm"
|
||||
"github.com/safing/portmaster/service/network"
|
||||
"github.com/safing/portmaster/service/network/netutils"
|
||||
@@ -131,6 +132,10 @@ func New(dbPath string) (*Database, error) {
|
||||
if err := os.MkdirAll(historyParentDir, 0o0700); err != nil {
|
||||
return nil, fmt.Errorf("failed to ensure database directory exists: %w", err)
|
||||
}
|
||||
err := utils.EnsureDirectory(historyParentDir, utils.AdminOnlyPermission)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set permission to folder %s: %w", historyParentDir, err)
|
||||
}
|
||||
|
||||
// Get file location of history database.
|
||||
historyFile := filepath.Join(historyParentDir, "history.db")
|
||||
@@ -229,6 +234,10 @@ func VacuumHistory(ctx context.Context) (err error) {
|
||||
if err := os.MkdirAll(historyParentDir, 0o0700); err != nil {
|
||||
return fmt.Errorf("failed to ensure database directory exists: %w", err)
|
||||
}
|
||||
err = utils.EnsureDirectory(historyParentDir, utils.AdminOnlyPermission)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set permission to folder %s: %w", historyParentDir, err)
|
||||
}
|
||||
|
||||
// Get file location of history database.
|
||||
historyFile := filepath.Join(historyParentDir, "history.db")
|
||||
|
||||
@@ -550,7 +550,11 @@ func (conn *Connection) GatherConnectionInfo(pkt packet.Packet) (err error) {
|
||||
if module.instance.Resolver().IsDisabled() && conn.shouldWaitForDomain() {
|
||||
// Flush the dns listener buffer and try again.
|
||||
for i := range 4 {
|
||||
_ = module.instance.DNSMonitor().Flush()
|
||||
err = module.instance.DNSMonitor().Flush()
|
||||
if err != nil {
|
||||
// Error flushing, dont try again.
|
||||
break
|
||||
}
|
||||
ipinfo, err = resolver.GetIPInfo(resolver.IPInfoProfileScopeGlobal, pkt.Info().RemoteIP().String())
|
||||
if err == nil {
|
||||
log.Tracer(pkt.Ctx()).Debugf("network: found domain from dnsmonitor after %d tries", i+1)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/safing/portmaster/base/database"
|
||||
"github.com/safing/portmaster/base/database/migration"
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
_ "github.com/safing/portmaster/service/core/base"
|
||||
"github.com/safing/portmaster/service/mgr"
|
||||
"github.com/safing/portmaster/service/profile/binmeta"
|
||||
@@ -66,10 +67,22 @@ func prep() error {
|
||||
}
|
||||
|
||||
// Setup icon storage location.
|
||||
iconsDir := filepath.Join(module.instance.DataDir(), "databases", "icons")
|
||||
databaseDir := filepath.Join(module.instance.DataDir(), "databases")
|
||||
iconsDir := filepath.Join(databaseDir, "icons")
|
||||
if err := os.MkdirAll(iconsDir, 0o0700); err != nil {
|
||||
return fmt.Errorf("failed to create/check icons directory: %w", err)
|
||||
}
|
||||
|
||||
// Ensure folder permissions
|
||||
err := utils.EnsureDirectory(databaseDir, utils.AdminOnlyPermission)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set permission to folder %s: %w", databaseDir, err)
|
||||
}
|
||||
err = utils.EnsureDirectory(iconsDir, utils.AdminOnlyPermission)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set permission to folder %s: %w", iconsDir, err)
|
||||
}
|
||||
|
||||
binmeta.ProfileIconStoragePath = iconsDir
|
||||
|
||||
return nil
|
||||
|
||||
@@ -510,7 +510,7 @@ func setScopedResolvers(resolvers []*Resolver) {
|
||||
for _, resolver := range resolvers {
|
||||
if resolver.Info.IPScope.IsLAN() {
|
||||
localResolvers = append(localResolvers, resolver)
|
||||
} else if _, err := netenv.GetLocalNetwork(resolver.Info.IP); err != nil {
|
||||
} else if net, _ := netenv.GetLocalNetwork(resolver.Info.IP); net != nil {
|
||||
localResolvers = append(localResolvers, resolver)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/safing/portmaster/base/api"
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
"github.com/safing/portmaster/service/mgr"
|
||||
"github.com/safing/portmaster/service/updates"
|
||||
)
|
||||
@@ -35,6 +36,12 @@ func start() error {
|
||||
log.Warningf("ui: failed to create safe exec dir: %s", err)
|
||||
}
|
||||
|
||||
// Ensure directory permission
|
||||
err = utils.EnsureDirectory(execDir, utils.PublicWritePermission)
|
||||
if err != nil {
|
||||
log.Warningf("ui: failed to set permissions to directory %s: %s", execDir, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user