mirror of
https://github.com/safing/portmaster
synced 2025-09-02 10:39:22 +00:00
Improve metadata handling of profiles
Also, improve OS profile handling
This commit is contained in:
parent
4b694c5f84
commit
5a88fc2fce
8 changed files with 133 additions and 130 deletions
|
@ -165,15 +165,26 @@ type Reason struct {
|
||||||
Context interface{}
|
Context interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProcessContext(proc *process.Process) ProcessContext {
|
func getProcessContext(ctx context.Context, proc *process.Process) ProcessContext {
|
||||||
return ProcessContext{
|
// Gather process information.
|
||||||
|
pCtx := ProcessContext{
|
||||||
BinaryPath: proc.Path,
|
BinaryPath: proc.Path,
|
||||||
ProcessName: proc.Name,
|
ProcessName: proc.Name,
|
||||||
ProfileName: proc.Profile().LocalProfile().Name,
|
|
||||||
PID: proc.Pid,
|
PID: proc.Pid,
|
||||||
Profile: proc.Profile().LocalProfile().ID,
|
|
||||||
Source: string(proc.Profile().LocalProfile().Source),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get local profile.
|
||||||
|
localProfile := proc.Profile().LocalProfile()
|
||||||
|
if localProfile == nil {
|
||||||
|
log.Tracer(ctx).Warningf("network: process %s has no profile", proc)
|
||||||
|
return pCtx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add profile information and return.
|
||||||
|
pCtx.ProfileName = localProfile.Name
|
||||||
|
pCtx.Profile = localProfile.ID
|
||||||
|
pCtx.Source = string(localProfile.Source)
|
||||||
|
return pCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnectionFromDNSRequest returns a new connection based on the given dns request.
|
// NewConnectionFromDNSRequest returns a new connection based on the given dns request.
|
||||||
|
@ -204,7 +215,7 @@ func NewConnectionFromDNSRequest(ctx context.Context, fqdn string, cnames []stri
|
||||||
CNAME: cnames,
|
CNAME: cnames,
|
||||||
},
|
},
|
||||||
process: proc,
|
process: proc,
|
||||||
ProcessContext: getProcessContext(proc),
|
ProcessContext: getProcessContext(ctx, proc),
|
||||||
Started: timestamp,
|
Started: timestamp,
|
||||||
Ended: timestamp,
|
Ended: timestamp,
|
||||||
}
|
}
|
||||||
|
@ -304,7 +315,7 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
|
||||||
IPProtocol: pkt.Info().Protocol,
|
IPProtocol: pkt.Info().Protocol,
|
||||||
LocalIP: pkt.Info().LocalIP(),
|
LocalIP: pkt.Info().LocalIP(),
|
||||||
LocalPort: pkt.Info().LocalPort(),
|
LocalPort: pkt.Info().LocalPort(),
|
||||||
ProcessContext: getProcessContext(proc),
|
ProcessContext: getProcessContext(pkt.Ctx(), proc),
|
||||||
process: proc,
|
process: proc,
|
||||||
// remote endpoint
|
// remote endpoint
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
|
|
|
@ -232,19 +232,14 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
defer markRequestFinished()
|
defer markRequestFinished()
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new process
|
// Create new a process object.
|
||||||
new := &Process{
|
new := &Process{
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
Virtual: true, // caller must decide to actually use the process - we need to save now.
|
Virtual: true, // caller must decide to actually use the process - we need to save now.
|
||||||
FirstSeen: time.Now().Unix(),
|
FirstSeen: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
// Get process information from the system.
|
||||||
case new.IsKernel():
|
|
||||||
new.UserName = "Kernel"
|
|
||||||
new.Name = "Operating System"
|
|
||||||
default:
|
|
||||||
|
|
||||||
pInfo, err := processInfo.NewProcess(int32(pid))
|
pInfo, err := processInfo.NewProcess(int32(pid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -313,7 +308,6 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
|
|
||||||
// OS specifics
|
// OS specifics
|
||||||
new.specialOSInit()
|
new.specialOSInit()
|
||||||
}
|
|
||||||
|
|
||||||
new.Save()
|
new.Save()
|
||||||
return new, nil
|
return new, nil
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
|
|
||||||
package process
|
package process
|
||||||
|
|
||||||
// IsKernel returns whether the process is the Kernel.
|
// SystemProcessID is the PID of the System/Kernel itself.
|
||||||
func (p *Process) IsKernel() bool {
|
const SystemProcessID = 0
|
||||||
return p.Pid == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// specialOSInit does special OS specific Process initialization.
|
// specialOSInit does special OS specific Process initialization.
|
||||||
func (p *Process) specialOSInit() {
|
func (p *Process) specialOSInit() {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package process
|
package process
|
||||||
|
|
||||||
// IsKernel returns whether the process is the Kernel.
|
// SystemProcessID is the PID of the System/Kernel itself.
|
||||||
func (p *Process) IsKernel() bool {
|
const SystemProcessID = 0
|
||||||
return p.Pid == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// specialOSInit does special OS specific Process initialization.
|
// specialOSInit does special OS specific Process initialization.
|
||||||
func (p *Process) specialOSInit() {
|
func (p *Process) specialOSInit() {
|
||||||
|
|
|
@ -7,10 +7,8 @@ import (
|
||||||
"github.com/safing/portbase/utils/osdetail"
|
"github.com/safing/portbase/utils/osdetail"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsKernel returns whether the process is the Kernel.
|
// SystemProcessID is the PID of the System/Kernel itself.
|
||||||
func (p *Process) IsKernel() bool {
|
const SystemProcessID = 4
|
||||||
return p.Pid == 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// specialOSInit does special OS specific Process initialization.
|
// specialOSInit does special OS specific Process initialization.
|
||||||
func (p *Process) specialOSInit() {
|
func (p *Process) specialOSInit() {
|
||||||
|
|
|
@ -9,11 +9,9 @@ import (
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Special Process IDs
|
// UnidentifiedProcessID is the PID used for anything that could not be
|
||||||
const (
|
// attributed to a PID for any reason.
|
||||||
UnidentifiedProcessID = -1
|
const UnidentifiedProcessID = -1
|
||||||
SystemProcessID = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// unidentifiedProcess is used when a process cannot be found.
|
// unidentifiedProcess is used when a process cannot be found.
|
||||||
|
@ -39,18 +37,18 @@ var (
|
||||||
|
|
||||||
// GetUnidentifiedProcess returns the special process assigned to unidentified processes.
|
// GetUnidentifiedProcess returns the special process assigned to unidentified processes.
|
||||||
func GetUnidentifiedProcess(ctx context.Context) *Process {
|
func GetUnidentifiedProcess(ctx context.Context) *Process {
|
||||||
return getSpecialProcess(ctx, UnidentifiedProcessID, unidentifiedProcess)
|
return getSpecialProcess(ctx, unidentifiedProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSystemProcess returns the special process used for the Kernel.
|
// GetSystemProcess returns the special process used for the Kernel.
|
||||||
func GetSystemProcess(ctx context.Context) *Process {
|
func GetSystemProcess(ctx context.Context) *Process {
|
||||||
return getSpecialProcess(ctx, SystemProcessID, systemProcess)
|
return getSpecialProcess(ctx, systemProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSpecialProcess(ctx context.Context, pid int, template *Process) *Process {
|
func getSpecialProcess(ctx context.Context, template *Process) *Process {
|
||||||
p, _, _ := getSpecialProcessSingleInflight.Do(strconv.Itoa(pid), func() (interface{}, error) {
|
p, _, _ := getSpecialProcessSingleInflight.Do(strconv.Itoa(template.Pid), func() (interface{}, error) {
|
||||||
// Check if we have already loaded the special process.
|
// Check if we have already loaded the special process.
|
||||||
process, ok := GetProcessFromStorage(pid)
|
process, ok := GetProcessFromStorage(template.Pid)
|
||||||
if ok {
|
if ok {
|
||||||
return process, nil
|
return process, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,10 @@ func (lp *LayeredProfile) UnlockForUsage() {
|
||||||
|
|
||||||
// LocalProfile returns the local profile associated with this layered profile.
|
// LocalProfile returns the local profile associated with this layered profile.
|
||||||
func (lp *LayeredProfile) LocalProfile() *Profile {
|
func (lp *LayeredProfile) LocalProfile() *Profile {
|
||||||
|
if lp == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
lp.RLock()
|
lp.RLock()
|
||||||
defer lp.RUnlock()
|
defer lp.RUnlock()
|
||||||
|
|
||||||
|
|
|
@ -386,22 +386,22 @@ func EnsureProfile(r record.Record) (*Profile, error) {
|
||||||
// the profile was changed. If there is data that needs to be fetched from the
|
// the profile was changed. If there is data that needs to be fetched from the
|
||||||
// operating system, it will start an async worker to fetch that data and save
|
// operating system, it will start an async worker to fetch that data and save
|
||||||
// the profile afterwards.
|
// the profile afterwards.
|
||||||
func (p *Profile) UpdateMetadata(processName string) (changed bool) {
|
func (profile *Profile) UpdateMetadata(processName string) (changed bool) {
|
||||||
// Check if this is a local profile, else warn and return.
|
// Check if this is a local profile, else warn and return.
|
||||||
if p.Source != SourceLocal {
|
if profile.Source != SourceLocal {
|
||||||
log.Warningf("tried to update metadata for non-local profile %s", p.ScopedID())
|
log.Warningf("tried to update metadata for non-local profile %s", profile.ScopedID())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Lock()
|
profile.Lock()
|
||||||
defer p.Unlock()
|
defer profile.Unlock()
|
||||||
|
|
||||||
// Check if this is a special profile.
|
// Check if this is a special profile.
|
||||||
if p.LinkedPath == "" {
|
if profile.LinkedPath == "" {
|
||||||
// This is a special profile, just assign the processName, if needed, and
|
// This is a special profile, just assign the processName, if needed, and
|
||||||
// return.
|
// return.
|
||||||
if p.Name != processName {
|
if profile.Name != processName {
|
||||||
p.Name = processName
|
profile.Name = processName
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -410,18 +410,18 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
|
||||||
var needsUpdateFromSystem bool
|
var needsUpdateFromSystem bool
|
||||||
|
|
||||||
// Check profile name.
|
// Check profile name.
|
||||||
_, filename := filepath.Split(p.LinkedPath)
|
_, filename := filepath.Split(profile.LinkedPath)
|
||||||
|
|
||||||
// Update profile name if it is empty or equals the filename, which is the
|
// Update profile name if it is empty or equals the filename, which is the
|
||||||
// case for older profiles.
|
// case for older profiles.
|
||||||
if p.Name == "" || p.Name == filename {
|
if profile.Name == "" || profile.Name == filename {
|
||||||
// Generate a default profile name if does not exist.
|
// Generate a default profile name if does not exist.
|
||||||
p.Name = osdetail.GenerateBinaryNameFromPath(p.LinkedPath)
|
profile.Name = osdetail.GenerateBinaryNameFromPath(profile.LinkedPath)
|
||||||
if p.Name == filename {
|
if profile.Name == filename {
|
||||||
// TODO: Theoretically, the generated name could be identical to the
|
// TODO: Theoretically, the generated name could be identical to the
|
||||||
// filename.
|
// filename.
|
||||||
// As a quick fix, append a space to the name.
|
// As a quick fix, append a space to the name.
|
||||||
p.Name += " "
|
profile.Name += " "
|
||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
needsUpdateFromSystem = true
|
needsUpdateFromSystem = true
|
||||||
|
@ -429,7 +429,7 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
|
||||||
|
|
||||||
// If needed, get more/better data from the operating system.
|
// If needed, get more/better data from the operating system.
|
||||||
if needsUpdateFromSystem {
|
if needsUpdateFromSystem {
|
||||||
module.StartWorker("get profile metadata", p.updateMetadataFromSystem)
|
module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
@ -437,32 +437,34 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
|
||||||
|
|
||||||
// updateMetadataFromSystem updates the profile metadata with data from the
|
// updateMetadataFromSystem updates the profile metadata with data from the
|
||||||
// operating system and saves it afterwards.
|
// operating system and saves it afterwards.
|
||||||
func (p *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
||||||
// This function is only valid for local profiles.
|
// This function is only valid for local profiles.
|
||||||
if p.Source != SourceLocal || p.LinkedPath == "" {
|
if profile.Source != SourceLocal || profile.LinkedPath == "" {
|
||||||
return fmt.Errorf("tried to update metadata for non-local / non-linked profile %s", p.ScopedID())
|
return fmt.Errorf("tried to update metadata for non-local / non-linked profile %s", profile.ScopedID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the profile when finished, if needed.
|
// Save the profile when finished, if needed.
|
||||||
save := false
|
save := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if save {
|
if save {
|
||||||
err := p.Save()
|
err := profile.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("profile: failed to save %s after metadata update: %s", p.ScopedID(), err)
|
log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Get binary name from linked path.
|
// Get binary name from linked path.
|
||||||
newName, err := osdetail.GetBinaryNameFromSystem(p.LinkedPath)
|
newName, err := osdetail.GetBinaryNameFromSystem(profile.LinkedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("profile: error while getting binary name for %s: %s", p.LinkedPath, err)
|
if !errors.Is(err, osdetail.ErrNotSupported) {
|
||||||
|
log.Warningf("profile: error while getting binary name for %s: %s", profile.LinkedPath, err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get filename of linked path for comparison.
|
// Get filename of linked path for comparison.
|
||||||
_, filename := filepath.Split(p.LinkedPath)
|
_, filename := filepath.Split(profile.LinkedPath)
|
||||||
|
|
||||||
// TODO: Theoretically, the generated name from the system could be identical
|
// TODO: Theoretically, the generated name from the system could be identical
|
||||||
// to the filename. This would mean that the worker is triggered every time
|
// to the filename. This would mean that the worker is triggered every time
|
||||||
|
@ -473,12 +475,12 @@ func (p *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock profile for applying metadata.
|
// Lock profile for applying metadata.
|
||||||
p.Lock()
|
profile.Lock()
|
||||||
defer p.Unlock()
|
defer profile.Unlock()
|
||||||
|
|
||||||
// Apply new name if it changed.
|
// Apply new name if it changed.
|
||||||
if p.Name != newName {
|
if profile.Name != newName {
|
||||||
p.Name = newName
|
profile.Name = newName
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue