diff --git a/HelperService/ConnectionOwnerLookup.swift b/HelperService/ConnectionOwnerLookup.swift index c894f2c..dddafd2 100644 --- a/HelperService/ConnectionOwnerLookup.swift +++ b/HelperService/ConnectionOwnerLookup.swift @@ -1,9 +1,5 @@ -import Darwin import Foundation -import os - -private let PROC_PIDPATHINFO_MAXSIZE: Int32 = 4096 -private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "ConnectionOwnerLookup") +import Libbox enum ConnectionOwnerLookup { struct Result { @@ -19,173 +15,21 @@ enum ConnectionOwnerLookup { destinationAddress: String, destinationPort: Int32 ) -> Result? { - let sourceAddr = parseAddress(sourceAddress) - let destAddr = parseAddress(destinationAddress) - - guard let sourceAddr, let destAddr else { - logger.error("find: failed to parse addresses") + var error: NSError? + guard let result = LibboxFindConnectionOwner( + ipProtocol, + sourceAddress, + sourcePort, + destinationAddress, + destinationPort, + &error + ) else { return nil } - - let pidCount = proc_listpids(UInt32(PROC_ALL_PIDS), 0, nil, 0) - guard pidCount > 0 else { - logger.error("find: no processes found") - return nil - } - - let pidBufferSize = Int(pidCount) * MemoryLayout.size - let pids = UnsafeMutablePointer.allocate(capacity: Int(pidCount)) - defer { pids.deallocate() } - - let actualCount = proc_listpids(UInt32(PROC_ALL_PIDS), 0, pids, Int32(pidBufferSize)) - guard actualCount > 0 else { - logger.error("find: failed to list processes") - return nil - } - - let numPids = Int(actualCount) / MemoryLayout.size - - for i in 0 ..< numPids { - let pid = pids[i] - if pid == 0 { continue } - - if let result = checkProcessForConnection( - pid: pid, - ipProtocol: ipProtocol, - sourceAddr: sourceAddr, - sourcePort: UInt16(sourcePort), - destAddr: destAddr, - destPort: UInt16(destinationPort) - ) { - return result - } - } - - return nil - } - - private static func checkProcessForConnection( - pid: pid_t, - ipProtocol: Int32, - sourceAddr: Data, - sourcePort: UInt16, - destAddr: Data, - destPort: UInt16 - ) -> Result? { - let bufferSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, nil, 0) - guard bufferSize > 0 else { return nil } - - let fdBuffer = UnsafeMutableRawPointer.allocate(byteCount: Int(bufferSize), alignment: MemoryLayout.alignment) - defer { fdBuffer.deallocate() } - - let actualSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdBuffer, bufferSize) - guard actualSize > 0 else { return nil } - - let fdCount = Int(actualSize) / MemoryLayout.size - - for i in 0 ..< fdCount { - let fd = fdBuffer.load(fromByteOffset: i * MemoryLayout.size, as: proc_fdinfo.self) - - guard fd.proc_fdtype == PROX_FDTYPE_SOCKET else { continue } - - var socketInfo = socket_fdinfo() - let socketInfoSize = Int32(MemoryLayout.size) - - let result = proc_pidfdinfo(pid, fd.proc_fd, PROC_PIDFDSOCKETINFO, &socketInfo, socketInfoSize) - guard result == socketInfoSize else { continue } - - let soi: in_sockinfo - if ipProtocol == IPPROTO_TCP { - guard socketInfo.psi.soi_kind == SOCKINFO_TCP else { continue } - soi = socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini - } else if ipProtocol == IPPROTO_UDP { - guard socketInfo.psi.soi_kind == SOCKINFO_IN else { continue } - soi = socketInfo.psi.soi_proto.pri_in - } else { - continue - } - - if matchesConnection( - socketInfo: soi, - sourceAddr: sourceAddr, - sourcePort: sourcePort, - destAddr: destAddr, - destPort: destPort - ) { - return getProcessInfo(pid: pid) - } - } - - return nil - } - - private static func matchesConnection( - socketInfo: in_sockinfo, - sourceAddr: Data, - sourcePort: UInt16, - destAddr: Data, - destPort: UInt16 - ) -> Bool { - let localPort = UInt16(bigEndian: UInt16(truncatingIfNeeded: socketInfo.insi_lport)) - let remotePort = UInt16(bigEndian: UInt16(truncatingIfNeeded: socketInfo.insi_fport)) - - guard localPort == sourcePort, remotePort == destPort else { - return false - } - - var localAddr = socketInfo.insi_laddr - var remoteAddr = socketInfo.insi_faddr - - let localData: Data - let remoteData: Data - - if sourceAddr.count == 4 { - localData = Data(bytes: &localAddr.ina_46.i46a_addr4, count: 4) - remoteData = Data(bytes: &remoteAddr.ina_46.i46a_addr4, count: 4) - } else { - localData = Data(bytes: &localAddr.ina_6, count: 16) - remoteData = Data(bytes: &remoteAddr.ina_6, count: 16) - } - - return localData == sourceAddr && remoteData == destAddr - } - - private static func getProcessInfo(pid: pid_t) -> Result? { - let pathBuffer = UnsafeMutablePointer.allocate(capacity: Int(PROC_PIDPATHINFO_MAXSIZE)) - defer { pathBuffer.deallocate() } - - let pathLength = proc_pidpath(pid, pathBuffer, UInt32(PROC_PIDPATHINFO_MAXSIZE)) - let processPath = pathLength > 0 ? String(cString: pathBuffer) : "" - - var info = proc_bsdinfo() - let infoSize = Int32(MemoryLayout.size) - let result = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, infoSize) - - guard result == infoSize else { return nil } - - let uid = Int32(info.pbi_uid) - let userName: String - - if let pw = getpwuid(info.pbi_uid) { - userName = String(cString: pw.pointee.pw_name) - } else { - userName = String(uid) - } - - return Result(userId: uid, userName: userName, processPath: processPath) - } - - private static func parseAddress(_ address: String) -> Data? { - var addr4 = in_addr() - if inet_pton(AF_INET, address, &addr4) == 1 { - return Data(bytes: &addr4, count: 4) - } - - var addr6 = in6_addr() - if inet_pton(AF_INET6, address, &addr6) == 1 { - return Data(bytes: &addr6, count: 16) - } - - return nil + return Result( + userId: result.userId, + userName: result.userName, + processPath: result.processPath + ) } }