I have some concerns related to shortening the lifetime of certificates, as per
https://support.apple.com/en-gb/102028
Does this apply to Private CA root certificates?
And if yes:
does it apply if I use ATS and higher level API like URLSession
does it apply it I carry my root CA cert in my app payload and use low level libraries without ATS support?
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I've implemented a custom VPN system extension for macOS, utilizing Packet Tunnel Provider.
One of the users reported a problem: he was connected to the VPN, and then his Mac entered sleep mode. Upon waking, the VPN is supposed to connect automatically (because of the on-demand rules).
The VPN's status changed to 'connecting', but it remained stuck in this status.
From my extension logs, I can see that the 'startTunnelWithOption()' function was called 2 minutes after the user clicked the 'connect' button.
From the system logs, I noticed some 'suspicious' logs, but I can't be sure if they are related to the problem. Some of them are:
kernel: (Sandbox) Sandbox: nesessionmanager(562) deny(1) system-fsctl (_IO "h" 47)
entitlement com.apple.developer.endpoint-security.client not present or not true (I don't need this entitlement at the extension)
nesessionmanager: [com.apple.networkextension:] NESMVPNSession[Primary Tunnel:XXXXXX(null)]: Skip a start command from YYYYY:session in state connecting
NetworkExtension.com.***: RunningBoard doesn't recognize submitted process - treating as a anonymous process
sysextd: activateDecision found existing entry of same version: state activated_enabled, ID FAE...
Are any of the logs related to the above problem? How can I debug such issues? What info should I get from the user?
We’ve noticed an issue where after running a network extension, if the phone’s language is changed the Locale.preferredLanguages array is not updated and still returns the old array. It only returns the updated array when the app is reinstalled or the phone is restarted. This is unlike the app itself where using the same Locale.preferredLanguages API immediately returns the updated array.
We think this issue is also the cause of notifications that are sent by the network extension being in the previous language as long as the app isn’t reinstalled or the phone is restarted, despite our Localizable file having localised strings for the new language.
Feedback ID: FB20086051
The feedback report includes a sample project with steps on how to reproduce the issue.
Recently, my application was having trouble sending udp messages after it was reinstalled. The cause of the problem was initially that I did not grant local network permissions when I reinstalled, I was aware of the problem, so udp worked fine after I granted permissions. However, the next time I repeat the previous operation, I also do not grant local network permissions, and then turn it back on in the Settings, and udp does not work properly (no messages can be sent, the system version and code have not changed).
Fortunately, udp worked after rebooting the phone, and more importantly, I was able to repeat the problem many times.
So I want to know if the process between when I re-uninstall the app and deny local network permissions, and when I turn it back on in Settings, is that permissions have been granted normally, and not fake, and not required a reboot to reset something for udp to take effect.
I'm not sure if it's the system, or if it's a similar situation as described here, hopefully that will help me find out
I have been battling this intermittent error for some time. It is generally random and has been difficult to reproduce until yesterday when I stumbled across a way to reproduce it each time. I can cause the code to throw this error:
Task <70E3909F-8C30-4F34-A8B0-4AF3B41DD81B>.<1> finished with error [-1001] Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_kCFStreamErrorCodeKey=-2103, _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDownloadTask <70E3909F-8C30-4F34-A8B0-4AF3B41DD81B>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDownloadTask <70E3909F-8C30-4F34-A8B0-4AF3B41DD81B>.<1>",
"LocalDownloadTask <70E3909F-8C30-4F34-A8B0-4AF3B41DD81B>.<1>"
), NSLocalizedDescription=The request timed out., _kCFStreamErrorDomainKey=4, NSErrorFailingURLStringKey=https://redacted*, NSErrorFailingURLKey=https://redacted*}
*"redacted" is the backend URL, and it is the correct and same path for each
immediately after restarting an actual device. I have been over the following threads with no results:
What is kCFStreamErrorCodeKey=-4 (kCFStreamErrorDomainKey=4)
Request timed out with _kCFStreamErrorCodeKey=60
How to better diagnose -1001 "The request timed out." URLSession errors
Random timed out error on app start
Because I was able to reproduce it, I have been able to get the following logs:
Console Logs.txt
Last bit of information is that I had Network Instruments running, and when this error occurred, I found that the Connection ID was "No Connection" and it appears the request was never actually sent, though it waited the full time out for a backend response.
Any help would be appreciated. This data request is being used after sending a certain APNs to update necessary data in the background, and has been the source of many user complaints.
I’m developing an app designed for hospital environments, where public internet access may not be available. The app includes two components: the main app and a Local Connectivity Extension. Both rely on persistent TCP socket connections to communicate with a local server.
We’re observing a recurring issue where the extension’s socket becomes unresponsive every 1–3 hours, but only when the device is on the lock screen, even if the main app remains in the foreground.
When the screen is not locked, the connection is stable and no disconnections occur.
❗ Issue Details:
• What’s going on: The extension sends a keep-alive ping packet every second, and the server replies with a pong and a system time packet.
• The bug: The server stops receiving keep alive packets from the extension.
• On the server, we detect about 30 second gap on the server, a gap that shows no packets were received by the extension. This was confirmed via server logs and Wireshark).
• On the extension, from our logs there was no gap in sending packets. From it’s perspective, all packets were sent with no error.
• Because no packet are being received by the server, no packets will be sent to the extension. Eventually the server closes the connection due to keep-alive timeout.
• FYI we log when the NEAppPushProvider subclass sleeps and it did NOT go to sleep while we were debugging.
🧾 Example Logs:
Extension log:
2025-03-24 18:34:48.808 sendKeepAliveRequest()
2025-03-24 18:34:49.717 sendKeepAliveRequest()
2025-03-24 18:34:50.692 sendKeepAliveRequest()
... // continuous sending of the ping packet to the server, no problems here
2025-03-24 18:35:55.063 sendKeepAliveRequest()
2025-03-24 18:35:55.063 keepAliveTimer IS TIME OUT... in CoreService. // this is triggered because we did not receive any packets from the server
Server log:
2025-03-24 18:34:16.298 No keep-alive received for 16 seconds... connection ID=95b3... // this shows that there has been no packets being received by the extension
...
2025-03-24 18:34:30.298 Connection timed out on keep-alive. connection ID=95b3... // eventually closes due to no packets being received
2025-03-24 18:34:30.298 Remote Subsystem Disconnected {name=iPhone|Replica-Ext|...}
✅ Observations:
• The extension process continues running and logging keep-alive attempts.
• However, network traffic stops reaching the server, and no inbound packets are received by the extension.
• It looks like the socket becomes silently suspended or frozen, without being properly closed or throwing an error.
❓Questions:
• Do you know why this might happen within a Local Connectivity Extension, especially under foreground conditions and locked ?
• Is there any known system behavior that might cause the socket to be suspended or blocked in this way after running for a few hours?
Any insights or recommendations would be greatly appreciated.
Thank you!
Topic:
App & System Services
SubTopic:
Networking
Question 1: After NetworkExtension is installed, when the software receives a pushed uninstall command, it needs to download the entire software but fails to uninstall this NetworkExtension. Are there any solutions?
Question 2: How can residual, uninstalled NetworkExtensions be cleaned up when SIP (System Integrity Protection) is enabled?
Hi,
I’m using Network Framework to implement a UDP client via NWConnection, and I’m looking for clarification about the correct and fully safe shutdown procedure, especially regarding resource release.
I have initiated some pending receive calls on the NWConnection (using receive). After calling connection.cancel(), do we need to wait for the cancellation of these pending receives?
As mentioned in this thread, NWConnection retains references to the receive closures and releases them once they are called. If a receive closure holds a reference to the NWConnection itself, do we need to wait for these closures to be called to avoid memory leaks? Or, if there are no such retained references, we don't need to wait for the cancellation of the pending I/O and cancelled state for NWConnection?
Summary
NetworkConnection<WebSocket> in iOS 26 Network framework throws POSIXErrorCode(rawValue: 22): Invalid argument when receiving WebSocket ping (opcode 9) or pong (opcode 10) control frames. This prevents proper WebSocket keep-alive functionality.
Environment
iOS 26.0 (Simulator)
macOS 26.1
Xcode 26.0
Note: This issue was initially discovered on iOS 26 Simulator. The same behavior was confirmed on macOS 26, suggesting a shared bug in the Network framework. The attached sample code is for macOS for easier reproduction.
Description
When using the new NetworkConnection<WebSocket> API introduced in iOS 26 or macOS 26, the receive() method throws EINVAL error whenever a ping or pong control frame is received from the server.
This is a critical issue because:
WebSocket servers commonly send ping frames to keep connections alive
Clients send ping frames to verify connection health
The receive callback never receives the ping/pong frame - the error occurs before the frame reaches user code
Steps to Reproduce
Create a WebSocket connection to any server that supports ping/pong (e.g., wss://echo.websocket.org):
import Foundation
import Network
// MARK: - WebSocket Ping/Pong EINVAL Bug Reproduction
// This sample demonstrates that NetworkConnection<WebSocket> throws EINVAL
// when receiving ping or pong control frames.
@main
struct WebSocketPingPongBug {
static func main() async {
print("=== WebSocket Ping/Pong EINVAL Bug Reproduction ===\n")
do {
try await testPingPong()
} catch {
print("Test failed with error: \(error)")
}
}
static func testPingPong() async throws {
let host = "echo.websocket.org"
let port: UInt16 = 443
print("Connecting to wss://\(host)...")
let endpoint = NWEndpoint.hostPort(
host: NWEndpoint.Host(host),
port: NWEndpoint.Port(rawValue: port)!
)
try await withNetworkConnection(to: endpoint, using: {
WebSocket {
TLS {
TCP()
}
}
}) { connection in
print("Connected!\n")
// Start receive loop in background
let receiveTask = Task {
var messageCount = 0
while !Task.isCancelled {
do {
let (data, metadata) = try await connection.receive()
messageCount += 1
print("[\(messageCount)] Received frame - opcode: \(metadata.opcode)")
if let text = String(data: data, encoding: .utf8) {
print("[\(messageCount)] Content: \(text)")
} else {
print("[\(messageCount)] Binary data: \(data.count) bytes")
}
} catch let error as NWError {
if case .posix(let code) = error, code == .EINVAL {
print("❌ EINVAL error occurred! (POSIXErrorCode 22: Invalid argument)")
print(" This is the bug - ping/pong frame caused EINVAL")
// Continue to demonstrate workaround
continue
}
print("Receive error: \(error)")
break
} catch {
print("Receive error: \(error)")
break
}
}
}
// Wait for initial message from server
try await Task.sleep(for: .seconds(2))
// Test 1: Send text message (should work)
print("\n--- Test 1: Sending text message ---")
try await connection.send("Hello, WebSocket!")
print("✅ Text message sent")
try await Task.sleep(for: .seconds(1))
// Test 2: Send ping (pong response will cause EINVAL)
print("\n--- Test 2: Sending ping frame ---")
print("Expecting EINVAL when pong is received...")
let pingMetadata = NWProtocolWebSocket.Metadata(opcode: .ping)
try await connection.ping(Data()) {
pingMetadata
}
print("✅ Ping sent, waiting for pong...")
// Wait for pong response
try await Task.sleep(for: .seconds(2))
// Cleanup
receiveTask.cancel()
print("\n=== Test Complete ===")
print("If you saw 'EINVAL error occurred!' above, the bug is reproduced.")
}
}
}
The receive() call fails with error when pong arrives:
❌ EINVAL error occurred! (POSIXErrorCode 22: Invalid argument)
Test Results
Scenario
Result
Send/receive text (opcode 1)
✅ OK
Client sends ping, receives pong
❌ EINVAL on pong receive
Expected Behavior
The receive() method should successfully return ping and pong frames, or at minimum, handle them internally without throwing an error. The autoReplyPing option should allow automatic pong responses without disrupting the receive loop.
Actual Behavior
When a ping or pong control frame is received:
The receive() method throws NWError.posix(.EINVAL)
The frame never reaches user code (no opcode check is possible)
The connection remains valid, but the receive loop is interrupted
Workaround
Catch the EINVAL error and restart the receive loop:
while !Task.isCancelled {
do {
let received = try await connection.receive()
// Process message
} catch let error as NWError {
if case .posix(let code) = error, code == .EINVAL {
// Control frame caused EINVAL, continue receiving
continue
}
throw error
}
}
This workaround allows continued operation but:
Cannot distinguish between ping-related EINVAL and other EINVAL errors
Cannot access the ping/pong frame content
Cannot implement custom ping/pong handling
Impact
WebSocket connections to servers that send periodic pings will experience repeated EINVAL errors
Applications must implement workarounds that may mask other legitimate errors
Additional Information
Packet capture confirms ping/pong frames are correctly transmitted at the network level
The error occurs in the Network framework's internal processing, before reaching user code
hello
I am testing the use of network extension. When we use dnsproxy to proxy DNS requests,
we will send you a message that the udp pcbcount of your system continues to increase.
For example
for ((i=1; i<=99999; i++));do
echo "Attempt $i:"
dig google.com
done
when the dig command is used continuously,
the dig command will show the following errors when pcbcount reaches a certain number.
isc_socket_bind: address not available
Can you help us determine what the problem might be? thank you
I have read all the information and forum posts about local network, such as TN3179, etc., and have added NSLocalNetworkUsageDescription, but it does not solve my problem.
The problem I encountered is described as follows:
Device: iOS18.1.1
Signing method: automatic
Xcode debug directly runs, and the app can access 17.25.11.128 normally. However, relase run or packaged into adhoc installation, this IP cannot be accessed. There is a phenomenon that the app package of the App Store can also be used.
Our test team has few iOS18+ devices, and internal testing is not possible. Please contact us as soon as possible, thank you.
=======
我已经了解了所有关于local network 相关的资料和论坛帖子,比如TN3179 等等, 已经添加了 NSLocalNetworkUsageDescription, 但是不解决我的问题。
我遇到的问题描述如下:
设备:iOS18.1.1
签名方式:自动
xcode debug 直接运行,app是可以正常访问17.25.11.128的。 但是 relase run 或者 打包成 adhoc 安装,就无法访问这个IP了。 有一个现象, App Store 的app包 也是可以的。
我们的测试团队,iOS18+的设备就没几个,还不能内部测试了。请尽快联系我们,谢谢。
We found there is a significant crash reports (most of them are from iOS 17, the rest are iOS 16 and 15) comes from network loader from CFNetwork. Apparently it seems there are two types of crashes if we checked from the stack trace, the one we found from both Xcode organizer and 3rd party crash reporter is referring to URLConnectionLoader::loadWithWhatToDo and the other one from our 3rd party crash reporter (didn’t found the report from Xcode organizer) referring to
_CFURLResponseCreateFromArchiveList (this one only happened on iOS 17.5 and later devices). It seems that they are both kinda similar which might point to the same root cause.
From what I’ve seen, we never touch the lower level API directly, we usually use the URLSession to manage our API request. The crashed stack trace also didn’t give any indication about which of our app code that triggered the crash, it only shows calls to Apple’s internal SDKs so we are unsure how to approach this issue meanwhile the crash event already reached 800+ in the last 30 days. Unfortunately, we cannot reproduce the issue as the stack trace itself seems unclear to us.
I have submitted a report through feedback assistant with number: FB14679252.
Would appreciate if anyone can give any advice on what we can do to avoid this in the future and probably any hint on why it could happened.
Hereby I attached the crash reports that we found each from Xcode crash report and our 3rd party crash reporter (the report said it crashed on com.apple.CFNetwork.LoaderQ) so you could get a glimpse of the similarity.
Xcode crash report
xcode crash report.crash
3rd party crash report
3rd party crash report.txt
I'm struggling to understand why the async-await version of URLSession download task APIs do not call the delegate functions, whereas the old non-async version that returns a reference to the download task works just fine.
Here is my sample code:
class DownloadDelegate: NSObject, URLSessionDownloadDelegate {
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64) {
// This only prints the percentage of the download progress.
let calculatedProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
let formatter = NumberFormatter()
formatter.numberStyle = .percent
print(formatter.string(from: NSNumber(value: calculatedProgress))!)
}
}
// Here's the VC.
final class DownloadsViewController: UIViewController {
private let url = URL(string: "https://pixabay.com/get/g0b9fa2936ff6a5078ea607398665e8151fc0c10df7db5c093e543314b883755ecd43eda2b7b5178a7e613a35541be6486885fb4a55d0777ba949aedccc807d8c_1280.jpg")!
private let delegate = DownloadDelegate()
private lazy var session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
// for the async-await version
private var task: Task<Void, Never>?
// for the old version
private var downloadTask: URLSessionDownloadTask?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
task?.cancel()
task = nil
task = Task {
let (_, _) = try! await session.download(for: URLRequest(url: url))
self.task = nil
}
// If I uncomment this, the progress listener delegate function above is called.
// downloadTask?.cancel()
// downloadTask = nil
// downloadTask = session.downloadTask(with: URLRequest(url: url))
// downloadTask?.resume()
}
}
What am I missing here?
When installing a new version the app while a tunnel is connected, seemingly the old packet tunnel process gets stopped but the new one does not come back up. Reportedly, a path monitor is reporting that the device has no connectivity. Is this the expected behavior?
When installing an update from TestFlight or the App store, the packet tunnel instance from the old tunnel is stopped, but, due to the profile being on-demand and incldueAllNetworks, the path monitoring believes the device has no connectivity - so the new app is never downloaded. Is this the expected behavior?
During development, the old packet tunnel gets stopped, the new app is installed, but the new packet tunnel is never started. To start it, the user has to toggle the VPN twice from the Settings app. The tunnel could be started from the VPN app too, if we chose to not take the path monitor into account, but then the user still needs to attempt to start the tunnel twice - it only works on the second try. As far as we can tell, the first time around, the packet tunnel never gets started, the app receives an update about NEVPNStatus being set to disconnecting yet NEVPNConnection does not throw.
The behavior I was naively expecting was that the packet tunnel process would be stopped only when the new app is fully downloaded and when the update is installed, Are we doing something horribly wrong here?
Hi,
I've created a packet tunnel but my packetFlow object isn't get called with any packets. Do I need to do something else to configure the packetFlow? Maybe I have to link it to a NWUDPSession?
Thanks,
Dave
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress)
settings.ipv4Settings = NEIPv4Settings(addresses: [tunnelRemoteAddress], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
setTunnelNetworkSettings(settings) { error in
completionHandler(error)
self.readPacketObjects()
}
}
private func readPacketObjects() {
self.packetFlow.readPacketObjects() { packets in
// It never gets here.
self.logMessage("Got '\(packets.count)' packet(s)")
self.packetFlow.writePacketObjects(packets)
self.readPacketObjects()
}
}
}
We have developed a DNS filter based on NEDNSProxyProvider. It works great for a minute, then it stops responding. Our logs indicate that during the outage our extension gets DNS requests and formulates DNS responses that it hands back to the OS, but from outside of our code it is as though our extension is not responding.
Apologies if this is not the correct topic to post under.
EpochField 5.2 is our application. It's a .NET MAUI application built against XCode 16. A customer of ours uses another app, TN3270, to connect to a mainframe host. After installing our app on an iPad and restarting the device, the TN3270 app will disconnect when suspended. Uninstalling our app (EpochField) will allow the TN3270 to suspend without disconnecting. We have tried removing background services, setting UIRequiresFullScreen to false or removing it entirely, and several other ideas. The only remedy seems to be uninstalling EpochField.
On an iPad device:
Install MochaSoft’s TN3270 app (free version is fine). Create a connection to ssl3270.nccourts.org, port 2023, SSL/TLS turned on, keep alive turned on.
Verify that you can connect. Suspend the app by swiping up or choosing another app. Go back to TN3270 and verify that the app has not disconnected.
Install EpochField 5.2. Do not run or configure the app, just install it.
Repeat step 2.
Restart the device.
Open EpochField 5.2. You do not need to configure the app or login. Sometimes it isn't necessary to ever open EpochField to get the disconnects, but this is the most reliable way to reproduce the situation.
Repeat step 2. The TN3270 app will now disconnect when suspended, even if EpochField is closed. You may need to wait a few seconds after suspending.
Uninstall EpochField 5.2.
Repeat step 2: the TN3270 app will now remain connected when suspended.
Topic:
App & System Services
SubTopic:
Networking
Hey,
We also opened a feedback assistant request,
and also opened a ticket with Apple Developer Technical Support a while ago that notice the unmount problem also but it was before we pin point the problem to the Network Extension.
After a further investigation, we've found out that the root cause of this problem is cause by having a network filter from the NetworkExtension provider on (Specifically we have tested with the NEFilterDataProvider) while having a Xsan volume.
The NEFilterDataProvider causing problems for the Xsan, and is stalling the shutdown until we get a panic from watchdog timeout, and only then the mac is fully shutdown.
The problem from what we investigated and also talked with you, is that the Xsan process can't unmount the volume and stuck.
We have also noticed that if we install a network extension and allow the popup of the network filters, i.e enabled the NEFilterDataProvider the computer is stuck, and the finder is in a non responsive state until a reboot (Also probably due to the fact the Xsan is now in a problematic state).
This tests was done on latest versions of MacOs 13 & 14.
We have taken a sysdiagnose from the computer while we have tested.
Do you familiar with the problem (We got no answer on the feedback assistant)?
Thank you,
Idan
Hi, I have a VPN product for macOS. When activated, it creates a virtual interface that capture all outgoing traffic for the VPN. the VPN encrypt it, and send it to the tunnel gateway. The gateway then decapsulates the packet and forwards it to the original destination.
To achieve this, The vpn modifies the routing table with the following commands:
# after packets were encoded with the vpn protocol, re-send them through
# the physical interface
/sbin/route add -host <tunnel_gateway_address_in_physical_subnet> <default_gateway> -ifp en0 > /dev/null 2>&1
# remove the default rule for en0 and replace it with scoped rule
/sbin/route delete default <default_gateway> -ifp en0 > /dev/null 2>&1
/sbin/route add default <default_gateway> -ifscope en0 > /dev/null 2>&1
# create new rule for the virtual interface that will catch all packets
# for the vpn
/sbin/route add default <tunnel_gateway_address_in_tunnel_subnet> -ifp utunX > /dev/null 2>&1
This works in most cases. However, there are scenarios where the VPN process may crash, stop responding, or another VPN product may alter the routing table. When that happens, packets may no longer go out through the correct interface.
Question: Is there a way to reliably reconstruct the routing table from scratch in such scenarios? Ideally, I would like to rebuild the baseline rules for the physical interface (e.g., en0) and then reapply the VPN-specific rules on top. Are there APIs, system utilities, or best practices in macOS for restoring the original routing configuration before reapplying custom VPN routes?
Thanks
Hi,
Our project is a MacOS SwiftUI GUI application that bundles a (Sandboxed) System Network Extension, signed with a Developer ID certificate for distribution outside of the app store. The system network extension is used to write a packet tunnel provider (NEPacketTunnelProvider), as our project requires the creation of a TUN device.
In order for our System VPN to function, it must reach out to a (self-hosted) server (i.e. to discover a list of peers). Being self-hosted, this server is typically not accessible via the public web, and may only be accessible from within a VPN (such as those also implemented using NEPacketTunnelProvider, e.g. Tailscale, Cloudflare WARP).
What we've discovered is that the networking code of the System Network Extension process does not attempt to use the other VPN network interfaces (utunX) on the system. In practice, this means requests to IPs and hostnames that should be routed to those interfaces time out. Identical requests made outside of the Network System Extension process use those interfaces and succeed.
The simplest example is where we create a URLSession.downloadTask for a resource on the server. A more complicated example is where we execute a Go .dylib that continues to communicate with that server. Both types of requests time out.
Two noteworthy logs appear when packets fail to send, both from the kernel 'process':
cfil_hash_entry_log:6088 <CFIL: Error: sosend_reinject() failed>: [30685 com.coder.Coder-Desktop.VPN] <UDP(17) out so b795d11aca7c26bf 57728068503033955 57728068503033955 age 0> lport 3001 fport 3001 laddr 100.108.7.40 faddr 100.112.177.88 hash 58B15863
cfil_service_inject_queue:4472 CFIL: sosend() failed 49
I also wrote some test code that probes using a UDP NWConnection and NWPath availableInterfaces. When run from the GUI App, multiple interfaces are returned, including the one that routes the address, utun5. When ran from within the sysex, only en0 is returned.
I understand routing a VPN through another is unconventional, but we unfortunately do need this functionality one way or another. Is there any way to modify which interfaces are exposed to the sysex?
Additionally, are these limitations of networking within a Network System Extension documented anywhere? Do you have any ideas why this specific limitation might exist?