mirror of
https://github.com/safing/portmaster
synced 2025-04-08 13:09:11 +00:00
* [service] Add reading of PID in ETW DNS event * [service] Use PID of the ETW DNS events * [service] Fix use of nil pointer * [service] Fix compiler error
109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package dnsmonitor
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/safing/portmaster/service/integration"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
type ETWSession struct {
|
|
i *integration.ETWFunctions
|
|
|
|
shutdownGuard atomic.Bool
|
|
shutdownMutex sync.Mutex
|
|
|
|
state uintptr
|
|
}
|
|
|
|
// NewSession creates new ETW event listener and initializes it. This is a low level interface, make sure to call DestroySession when you are done using it.
|
|
func NewSession(etwInterface *integration.ETWFunctions, callback func(domain string, pid uint32, result string)) (*ETWSession, error) {
|
|
if etwInterface == nil {
|
|
return nil, fmt.Errorf("etw interface was nil")
|
|
}
|
|
etwSession := &ETWSession{
|
|
i: etwInterface,
|
|
}
|
|
|
|
// Make sure session from previous instances are not running.
|
|
_ = etwSession.i.StopOldSession()
|
|
|
|
// Initialize notification activated callback
|
|
win32Callback := windows.NewCallback(func(domain *uint16, pid uint32, result *uint16) uintptr {
|
|
callback(windows.UTF16PtrToString(domain), pid, windows.UTF16PtrToString(result))
|
|
return 0
|
|
})
|
|
// The function only allocates memory it will not fail.
|
|
etwSession.state = etwSession.i.CreateState(win32Callback)
|
|
|
|
// Make sure DestroySession is called even if caller forgets to call it.
|
|
runtime.SetFinalizer(etwSession, func(s *ETWSession) {
|
|
_ = s.i.DestroySession(s.state)
|
|
})
|
|
|
|
// Initialize session.
|
|
err := etwSession.i.InitializeSession(etwSession.state)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize session: %q", err)
|
|
}
|
|
|
|
return etwSession, nil
|
|
}
|
|
|
|
// StartTrace starts the tracing session of dns events. This is a blocking call. It will not return until the trace is stopped.
|
|
func (l *ETWSession) StartTrace() error {
|
|
return l.i.StartTrace(l.state)
|
|
}
|
|
|
|
// IsRunning returns true if DestroySession has NOT been called.
|
|
func (l *ETWSession) IsRunning() bool {
|
|
return !l.shutdownGuard.Load()
|
|
}
|
|
|
|
// 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()
|
|
|
|
// Make sure session is still running.
|
|
if l.shutdownGuard.Load() {
|
|
return nil
|
|
}
|
|
|
|
return l.i.FlushTrace(l.state)
|
|
}
|
|
|
|
// StopTrace stops the trace. This will cause StartTrace to return.
|
|
func (l *ETWSession) StopTrace() error {
|
|
return l.i.StopTrace(l.state)
|
|
}
|
|
|
|
// 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()
|
|
|
|
if l.shutdownGuard.Swap(true) {
|
|
return nil
|
|
}
|
|
|
|
err := l.i.DestroySession(l.state)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
l.state = 0
|
|
return nil
|
|
}
|