mirror of
https://github.com/safing/portmaster
synced 2025-09-05 03:59:11 +00:00
Merge pull request #39 from safing/feature/unidentified-process-and-profile
Add support for unidentified processes and profiles
This commit is contained in:
commit
1f90c05654
25 changed files with 336 additions and 140 deletions
|
@ -18,7 +18,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
modules.Register("base", nil, registerDatabases, nil, "database", "config", "random")
|
modules.Register("base", nil, registerDatabases, nil, "database", "config", "rng")
|
||||||
|
|
||||||
module = modules.Register("core", nil, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui")
|
module = modules.Register("core", nil, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui")
|
||||||
subsystems.Register(
|
subsystems.Register(
|
||||||
|
|
|
@ -233,6 +233,7 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
|
||||||
if ps.isMe {
|
if ps.isMe {
|
||||||
// approve
|
// approve
|
||||||
conn.Accept("internally approved")
|
conn.Accept("internally approved")
|
||||||
|
conn.Internal = true
|
||||||
// finish
|
// finish
|
||||||
conn.StopFirewallHandler()
|
conn.StopFirewallHandler()
|
||||||
issueVerdict(conn, pkt, 0, true)
|
issueVerdict(conn, pkt, 0, true)
|
||||||
|
|
|
@ -50,6 +50,7 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint:
|
||||||
if conn.Process().Pid == os.Getpid() {
|
if conn.Process().Pid == os.Getpid() {
|
||||||
log.Infof("filter: granting own connection %s", conn)
|
log.Infof("filter: granting own connection %s", conn)
|
||||||
conn.Verdict = network.VerdictAccept
|
conn.Verdict = network.VerdictAccept
|
||||||
|
conn.Internal = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint:
|
||||||
log.Warningf("filter: failed to find load local peer process with PID %d: %s", otherPid, err)
|
log.Warningf("filter: failed to find load local peer process with PID %d: %s", otherPid, err)
|
||||||
} else if otherProcess.Pid == conn.Process().Pid {
|
} else if otherProcess.Pid == conn.Process().Pid {
|
||||||
conn.Accept("connection to self")
|
conn.Accept("connection to self")
|
||||||
|
conn.Internal = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// TODO: this has been obsoleted due to special profiles
|
||||||
if conn.Process().Profile() == nil {
|
if conn.Process().Profile() == nil {
|
||||||
tracer.Infof("nameserver: failed to find process for request %s, returning NXDOMAIN", conn)
|
tracer.Infof("nameserver: failed to find process for request %s, returning NXDOMAIN", conn)
|
||||||
returnNXDomain(w, query)
|
returnNXDomain(w, query)
|
||||||
|
|
|
@ -57,8 +57,7 @@ func cleanConnections() (activePIDs map[int]struct{}) {
|
||||||
// Step 2: mark end
|
// Step 2: mark end
|
||||||
activePIDs[conn.process.Pid] = struct{}{}
|
activePIDs[conn.process.Pid] = struct{}{}
|
||||||
conn.Ended = now
|
conn.Ended = now
|
||||||
// "save"
|
conn.Save()
|
||||||
dbController.PushUpdate(conn)
|
|
||||||
}
|
}
|
||||||
case conn.Ended < deleteOlderThan:
|
case conn.Ended < deleteOlderThan:
|
||||||
// Step 3: delete
|
// Step 3: delete
|
||||||
|
|
|
@ -41,6 +41,7 @@ type Connection struct { //nolint:maligned // TODO: fix alignment
|
||||||
VerdictPermanent bool
|
VerdictPermanent bool
|
||||||
Inspecting bool
|
Inspecting bool
|
||||||
Encrypted bool // TODO
|
Encrypted bool // TODO
|
||||||
|
Internal bool // Portmaster internal connections are marked in order to easily filter these out in the UI
|
||||||
|
|
||||||
pktQueue chan packet.Packet
|
pktQueue chan packet.Packet
|
||||||
firewallHandler FirewallHandler
|
firewallHandler FirewallHandler
|
||||||
|
@ -58,7 +59,7 @@ func NewConnectionFromDNSRequest(ctx context.Context, fqdn string, ip net.IP, po
|
||||||
proc, err := process.GetProcessByEndpoints(ctx, ip, port, dnsAddress, dnsPort, packet.UDP)
|
proc, err := process.GetProcessByEndpoints(ctx, ip, port, dnsAddress, dnsPort, packet.UDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("network: failed to find process of dns request for %s: %s", fqdn, err)
|
log.Warningf("network: failed to find process of dns request for %s: %s", fqdn, err)
|
||||||
proc = process.UnknownProcess
|
proc = process.GetUnidentifiedProcess(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := time.Now().Unix()
|
timestamp := time.Now().Unix()
|
||||||
|
@ -80,7 +81,7 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
|
||||||
proc, inbound, err := process.GetProcessByPacket(pkt)
|
proc, inbound, err := process.GetProcessByPacket(pkt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("network: failed to find process of packet %s: %s", pkt, err)
|
log.Warningf("network: failed to find process of packet %s: %s", pkt, err)
|
||||||
proc = process.UnknownProcess
|
proc = process.GetUnidentifiedProcess(pkt.Ctx())
|
||||||
}
|
}
|
||||||
|
|
||||||
var scope string
|
var scope string
|
||||||
|
@ -229,39 +230,31 @@ func (conn *Connection) SaveWhenFinished() {
|
||||||
|
|
||||||
// Save saves the connection in the storage and propagates the change through the database system.
|
// Save saves the connection in the storage and propagates the change through the database system.
|
||||||
func (conn *Connection) Save() {
|
func (conn *Connection) Save() {
|
||||||
if conn.ID == "" {
|
conn.UpdateMeta()
|
||||||
|
|
||||||
// dns request
|
if !conn.KeyIsSet() {
|
||||||
if !conn.KeyIsSet() {
|
if conn.ID == "" {
|
||||||
|
// dns request
|
||||||
|
|
||||||
|
// set key
|
||||||
conn.SetKey(fmt.Sprintf("network:tree/%d/%s", conn.process.Pid, conn.Scope))
|
conn.SetKey(fmt.Sprintf("network:tree/%d/%s", conn.process.Pid, conn.Scope))
|
||||||
conn.UpdateMeta()
|
mapKey := strconv.Itoa(conn.process.Pid) + "/" + conn.Scope
|
||||||
}
|
|
||||||
// save to internal state
|
// save
|
||||||
// check if it already exists
|
dnsConnsLock.Lock()
|
||||||
mapKey := strconv.Itoa(conn.process.Pid) + "/" + conn.Scope
|
|
||||||
dnsConnsLock.Lock()
|
|
||||||
_, ok := dnsConns[mapKey]
|
|
||||||
if !ok {
|
|
||||||
dnsConns[mapKey] = conn
|
dnsConns[mapKey] = conn
|
||||||
}
|
dnsConnsLock.Unlock()
|
||||||
dnsConnsLock.Unlock()
|
} else {
|
||||||
|
// network connection
|
||||||
|
|
||||||
} else {
|
// set key
|
||||||
|
|
||||||
// connection
|
|
||||||
if !conn.KeyIsSet() {
|
|
||||||
conn.SetKey(fmt.Sprintf("network:tree/%d/%s/%s", conn.process.Pid, conn.Scope, conn.ID))
|
conn.SetKey(fmt.Sprintf("network:tree/%d/%s/%s", conn.process.Pid, conn.Scope, conn.ID))
|
||||||
conn.UpdateMeta()
|
|
||||||
}
|
|
||||||
// save to internal state
|
|
||||||
// check if it already exists
|
|
||||||
connsLock.Lock()
|
|
||||||
_, ok := conns[conn.ID]
|
|
||||||
if !ok {
|
|
||||||
conns[conn.ID] = conn
|
|
||||||
}
|
|
||||||
connsLock.Unlock()
|
|
||||||
|
|
||||||
|
// save
|
||||||
|
connsLock.Lock()
|
||||||
|
conns[conn.ID] = conn
|
||||||
|
connsLock.Unlock()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify database controller
|
// notify database controller
|
||||||
|
@ -270,7 +263,11 @@ func (conn *Connection) Save() {
|
||||||
|
|
||||||
// delete deletes a link from the storage and propagates the change. Nothing is locked - both the conns map and the connection itself require locking
|
// delete deletes a link from the storage and propagates the change. Nothing is locked - both the conns map and the connection itself require locking
|
||||||
func (conn *Connection) delete() {
|
func (conn *Connection) delete() {
|
||||||
delete(conns, conn.ID)
|
if conn.ID == "" {
|
||||||
|
delete(dnsConns, strconv.Itoa(conn.process.Pid)+"/"+conn.Scope)
|
||||||
|
} else {
|
||||||
|
delete(conns, conn.ID)
|
||||||
|
}
|
||||||
|
|
||||||
conn.Meta().Delete()
|
conn.Meta().Delete()
|
||||||
dbController.PushUpdate(conn)
|
dbController.PushUpdate(conn)
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
||||||
if slashes <= 1 {
|
if slashes <= 1 {
|
||||||
// processes
|
// processes
|
||||||
for _, proc := range process.All() {
|
for _, proc := range process.All() {
|
||||||
if strings.HasPrefix(proc.DatabaseKey(), q.DatabaseKeyPrefix()) {
|
if q.Matches(proc) {
|
||||||
it.Next <- proc
|
it.Next <- proc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,9 +86,9 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
||||||
if slashes <= 2 {
|
if slashes <= 2 {
|
||||||
// dns scopes only
|
// dns scopes only
|
||||||
dnsConnsLock.RLock()
|
dnsConnsLock.RLock()
|
||||||
for _, dnsConns := range dnsConns {
|
for _, dnsConn := range dnsConns {
|
||||||
if strings.HasPrefix(dnsConns.DatabaseKey(), q.DatabaseKeyPrefix()) {
|
if q.Matches(dnsConn) {
|
||||||
it.Next <- dnsConns
|
it.Next <- dnsConn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dnsConnsLock.RUnlock()
|
dnsConnsLock.RUnlock()
|
||||||
|
@ -98,7 +98,7 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
||||||
// connections
|
// connections
|
||||||
connsLock.RLock()
|
connsLock.RLock()
|
||||||
for _, conn := range conns {
|
for _, conn := range conns {
|
||||||
if strings.HasPrefix(conn.DatabaseKey(), q.DatabaseKeyPrefix()) {
|
if q.Matches(conn) {
|
||||||
it.Next <- conn
|
it.Next <- conn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/safing/portmaster/process"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,6 +18,9 @@ var (
|
||||||
|
|
||||||
// duration after which DNS requests without a following connection are logged
|
// duration after which DNS requests without a following connection are logged
|
||||||
openDNSRequestLimit = 3 * time.Second
|
openDNSRequestLimit = 3 * time.Second
|
||||||
|
|
||||||
|
// scope prefix
|
||||||
|
unidentifiedProcessScopePrefix = strconv.Itoa(process.UnidentifiedProcessID) + "/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func removeOpenDNSRequest(pid int, fqdn string) {
|
func removeOpenDNSRequest(pid int, fqdn string) {
|
||||||
|
@ -23,7 +28,13 @@ func removeOpenDNSRequest(pid int, fqdn string) {
|
||||||
defer openDNSRequestsLock.Unlock()
|
defer openDNSRequestsLock.Unlock()
|
||||||
|
|
||||||
key := strconv.Itoa(pid) + "/" + fqdn
|
key := strconv.Itoa(pid) + "/" + fqdn
|
||||||
delete(openDNSRequests, key)
|
_, ok := openDNSRequests[key]
|
||||||
|
if ok {
|
||||||
|
delete(openDNSRequests, key)
|
||||||
|
} else if pid != process.UnidentifiedProcessID {
|
||||||
|
// check if there is an open dns request from an unidentified process
|
||||||
|
delete(openDNSRequests, unidentifiedProcessScopePrefix+fqdn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveOpenDNSRequest saves a dns request connection that was allowed to proceed.
|
// SaveOpenDNSRequest saves a dns request connection that was allowed to proceed.
|
||||||
|
|
|
@ -53,16 +53,13 @@ func (p *Process) Save() {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
|
|
||||||
|
p.UpdateMeta()
|
||||||
|
|
||||||
if !p.KeyIsSet() {
|
if !p.KeyIsSet() {
|
||||||
|
// set key
|
||||||
p.SetKey(fmt.Sprintf("%s/%d", processDatabaseNamespace, p.Pid))
|
p.SetKey(fmt.Sprintf("%s/%d", processDatabaseNamespace, p.Pid))
|
||||||
p.CreateMeta()
|
|
||||||
}
|
|
||||||
|
|
||||||
processesLock.RLock()
|
// save
|
||||||
_, ok := processes[p.Pid]
|
|
||||||
processesLock.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
processesLock.Lock()
|
processesLock.Lock()
|
||||||
processes[p.Pid] = p
|
processes[p.Pid] = p
|
||||||
processesLock.Unlock()
|
processesLock.Unlock()
|
||||||
|
@ -113,7 +110,9 @@ func CleanProcessStorage(activePIDs map[int]struct{}) {
|
||||||
|
|
||||||
_, active := activePIDs[p.Pid]
|
_, active := activePIDs[p.Pid]
|
||||||
switch {
|
switch {
|
||||||
case p.Pid <= 0:
|
case p.Pid == UnidentifiedProcessID:
|
||||||
|
// internal
|
||||||
|
case p.Pid == SystemProcessID:
|
||||||
// internal
|
// internal
|
||||||
case active:
|
case active:
|
||||||
// process in system process table or recently seen on the network
|
// process in system process table or recently seen on the network
|
||||||
|
|
|
@ -49,7 +49,7 @@ func GetPidByPacket(pkt packet.Packet) (pid int, direction bool, err error) {
|
||||||
case pkt.Info().Protocol == packet.UDP && pkt.Info().Version == packet.IPv6:
|
case pkt.Info().Protocol == packet.UDP && pkt.Info().Version == packet.IPv6:
|
||||||
return getUDP6PacketInfo(localIP, localPort, remoteIP, remotePort, pkt.IsInbound())
|
return getUDP6PacketInfo(localIP, localPort, remoteIP, remotePort, pkt.IsInbound())
|
||||||
default:
|
default:
|
||||||
return -1, false, errors.New("unsupported protocol for finding process")
|
return UnidentifiedProcessID, false, errors.New("unsupported protocol for finding process")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ func GetPidByPacket(pkt packet.Packet) (pid int, direction bool, err error) {
|
||||||
func GetProcessByPacket(pkt packet.Packet) (process *Process, direction bool, err error) {
|
func GetProcessByPacket(pkt packet.Packet) (process *Process, direction bool, err error) {
|
||||||
if !enableProcessDetection() {
|
if !enableProcessDetection() {
|
||||||
log.Tracer(pkt.Ctx()).Tracef("process: process detection disabled")
|
log.Tracer(pkt.Ctx()).Tracef("process: process detection disabled")
|
||||||
return UnknownProcess, direction, nil
|
return GetUnidentifiedProcess(pkt.Ctx()), pkt.Info().Direction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracer(pkt.Ctx()).Tracef("process: getting process and profile by packet")
|
log.Tracer(pkt.Ctx()).Tracef("process: getting process and profile by packet")
|
||||||
|
@ -107,7 +107,7 @@ func GetPidByEndpoints(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
case protocol == packet.UDP && ipVersion == packet.IPv6:
|
case protocol == packet.UDP && ipVersion == packet.IPv6:
|
||||||
return getUDP6PacketInfo(localIP, localPort, remoteIP, remotePort, false)
|
return getUDP6PacketInfo(localIP, localPort, remoteIP, remotePort, false)
|
||||||
default:
|
default:
|
||||||
return -1, false, errors.New("unsupported protocol for finding process")
|
return UnidentifiedProcessID, false, errors.New("unsupported protocol for finding process")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ func GetPidByEndpoints(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
func GetProcessByEndpoints(ctx context.Context, localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, protocol packet.IPProtocol) (process *Process, err error) {
|
func GetProcessByEndpoints(ctx context.Context, localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, protocol packet.IPProtocol) (process *Process, err error) {
|
||||||
if !enableProcessDetection() {
|
if !enableProcessDetection() {
|
||||||
log.Tracer(ctx).Tracef("process: process detection disabled")
|
log.Tracer(ctx).Tracef("process: process detection disabled")
|
||||||
return UnknownProcess, nil
|
return GetUnidentifiedProcess(ctx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracer(ctx).Tracef("process: getting process and profile by endpoints")
|
log.Tracer(ctx).Tracef("process: getting process and profile by endpoints")
|
||||||
|
|
|
@ -9,6 +9,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
unidentifiedProcessID = -1
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tcp4Connections []*ConnectionEntry
|
tcp4Connections []*ConnectionEntry
|
||||||
tcp4Listeners []*ConnectionEntry
|
tcp4Listeners []*ConnectionEntry
|
||||||
|
@ -55,7 +59,7 @@ func GetTCP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, pktDirection, err
|
return unidentifiedProcessID, pktDirection, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
|
@ -67,7 +71,7 @@ func GetTCP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
time.Sleep(waitTime)
|
time.Sleep(waitTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, pktDirection, nil
|
return unidentifiedProcessID, pktDirection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTCP6PacketInfo returns the pid of the given IPv6/TCP connection.
|
// GetTCP6PacketInfo returns the pid of the given IPv6/TCP connection.
|
||||||
|
@ -91,7 +95,7 @@ func GetTCP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, pktDirection, err
|
return unidentifiedProcessID, pktDirection, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
|
@ -103,7 +107,7 @@ func GetTCP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
time.Sleep(waitTime)
|
time.Sleep(waitTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, pktDirection, nil
|
return unidentifiedProcessID, pktDirection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUDP4PacketInfo returns the pid of the given IPv4/UDP connection.
|
// GetUDP4PacketInfo returns the pid of the given IPv4/UDP connection.
|
||||||
|
@ -127,7 +131,7 @@ func GetUDP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, pktDirection, err
|
return unidentifiedProcessID, pktDirection, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
|
@ -139,7 +143,7 @@ func GetUDP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
time.Sleep(waitTime)
|
time.Sleep(waitTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, pktDirection, nil
|
return unidentifiedProcessID, pktDirection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUDP6PacketInfo returns the pid of the given IPv6/UDP connection.
|
// GetUDP6PacketInfo returns the pid of the given IPv6/UDP connection.
|
||||||
|
@ -163,7 +167,7 @@ func GetUDP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, pktDirection, err
|
return unidentifiedProcessID, pktDirection, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
|
@ -175,7 +179,7 @@ func GetUDP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||||
time.Sleep(waitTime)
|
time.Sleep(waitTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, pktDirection, nil
|
return unidentifiedProcessID, pktDirection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func search(connections, listeners []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16, pktDirection bool) (pid int, direction bool) { //nolint:unparam // TODO: use direction, it may not be used because results caused problems, investigate.
|
func search(connections, listeners []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16, pktDirection bool) (pid int, direction bool) { //nolint:unparam // TODO: use direction, it may not be used because results caused problems, investigate.
|
||||||
|
@ -204,7 +208,7 @@ func search(connections, listeners []*ConnectionEntry, localIP, remoteIP net.IP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, pktDirection
|
return unidentifiedProcessID, pktDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchConnections(list []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16) (pid int) {
|
func searchConnections(list []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16) (pid int) {
|
||||||
|
@ -218,7 +222,7 @@ func searchConnections(list []*ConnectionEntry, localIP, remoteIP net.IP, localP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
return unidentifiedProcessID
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchListeners(list []*ConnectionEntry, localIP net.IP, localPort uint16) (pid int) {
|
func searchListeners(list []*ConnectionEntry, localIP net.IP, localPort uint16) (pid int) {
|
||||||
|
@ -231,7 +235,7 @@ func searchListeners(list []*ConnectionEntry, localIP net.IP, localPort uint16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
return unidentifiedProcessID
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActiveConnectionIDs returns all currently active connection IDs.
|
// GetActiveConnectionIDs returns all currently active connection IDs.
|
||||||
|
|
|
@ -33,7 +33,7 @@ func GetPidOfConnection(localIP net.IP, localPort uint16, protocol uint8) (pid i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, NoSocket
|
return unidentifiedProcessID, NoSocket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ func GetPidOfConnection(localIP net.IP, localPort uint16, protocol uint8) (pid i
|
||||||
pid, ok = GetPidOfInode(uid, inode)
|
pid, ok = GetPidOfInode(uid, inode)
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, NoProcess
|
return unidentifiedProcessID, NoProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -64,7 +64,7 @@ func GetPidOfIncomingConnection(localIP net.IP, localPort uint16, protocol uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, NoSocket
|
return unidentifiedProcessID, NoSocket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func GetPidOfIncomingConnection(localIP net.IP, localPort uint16, protocol uint8
|
||||||
pid, ok = GetPidOfInode(uid, inode)
|
pid, ok = GetPidOfInode(uid, inode)
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, NoProcess
|
return unidentifiedProcessID, NoProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,6 +7,10 @@ import (
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
unidentifiedProcessID = -1
|
||||||
|
)
|
||||||
|
|
||||||
// GetTCP4PacketInfo searches the network state tables for a TCP4 connection
|
// GetTCP4PacketInfo searches the network state tables for a TCP4 connection
|
||||||
func GetTCP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
func GetTCP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
||||||
return search(TCP4, localIP, localPort, pktDirection)
|
return search(TCP4, localIP, localPort, pktDirection)
|
||||||
|
@ -52,11 +56,11 @@ func search(protocol uint8, localIP net.IP, localPort uint16, pktDirection bool)
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case NoSocket:
|
case NoSocket:
|
||||||
return -1, direction, errors.New("could not find socket")
|
return unidentifiedProcessID, direction, errors.New("could not find socket")
|
||||||
case NoProcess:
|
case NoProcess:
|
||||||
return -1, direction, errors.New("could not find PID")
|
return unidentifiedProcessID, direction, errors.New("could not find PID")
|
||||||
default:
|
default:
|
||||||
return -1, direction, nil
|
return unidentifiedProcessID, direction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func GetPidOfInode(uid, inode int) (int, bool) { //nolint:gocognit // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, false
|
return unidentifiedProcessID, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func findSocketFromPid(pid, inode int) bool {
|
func findSocketFromPid(pid, inode int) bool {
|
||||||
|
|
|
@ -100,7 +100,7 @@ func getConnectionSocket(localIP net.IP, localPort uint16, protocol uint8) (int,
|
||||||
socketData, err := os.Open(procFile)
|
socketData, err := os.Open(procFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("process/proc: could not read %s: %s", procFile, err)
|
log.Warningf("process/proc: could not read %s: %s", procFile, err)
|
||||||
return -1, -1, false
|
return unidentifiedProcessID, unidentifiedProcessID, false
|
||||||
}
|
}
|
||||||
defer socketData.Close()
|
defer socketData.Close()
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ func getConnectionSocket(localIP net.IP, localPort uint16, protocol uint8) (int,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, -1, false
|
return unidentifiedProcessID, unidentifiedProcessID, false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ func getListeningSocket(localIP net.IP, localPort uint16, protocol uint8) (uid,
|
||||||
return data[0], data[1], true
|
return data[0], data[1], true
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, -1, false
|
return unidentifiedProcessID, unidentifiedProcessID, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func procDelimiter(c rune) bool {
|
func procDelimiter(c rune) bool {
|
||||||
|
|
|
@ -75,11 +75,11 @@ func (p *Process) String() string {
|
||||||
func GetOrFindPrimaryProcess(ctx context.Context, pid int) (*Process, error) {
|
func GetOrFindPrimaryProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
log.Tracer(ctx).Tracef("process: getting primary process for PID %d", pid)
|
log.Tracer(ctx).Tracef("process: getting primary process for PID %d", pid)
|
||||||
|
|
||||||
if pid == -1 {
|
switch pid {
|
||||||
return UnknownProcess, nil
|
case UnidentifiedProcessID:
|
||||||
}
|
return GetUnidentifiedProcess(ctx), nil
|
||||||
if pid == 0 {
|
case SystemProcessID:
|
||||||
return OSProcess, nil
|
return GetSystemProcess(ctx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
process, err := loadProcess(ctx, pid)
|
process, err := loadProcess(ctx, pid)
|
||||||
|
@ -88,8 +88,8 @@ func GetOrFindPrimaryProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if process.ParentPid == 0 {
|
if process.ParentPid <= 0 {
|
||||||
return OSProcess, nil
|
return process, nil
|
||||||
}
|
}
|
||||||
parentProcess, err := loadProcess(ctx, process.ParentPid)
|
parentProcess, err := loadProcess(ctx, process.ParentPid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -121,11 +121,11 @@ func GetOrFindPrimaryProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
func GetOrFindProcess(ctx context.Context, pid int) (*Process, error) {
|
func GetOrFindProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
log.Tracer(ctx).Tracef("process: getting process for PID %d", pid)
|
log.Tracer(ctx).Tracef("process: getting process for PID %d", pid)
|
||||||
|
|
||||||
if pid == -1 {
|
switch pid {
|
||||||
return UnknownProcess, nil
|
case UnidentifiedProcessID:
|
||||||
}
|
return GetUnidentifiedProcess(ctx), nil
|
||||||
if pid == 0 {
|
case SystemProcessID:
|
||||||
return OSProcess, nil
|
return GetSystemProcess(ctx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := loadProcess(ctx, pid)
|
p, err := loadProcess(ctx, pid)
|
||||||
|
@ -184,11 +184,12 @@ func deduplicateRequest(ctx context.Context, pid int) (finishRequest func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadProcess(ctx context.Context, pid int) (*Process, error) {
|
func loadProcess(ctx context.Context, pid int) (*Process, error) {
|
||||||
if pid == -1 {
|
|
||||||
return UnknownProcess, nil
|
switch pid {
|
||||||
}
|
case UnidentifiedProcessID:
|
||||||
if pid == 0 {
|
return GetUnidentifiedProcess(ctx), nil
|
||||||
return OSProcess, nil
|
case SystemProcessID:
|
||||||
|
return GetSystemProcess(ctx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
process, ok := GetProcessFromStorage(pid)
|
process, ok := GetProcessFromStorage(pid)
|
||||||
|
|
|
@ -15,6 +15,8 @@ func (p *Process) GetProfile(ctx context.Context) error {
|
||||||
// only find profiles if not already done.
|
// only find profiles if not already done.
|
||||||
if p.profile != nil {
|
if p.profile != nil {
|
||||||
log.Tracer(ctx).Trace("process: profile already loaded")
|
log.Tracer(ctx).Trace("process: profile already loaded")
|
||||||
|
// mark profile as used
|
||||||
|
p.profile.MarkUsed()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Tracer(ctx).Trace("process: loading profile")
|
log.Tracer(ctx).Trace("process: loading profile")
|
||||||
|
@ -29,10 +31,8 @@ func (p *Process) GetProfile(ctx context.Context) error {
|
||||||
localProfile.Name = p.ExecName
|
localProfile.Name = p.ExecName
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark as used and save
|
// mark profile as used
|
||||||
if localProfile.MarkUsed() {
|
localProfile.MarkUsed()
|
||||||
_ = localProfile.Save()
|
|
||||||
}
|
|
||||||
|
|
||||||
p.LocalProfileKey = localProfile.Key()
|
p.LocalProfileKey = localProfile.Key()
|
||||||
p.profile = profile.NewLayeredProfile(localProfile)
|
p.profile = profile.NewLayeredProfile(localProfile)
|
||||||
|
|
84
process/special.go
Normal file
84
process/special.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portmaster/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Special Process IDs
|
||||||
|
const (
|
||||||
|
UnidentifiedProcessID = -1
|
||||||
|
SystemProcessID = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// unidentifiedProcess is used when a process cannot be found.
|
||||||
|
unidentifiedProcess = &Process{
|
||||||
|
UserID: UnidentifiedProcessID,
|
||||||
|
UserName: "Unknown",
|
||||||
|
Pid: UnidentifiedProcessID,
|
||||||
|
ParentPid: UnidentifiedProcessID,
|
||||||
|
Name: "Unidentified Processes",
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemProcess is used to represent the Kernel.
|
||||||
|
systemProcess = &Process{
|
||||||
|
UserID: SystemProcessID,
|
||||||
|
UserName: "Kernel",
|
||||||
|
Pid: SystemProcessID,
|
||||||
|
ParentPid: SystemProcessID,
|
||||||
|
Name: "Operating System",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetUnidentifiedProcess returns the special process assigned to unidentified processes.
|
||||||
|
func GetUnidentifiedProcess(ctx context.Context) *Process {
|
||||||
|
return getSpecialProcess(ctx, UnidentifiedProcessID, unidentifiedProcess, profile.GetUnidentifiedProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemProcess returns the special process used for the Kernel.
|
||||||
|
func GetSystemProcess(ctx context.Context) *Process {
|
||||||
|
return getSpecialProcess(ctx, SystemProcessID, systemProcess, profile.GetSystemProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSpecialProcess(ctx context.Context, pid int, template *Process, getProfile func() *profile.Profile) *Process {
|
||||||
|
// check storage
|
||||||
|
p, ok := GetProcessFromStorage(pid)
|
||||||
|
if ok {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign template
|
||||||
|
p = template
|
||||||
|
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
if p.FirstSeen == 0 {
|
||||||
|
p.FirstSeen = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// only find profiles if not already done.
|
||||||
|
if p.profile != nil {
|
||||||
|
log.Tracer(ctx).Trace("process: special profile already loaded")
|
||||||
|
// mark profile as used
|
||||||
|
p.profile.MarkUsed()
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
log.Tracer(ctx).Trace("process: loading special profile")
|
||||||
|
|
||||||
|
// get profile
|
||||||
|
localProfile := getProfile()
|
||||||
|
|
||||||
|
// mark profile as used
|
||||||
|
localProfile.MarkUsed()
|
||||||
|
|
||||||
|
p.LocalProfileKey = localProfile.Key()
|
||||||
|
p.profile = profile.NewLayeredProfile(localProfile)
|
||||||
|
|
||||||
|
go p.Save()
|
||||||
|
return p
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package process
|
|
||||||
|
|
||||||
var (
|
|
||||||
// UnknownProcess is used when a process cannot be found.
|
|
||||||
UnknownProcess = &Process{
|
|
||||||
UserID: -1,
|
|
||||||
UserName: "Unknown",
|
|
||||||
Pid: -1,
|
|
||||||
ParentPid: -1,
|
|
||||||
Name: "Unknown Processes",
|
|
||||||
}
|
|
||||||
|
|
||||||
// OSProcess is used to represent the Kernel.
|
|
||||||
OSProcess = &Process{
|
|
||||||
UserID: 0,
|
|
||||||
UserName: "Kernel",
|
|
||||||
Pid: 0,
|
|
||||||
ParentPid: 0,
|
|
||||||
Name: "Operating System",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
UnknownProcess.Save()
|
|
||||||
OSProcess.Save()
|
|
||||||
}
|
|
|
@ -1,7 +1,14 @@
|
||||||
package profile
|
package profile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
activeProfileCleanerTickDuration = 10 * time.Minute
|
||||||
|
activeProfileCleanerThreshold = 1 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -38,7 +45,34 @@ func markActiveProfileAsOutdated(scopedID string) {
|
||||||
|
|
||||||
profile, ok := activeProfiles[scopedID]
|
profile, ok := activeProfiles[scopedID]
|
||||||
if ok {
|
if ok {
|
||||||
profile.oudated.Set()
|
profile.outdated.Set()
|
||||||
delete(activeProfiles, scopedID)
|
delete(activeProfiles, scopedID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanActiveProfiles(ctx context.Context) error {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(activeProfileCleanerTickDuration):
|
||||||
|
|
||||||
|
threshold := time.Now().Add(-activeProfileCleanerThreshold)
|
||||||
|
|
||||||
|
activeProfilesLock.Lock()
|
||||||
|
for id, profile := range activeProfiles {
|
||||||
|
// get last used
|
||||||
|
profile.Lock()
|
||||||
|
lastUsed := profile.lastUsed
|
||||||
|
profile.Unlock()
|
||||||
|
// remove if not used for a while
|
||||||
|
if lastUsed.Before(threshold) {
|
||||||
|
profile.outdated.Set()
|
||||||
|
delete(activeProfiles, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeProfilesLock.Unlock()
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -70,8 +70,8 @@ func updateGlobalConfigProfile(ctx context.Context, data interface{}) error {
|
||||||
|
|
||||||
// build global profile for reference
|
// build global profile for reference
|
||||||
profile := &Profile{
|
profile := &Profile{
|
||||||
ID: "config",
|
ID: "global-config",
|
||||||
Source: SourceGlobal,
|
Source: SourceSpecial,
|
||||||
Name: "Global Configuration",
|
Name: "Global Configuration",
|
||||||
Config: make(map[string]interface{}),
|
Config: make(map[string]interface{}),
|
||||||
internalSave: true,
|
internalSave: true,
|
||||||
|
|
|
@ -42,6 +42,8 @@ func start() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.StartServiceWorker("clean active profiles", 0, cleanActiveProfiles)
|
||||||
|
|
||||||
err = updateGlobalConfigProfile(module.Ctx, nil)
|
err = updateGlobalConfigProfile(module.Ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("profile: error during loading global profile from configuration: %s", err)
|
log.Warningf("profile: error during loading global profile from configuration: %s", err)
|
||||||
|
|
|
@ -128,7 +128,7 @@ func (lp *LayeredProfile) Update() (revisionCounter uint64) {
|
||||||
|
|
||||||
var changed bool
|
var changed bool
|
||||||
for i, layer := range lp.layers {
|
for i, layer := range lp.layers {
|
||||||
if layer.oudated.IsSet() {
|
if layer.outdated.IsSet() {
|
||||||
changed = true
|
changed = true
|
||||||
// update layer
|
// update layer
|
||||||
newLayer, err := GetProfile(layer.Source, layer.ID)
|
newLayer, err := GetProfile(layer.Source, layer.ID)
|
||||||
|
@ -175,6 +175,11 @@ func (lp *LayeredProfile) updateCaches() {
|
||||||
// TODO: ignore community profiles
|
// TODO: ignore community profiles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkUsed marks the localProfile as used.
|
||||||
|
func (lp *LayeredProfile) MarkUsed() {
|
||||||
|
lp.localProfile.MarkUsed()
|
||||||
|
}
|
||||||
|
|
||||||
// SecurityLevel returns the highest security level of all layered profiles.
|
// SecurityLevel returns the highest security level of all layered profiles.
|
||||||
func (lp *LayeredProfile) SecurityLevel() uint8 {
|
func (lp *LayeredProfile) SecurityLevel() uint8 {
|
||||||
return uint8(atomic.LoadUint32(lp.securityLevel))
|
return uint8(atomic.LoadUint32(lp.securityLevel))
|
||||||
|
|
|
@ -19,15 +19,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lastUsedUpdateThreshold = 1 * time.Hour
|
lastUsedUpdateThreshold = 24 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
// Profile Sources
|
// Profile Sources
|
||||||
const (
|
const (
|
||||||
SourceLocal string = "local"
|
SourceLocal string = "local" // local, editable
|
||||||
|
SourceSpecial string = "special" // specials (read-only)
|
||||||
SourceCommunity string = "community"
|
SourceCommunity string = "community"
|
||||||
SourceEnterprise string = "enterprise"
|
SourceEnterprise string = "enterprise"
|
||||||
SourceGlobal string = "global"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default Action IDs
|
// Default Action IDs
|
||||||
|
@ -77,7 +77,8 @@ type Profile struct { //nolint:maligned // not worth the effort
|
||||||
filterListIDs []string
|
filterListIDs []string
|
||||||
|
|
||||||
// Lifecycle Management
|
// Lifecycle Management
|
||||||
oudated *abool.AtomicBool
|
outdated *abool.AtomicBool
|
||||||
|
lastUsed time.Time
|
||||||
|
|
||||||
// Framework
|
// Framework
|
||||||
// If a Profile is declared as a Framework (i.e. an Interpreter and the likes), then the real process/actor must be found
|
// If a Profile is declared as a Framework (i.e. an Interpreter and the likes), then the real process/actor must be found
|
||||||
|
@ -94,7 +95,7 @@ type Profile struct { //nolint:maligned // not worth the effort
|
||||||
func (profile *Profile) prepConfig() (err error) {
|
func (profile *Profile) prepConfig() (err error) {
|
||||||
// prepare configuration
|
// prepare configuration
|
||||||
profile.configPerspective, err = config.NewPerspective(profile.Config)
|
profile.configPerspective, err = config.NewPerspective(profile.Config)
|
||||||
profile.oudated = abool.New()
|
profile.outdated = abool.New()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,10 +157,11 @@ func (profile *Profile) parseConfig() error {
|
||||||
// New returns a new Profile.
|
// New returns a new Profile.
|
||||||
func New() *Profile {
|
func New() *Profile {
|
||||||
profile := &Profile{
|
profile := &Profile{
|
||||||
ID: uuid.NewV4().String(),
|
ID: uuid.NewV4().String(),
|
||||||
Source: SourceLocal,
|
Source: SourceLocal,
|
||||||
Created: time.Now().Unix(),
|
Created: time.Now().Unix(),
|
||||||
Config: make(map[string]interface{}),
|
Config: make(map[string]interface{}),
|
||||||
|
internalSave: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create placeholders
|
// create placeholders
|
||||||
|
@ -190,13 +192,26 @@ func (profile *Profile) Save() error {
|
||||||
return profileDB.Put(profile)
|
return profileDB.Put(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkUsed marks the profile as used, eventually.
|
// MarkUsed marks the profile as used and saves it when it has changed.
|
||||||
func (profile *Profile) MarkUsed() (updated bool) {
|
func (profile *Profile) MarkUsed() {
|
||||||
|
profile.Lock()
|
||||||
|
// lastUsed
|
||||||
|
profile.lastUsed = time.Now()
|
||||||
|
|
||||||
|
// ApproxLastUsed
|
||||||
|
save := false
|
||||||
if time.Now().Add(-lastUsedUpdateThreshold).Unix() > profile.ApproxLastUsed {
|
if time.Now().Add(-lastUsedUpdateThreshold).Unix() > profile.ApproxLastUsed {
|
||||||
profile.ApproxLastUsed = time.Now().Unix()
|
profile.ApproxLastUsed = time.Now().Unix()
|
||||||
return true
|
save = true
|
||||||
|
}
|
||||||
|
profile.Unlock()
|
||||||
|
|
||||||
|
if save {
|
||||||
|
err := profile.Save()
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("profiles: failed to save profile %s after marking as used: %s", profile.ScopedID(), err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the Profile.
|
// String returns a string representation of the Profile.
|
||||||
|
@ -224,8 +239,6 @@ func (profile *Profile) addEndpointyEntry(cfgKey, newEntry string) {
|
||||||
endpointList = append(endpointList, newEntry)
|
endpointList = append(endpointList, newEntry)
|
||||||
profile.Config[cfgKey] = endpointList
|
profile.Config[cfgKey] = endpointList
|
||||||
|
|
||||||
// save without full reload
|
|
||||||
profile.internalSave = true
|
|
||||||
profile.Unlock()
|
profile.Unlock()
|
||||||
err := profile.Save()
|
err := profile.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -233,10 +246,13 @@ func (profile *Profile) addEndpointyEntry(cfgKey, newEntry string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload manually
|
// reload manually
|
||||||
|
profile.Lock()
|
||||||
|
profile.dataParsed = false
|
||||||
err = profile.parseConfig()
|
err = profile.parseConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("profile: failed to parse profile config after adding endpoint: %s", err)
|
log.Warningf("profile: failed to parse profile config after adding endpoint: %s", err)
|
||||||
}
|
}
|
||||||
|
profile.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProfile loads a profile from the database.
|
// GetProfile loads a profile from the database.
|
||||||
|
@ -249,6 +265,7 @@ func GetProfileByScopedID(scopedID string) (*Profile, error) {
|
||||||
// check cache
|
// check cache
|
||||||
profile := getActiveProfile(scopedID)
|
profile := getActiveProfile(scopedID)
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
|
profile.MarkUsed()
|
||||||
return profile, nil
|
return profile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +283,6 @@ func GetProfileByScopedID(scopedID string) (*Profile, error) {
|
||||||
|
|
||||||
// lock for prepping
|
// lock for prepping
|
||||||
profile.Lock()
|
profile.Lock()
|
||||||
defer profile.Unlock()
|
|
||||||
|
|
||||||
// prepare config
|
// prepare config
|
||||||
err = profile.prepConfig()
|
err = profile.prepConfig()
|
||||||
|
@ -280,7 +296,13 @@ func GetProfileByScopedID(scopedID string) (*Profile, error) {
|
||||||
log.Warningf("profiles: profile %s has (partly) invalid configuration: %s", profile.ID, err)
|
log.Warningf("profiles: profile %s has (partly) invalid configuration: %s", profile.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark as internal
|
||||||
|
profile.internalSave = true
|
||||||
|
|
||||||
|
profile.Unlock()
|
||||||
|
|
||||||
// mark active
|
// mark active
|
||||||
|
profile.MarkUsed()
|
||||||
markProfileActive(profile)
|
markProfileActive(profile)
|
||||||
|
|
||||||
return profile, nil
|
return profile, nil
|
||||||
|
|
56
profile/special.go
Normal file
56
profile/special.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package profile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
unidentifiedProfileID = "_unidentified"
|
||||||
|
systemProfileID = "_system"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetUnidentifiedProfile returns the special profile assigned to unidentified processes.
|
||||||
|
func GetUnidentifiedProfile() *Profile {
|
||||||
|
// get profile
|
||||||
|
profile, err := GetProfile(SourceLocal, unidentifiedProfileID)
|
||||||
|
if err == nil {
|
||||||
|
return profile
|
||||||
|
}
|
||||||
|
|
||||||
|
// create if not available (or error)
|
||||||
|
profile = New()
|
||||||
|
profile.Name = "Unidentified Processes"
|
||||||
|
profile.Source = SourceLocal
|
||||||
|
profile.ID = unidentifiedProfileID
|
||||||
|
|
||||||
|
// save to db
|
||||||
|
err = profile.Save()
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("profiles: failed to save %s: %s", profile.ScopedID(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemProfile returns the special profile used for the Kernel.
|
||||||
|
func GetSystemProfile() *Profile {
|
||||||
|
// get profile
|
||||||
|
profile, err := GetProfile(SourceLocal, systemProfileID)
|
||||||
|
if err == nil {
|
||||||
|
return profile
|
||||||
|
}
|
||||||
|
|
||||||
|
// create if not available (or error)
|
||||||
|
profile = New()
|
||||||
|
profile.Name = "Operating System"
|
||||||
|
profile.Source = SourceLocal
|
||||||
|
profile.ID = systemProfileID
|
||||||
|
|
||||||
|
// save to db
|
||||||
|
err = profile.Save()
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("profiles: failed to save %s: %s", profile.ScopedID(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue