diff --git a/macos-redirector/ipc/utils.swift b/macos-redirector/ipc/utils.swift index b570b727..e4fbf367 100644 --- a/macos-redirector/ipc/utils.swift +++ b/macos-redirector/ipc/utils.swift @@ -9,7 +9,7 @@ enum IpcError: Error { func readIpcMessage(ofType: T.Type, fh: FileHandle) throws -> T? { // read u32 - guard let len_buf = try FileHandle.standardInput.read(upToCount: 4) else { throw IpcError.emptyRead } + guard let len_buf = try fh.read(upToCount: 4) else { throw IpcError.emptyRead } guard len_buf.count == 4 else { throw IpcError.incompleteRead } let len = len_buf[...].reduce(Int(0)) { $0 << 8 + Int($1) }; // 4x \n (testing) @@ -18,7 +18,15 @@ func readIpcMessage(ofType: T.Type, fh: FileHandle) th } guard len < 1024 * 1024 else { throw IpcError.tooLarge(len) } // read protobuf data - guard let data = try FileHandle.standardInput.read(upToCount: len) else { throw IpcError.incompleteRead } + guard let data = try fh.read(upToCount: len) else { throw IpcError.incompleteRead } // decode protobuf return try T(contiguousBytes: data) } + + +func writeIpcMessage(message: SwiftProtobuf.Message, fh: FileHandle) throws { + let data = try message.serializedData() + let len = withUnsafeBytes(of: UInt32(data.count).bigEndian, Array.init) + try fh.write(contentsOf: len) + try fh.write(contentsOf: data) +} diff --git a/macos-redirector/macos-redirector/app.swift b/macos-redirector/macos-redirector/app.swift index f65e1ad3..5e6b3ff6 100644 --- a/macos-redirector/macos-redirector/app.swift +++ b/macos-redirector/macos-redirector/app.swift @@ -22,7 +22,6 @@ struct App { while let spec = try readIpcMessage(ofType: Mitmproxy_Ipc_InterceptSpec.self, fh: FileHandle.standardInput) { log.debug("received intercept spec: \(spec.spec)") - guard !spec.spec.starts(with: "!") else { log.error("inverse specs are not implemented yet.") continue @@ -97,9 +96,8 @@ func startVPN() async throws -> NETunnelProviderManager { let providerProtocol = NETunnelProviderProtocol() providerProtocol.providerBundleIdentifier = networkExtensionIdentifier - // TODO: Use either of these to signal pipes. - //providerProtocol.providerConfiguration = ["server": "127.0.0.1", "port": 1234] - providerProtocol.serverAddress = "mitmproxy" + providerProtocol.serverAddress = "/tmp/mitmproxy-123" + // XXX: it's unclear if these are actually necessary for per-app VPNs providerProtocol.enforceRoutes = true providerProtocol.includeAllNetworks = true diff --git a/macos-redirector/network-extension/PacketTunnelProvider.swift b/macos-redirector/network-extension/PacketTunnelProvider.swift index fedb7526..5864ac4a 100644 --- a/macos-redirector/network-extension/PacketTunnelProvider.swift +++ b/macos-redirector/network-extension/PacketTunnelProvider.swift @@ -1,52 +1,83 @@ import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider { - - var t: Task? override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { - log.debug("startTunnel options=\(String(describing:options), privacy: .public)") + log.debug("startTunnel") + + let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "10.0.0.42") + let ipv4Settings = NEIPv4Settings(addresses: ["10.0.0.1"], subnetMasks: ["255.255.255.0"]) + ipv4Settings.includedRoutes = [ + NEIPv4Route.default() + ] + tunnelNetworkSettings.ipv4Settings = ipv4Settings + tunnelNetworkSettings.dnsSettings = NEDNSSettings(servers: ["10.0.0.53"]) + + let addr = self.protocolConfiguration.serverAddress! - self.t = Task { - - log.debug("setting network settings") - - let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "10.0.0.42") - - let ipv4Settings = NEIPv4Settings(addresses: ["10.0.0.1"], subnetMasks: ["255.255.255.0"]) - ipv4Settings.includedRoutes = [ - NEIPv4Route.default() - ] - tunnelNetworkSettings.ipv4Settings = ipv4Settings - - tunnelNetworkSettings.dnsSettings = NEDNSSettings(servers: ["10.0.0.53"]) - - do { - try await self.setTunnelNetworkSettings(tunnelNetworkSettings) - } catch let error { - completionHandler(error) - throw error + let proxy_file: FileHandle, redir_file: FileHandle + do { + proxy_file = try FileHandle(forReadingFrom: URL(fileURLWithPath: "\(addr).proxy")); + redir_file = try FileHandle(forWritingTo: URL(fileURLWithPath: "\(addr).redir")) + } catch { + return completionHandler(error) + } + + self.setTunnelNetworkSettings(tunnelNetworkSettings) { err in + completionHandler(err) + log.debug("tunnel settings set (err=\(err))") + if err == nil { + self.redirectPackets(redir_file) + self.reinjectPackets(proxy_file) } - - completionHandler(nil) - - while !Task.isCancelled { - log.debug("reading packet objects...") - let packets = await self.packetFlow.readPacketObjects(); - for packet in packets { - log.debug("received packet: \(packet, privacy: .public)") + } + + log.debug("startTunnel done") + } + + func redirectPackets(_ wfile: FileHandle) { + log.debug("redirecting packets to \(wfile, privacy: .public)...") + self.packetFlow.readPacketObjects { packets in + for packet in packets { + + var message = Mitmproxy_Ipc_FromRedirector() + message.packet.data = packet.data + message.packet.pid = 0 // TODO + message.packet.processName = packet.metadata!.sourceAppSigningIdentifier + + do { + try writeIpcMessage(message: message, fh: wfile) + } catch { + log.error("redirectPackets errored: \(error)") + exit(1) } + self.redirectPackets(wfile) } - log.debug("packet task cancelled") } - log.debug("startTunnel done") + } + + func reinjectPackets(_ rfile: FileHandle) { + log.debug("reading \(rfile, privacy: .public)...") + do { + while let packet = try readIpcMessage(ofType: Mitmproxy_Ipc_Packet.self, fh: rfile) { + + log.debug("reinjecting packet...") + self.packetFlow.writePackets([packet.data], withProtocols: [AF_INET as NSNumber]) + + } + } catch { + log.error("redirectPackets errored: \(error)") + exit(1) + } + + log.debug("exiting...") + exit(0) } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { log.debug("stopTunnel \(String(describing:reason))") - self.t?.cancel() completionHandler() - log.debug("stopTunnel done") + exit(0) // XXX: is that a reasonable approach to tear things down? } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {