import Foundation import Darwin import NetworkExtension enum TunFileDescriptor { /// Locate the utun socket used by NEPacketTunnelProvider (unsupported but widely used). static func find() -> Int32? { if let fd = packetFlowKVO() { return fd } return findUtunByGetsockopt() } private static func packetFlowKVO() -> Int32? { // Caller may set via associated object; left for PacketTunnelProvider to try first. nil } private static func findUtunByGetsockopt() -> Int32? { var buf = [CChar](repeating: 0, count: Int(IFNAMSIZ)) let prefix = Array("utun".utf8CString.dropLast()) for fd: Int32 in 0...1024 { var len = socklen_t(buf.count) // SOL_LOCAL=0 / SYSPROTO_CONTROL path varies; use getsockopt(fd, 2, 2) like WireGuard/others. if getsockopt(fd, 2, 2, &buf, &len) == 0 { if buf.starts(with: prefix) { return fd } } } return nil } } extension NEPacketTunnelProvider { func resolveTunnelFileDescriptor() -> Int32? { if let fd = packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32, fd >= 0 { return fd } return TunFileDescriptor.find() } }