Files
sing-box-for-apple/HelperService/RootHelperService.swift
T

110 lines
3.6 KiB
Swift

import Foundation
import Library
import os
private let logger = Logger(category: "RootHelper")
class RootHelperService: NSObject {
private var listener: NSXPCListener?
func start() {
setupLogging()
startXPCListener()
}
private func setupLogging() {
let basePath = "/var/log/sing-box"
try? FileManager.default.createDirectory(atPath: basePath, withIntermediateDirectories: true)
let logPath = basePath + "/roothelper.log"
freopen(logPath, "a", stderr)
}
private func startXPCListener() {
let machServiceName = getMachServiceName()
listener = NSXPCListener(machServiceName: machServiceName)
listener?.delegate = self
listener?.resume()
}
private func getMachServiceName() -> String {
if let identifier = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String {
return "\(identifier).helper"
}
fatalError("Missing AppGroupIdentifier in Info.plist")
}
}
extension RootHelperService: NSXPCListenerDelegate {
func listener(_: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
let allowedBundleIDs = [
AppConfiguration.systemExtensionBundleID,
AppConfiguration.packageName + ".standalone",
]
guard XPCConnectionValidator.validateConnection(
newConnection,
teamID: AppConfiguration.teamID,
allowedBundleIDs: allowedBundleIDs
) else {
let info = XPCConnectionValidator.getConnectionInfo(newConnection)
logger.warning("Rejected XPC connection: pid=\(info.pid), bundleID=\(info.bundleID ?? "unknown"), teamID=\(info.teamID ?? "unknown")")
return false
}
let exportedInterface = NSXPCInterface(with: RootHelperProtocol.self)
RootHelperXPC.configureInterface(exportedInterface)
newConnection.exportedInterface = exportedInterface
newConnection.exportedObject = self
newConnection.resume()
return true
}
}
extension RootHelperService: RootHelperProtocol {
func findConnectionOwner(
ipProtocol: Int32,
sourceAddress: String,
sourcePort: Int32,
destinationAddress: String,
destinationPort: Int32,
reply: @escaping (ConnectionOwnerResult?, NSError?) -> Void
) {
guard let result = ConnectionOwnerLookup.find(
ipProtocol: ipProtocol,
sourceAddress: sourceAddress,
sourcePort: sourcePort,
destinationAddress: destinationAddress,
destinationPort: destinationPort
) else {
let error = NSError(domain: "RootHelper", code: -1, userInfo: [
NSLocalizedDescriptionKey: "Connection owner not found",
])
logger.error("findConnectionOwner: \(error.localizedDescription)")
reply(nil, error)
return
}
let ownerResult = ConnectionOwnerResult(
userId: result.userId,
userName: result.userName,
processPath: result.processPath
)
reply(ownerResult, nil)
}
func getWorkingDirectorySize(reply: @escaping (Int64, NSError?) -> Void) {
let size = WorkingDirectoryManager.getSize()
reply(size, nil)
}
func cleanWorkingDirectory(reply: @escaping (NSError?) -> Void) {
do {
try WorkingDirectoryManager.clean()
reply(nil)
} catch {
logger.error("cleanWorkingDirectory error: \(error.localizedDescription)")
reply(error as NSError)
}
}
}