Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased: mitmproxy_rs next

- Fix a bug where macOS local capture mode wouldn't clean up connections and stop working after a while.
The changes may break half-closed TCP streams.
- tun mode: allow using a pre-configured persistent tun interface, to avoid requiring CAP_NET_ADMIN.

## 29 April 2025: mitmproxy_rs 0.12.3
Expand Down
30 changes: 20 additions & 10 deletions mitmproxy-macos/redirector/network-extension/FlowExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ extension NEAppProxyTCPFlow {
self.outboundCopier(conn)
} else {
// log.debug("outbound copier: error copying: \(String(describing: error), privacy: .public)")
self.closeConnection(conn, error)
}
}))
} else {
log.debug(
"outbound copier end: \(String(describing: data), privacy: .public) \(String(describing: error), privacy: .public)"
)
conn.send(content: nil, isComplete: true, completion: .contentProcessed({ error in
conn.cancel()
// log.debug("outbound copier: sent end.")
self.closeConnection(conn, error)
}))
self.closeWriteWithError(error)
}
}
}
Expand All @@ -40,12 +40,14 @@ extension NEAppProxyTCPFlow {
self.write(data) { error in
if error == nil {
self.inboundCopier(conn)
} else {
self.closeConnection(conn, error)
}
}
case (_, true, _):
self.closeReadWithError(error)
self.closeConnection(conn, error)
default:
self.closeReadWithError(error)
self.closeConnection(conn, error)
log.info(
"inbound copier error=\(String(describing: error), privacy: .public) isComplete=\(String(describing: isComplete), privacy: .public)"
)
Expand All @@ -61,8 +63,9 @@ extension NEAppProxyUDPFlow {
func readDatagrams() async throws -> ([Data], [NetworkExtension.NWEndpoint]) {
return try await withCheckedThrowingContinuation { continuation in
readDatagrams { datagrams, endpoints, error in
if let error = error {
if let error {
continuation.resume(throwing: error)
return
}
guard let datagrams = datagrams, let endpoints = endpoints else {
fatalError("No error, but also no datagrams")
Expand Down Expand Up @@ -94,10 +97,10 @@ extension NEAppProxyUDPFlow {
try await conn.send(ipc: message)
}
}
self.closeConnection(conn, nil)
} catch {
log.error("Error in outbound UDP copier: \(String(describing: error), privacy: .public)")
self.closeWriteWithError(error)
conn.cancel()
self.closeConnection(conn, error)
}
}
}
Expand All @@ -108,18 +111,25 @@ extension NEAppProxyUDPFlow {
while true {
// log.debug("UDP inbound: receiving...")
guard let packet = try await conn.receive(ipc: MitmproxyIpc_UdpPacket.self) else {
self.closeReadWithError(nil)
break
}
// log.debug("UDP inbound: received packet.: \(String(describing: packet), privacy: .public)")
let endpoint = NWHostEndpoint(address: packet.remoteAddress)
try await self.writeDatagrams([packet.data], sentBy: [endpoint])
}
self.closeConnection(conn, nil)
} catch {
log.error("Error in inbound UDP copier: \(String(describing: error), privacy: .public)")
self.closeReadWithError(error)
conn.cancel()
self.closeConnection(conn, error)
}
}
}
}

extension NEAppProxyFlow {
func closeConnection(_ conn: NWConnection, _ error: Error?) {
conn.cancel()
self.closeReadWithError(error)
self.closeWriteWithError(error)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ class TransparentProxyProvider: NETransparentProxyProvider {
switch state {
case .failed(.posix(.ENETDOWN)):
log.debug("control channel closed, stopping proxy.")
control.forceCancel()
self.cancelProxyWithError(.none)
case .failed(let err):
log.error("control channel failed: \(err, privacy: .public)")
control.forceCancel()
self.cancelProxyWithError(err)
default:
break
Expand All @@ -48,6 +50,7 @@ class TransparentProxyProvider: NETransparentProxyProvider {
}
} catch {
log.error("Error on control channel: \(String(describing: error), privacy: .public)")
control.forceCancel()
self.cancelProxyWithError(error)
}
}
Expand Down
Loading