Reduce PID finding retries and simply proc interface on linux

This commit is contained in:
Daniel 2023-12-18 17:03:48 +01:00
parent 6822b7a8a8
commit d67b1e8a64
5 changed files with 24 additions and 72 deletions

View file

@ -7,17 +7,11 @@ import (
"io/fs" "io/fs"
"os" "os"
"strconv" "strconv"
"time"
"github.com/safing/portbase/log" "github.com/safing/portbase/log"
"github.com/safing/portmaster/network/socket" "github.com/safing/portmaster/network/socket"
) )
var (
baseWaitTime = 3 * time.Millisecond
lookupRetries = 3
)
// GetPID returns the already existing pid of the given socket info or searches for it. // GetPID returns the already existing pid of the given socket info or searches for it.
// This also acts as a getter for socket.Info.PID, as locking for that occurs here. // This also acts as a getter for socket.Info.PID, as locking for that occurs here.
func GetPID(socketInfo socket.Info) (pid int) { func GetPID(socketInfo socket.Info) (pid int) {
@ -43,60 +37,27 @@ func GetPID(socketInfo socket.Info) (pid int) {
func findPID(uid, inode int) (pid int) { func findPID(uid, inode int) (pid int) {
socketName := "socket:[" + strconv.Itoa(inode) + "]" socketName := "socket:[" + strconv.Itoa(inode) + "]"
for i := 0; i <= lookupRetries; i++ { // Always update pid table (it has a call limiter anyway)
var pidsUpdated bool updatePids()
// Get all pids for the given uid. // Get all pids for the given uid.
pids, ok := getPidsByUser(uid) pids, ok := getPidsByUser(uid)
if !ok { if !ok {
// If we cannot find the uid in the map, update it. return socket.UndefinedProcessID
updatePids() }
pidsUpdated = true
pids, ok = getPidsByUser(uid)
}
// If we have found PIDs, search them. // Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to
if ok { // be searched for.
// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to for j := len(pids) - 1; j >= 0; j-- {
// be searched for. if pidHasSocket(pids[j], socketName) {
for i := len(pids) - 1; i >= 0; i-- { return pids[j]
if findSocketFromPid(pids[i], socketName) {
return pids[i]
}
}
}
// If we still cannot find our socket, and haven't yet updated the PID map,
// do this and then check again immediately.
if !pidsUpdated {
updatePids()
pids, ok = getPidsByUser(uid)
if ok {
// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to
// be searched for.
for i := len(pids) - 1; i >= 0; i-- {
if findSocketFromPid(pids[i], socketName) {
return pids[i]
}
}
}
}
// We have updated the PID map, but still cannot find anything.
// So, there is nothing we can do other than to wait a little for the kernel to
// populate the information.
// Wait after each try, except for the last iteration
if i < lookupRetries {
// Wait in back-off fashion - with 3ms baseWaitTime: 3, 6, 9 - 18ms in total.
time.Sleep(time.Duration(i+1) * baseWaitTime)
} }
} }
return socket.UndefinedProcessID return socket.UndefinedProcessID
} }
func findSocketFromPid(pid int, socketName string) bool { func pidHasSocket(pid int, socketName string) bool {
socketBase := "/proc/" + strconv.Itoa(pid) + "/fd" socketBase := "/proc/" + strconv.Itoa(pid) + "/fd"
entries := readDirNames(socketBase) entries := readDirNames(socketBase)
if len(entries) == 0 { if len(entries) == 0 {

View file

@ -28,6 +28,11 @@ var (
ErrPIDNotFound = errors.New("could not find pid for socket inode") ErrPIDNotFound = errors.New("could not find pid for socket inode")
) )
const (
lookupTries = 5
fastLookupTries = 2
)
// Lookup looks for the given connection in the system state tables and returns the PID of the associated process and whether the connection is inbound. // Lookup looks for the given connection in the system state tables and returns the PID of the associated process and whether the connection is inbound.
func Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error) { func Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error) {
// auto-detect version // auto-detect version

View file

@ -10,11 +10,6 @@ import (
"github.com/safing/portmaster/network/socket" "github.com/safing/portmaster/network/socket"
) )
var (
lookupTries = 20 // With a max wait of 5ms, this amounts to up to 100ms.
fastLookupTries = 2
)
func init() { func init() {
// This increases performance on unsupported system. // This increases performance on unsupported system.
// It's not critical at all and does not break anything if it fails. // It's not critical at all and does not break anything if it fails.

View file

@ -13,16 +13,14 @@ var (
getUDP4Table = proc.GetUDP4Table getUDP4Table = proc.GetUDP4Table
getUDP6Table = proc.GetUDP6Table getUDP6Table = proc.GetUDP6Table
lookupTries = 20 // With a max wait of 5ms, this amounts to up to 100ms. checkPIDTries = 5
fastLookupTries = 2 checkPIDBaseWaitTime = 5 * time.Millisecond
baseWaitTime = 3 * time.Millisecond
) )
// CheckPID checks the if socket info already has a PID and if not, tries to find it. // CheckPID checks the if socket info already has a PID and if not, tries to find it.
// Depending on the OS, this might be a no-op. // Depending on the OS, this might be a no-op.
func CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) { func CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) {
for i := 1; i <= lookupTries; i++ { for i := 1; i <= checkPIDTries; i++ {
// look for PID // look for PID
pid = proc.GetPID(socketInfo) pid = proc.GetPID(socketInfo)
if pid != socket.UndefinedProcessID { if pid != socket.UndefinedProcessID {
@ -31,10 +29,10 @@ func CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool,
} }
// every time, except for the last iteration // every time, except for the last iteration
if i < lookupTries { if i < checkPIDTries {
// we found no PID, we could have been too fast, give the kernel some time to think // we found no PID, we could have been too fast, give the kernel some time to think
// back off timer: with 3ms baseWaitTime: 3, 6, 9, 12, 15, 18, 21ms - 84ms in total // back off timer: with 5ms baseWaitTime: 5, 10, 15, 20, 25 - 75ms in total
time.Sleep(time.Duration(i+1) * baseWaitTime) time.Sleep(time.Duration(i) * checkPIDBaseWaitTime)
} }
} }

View file

@ -10,13 +10,6 @@ var (
getTCP6Table = iphelper.GetTCP6Table getTCP6Table = iphelper.GetTCP6Table
getUDP4Table = iphelper.GetUDP4Table getUDP4Table = iphelper.GetUDP4Table
getUDP6Table = iphelper.GetUDP6Table getUDP6Table = iphelper.GetUDP6Table
// With a max wait of 5ms, this amounts to up to 25ms,
// excluding potential data fetching time.
// Measured on Windows: ~150ms
lookupTries = 5
fastLookupTries = 2
) )
// CheckPID checks the if socket info already has a PID and if not, tries to find it. // CheckPID checks the if socket info already has a PID and if not, tries to find it.