Networking

RSS for tag

Explore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.

Networking Documentation

Posts under Networking subtopic

Post

Replies

Boosts

Views

Activity

XPC listener initialized in System Extesnion invalidates incoming connection under certain conditions
I found a problem where a process tries to connect to System Extension and connection is invalidated. XPC listener has to be disposed and initialized again. This happens when System Extension executes tasks in following order: NSXPCListener initialized NSXPCListener.resume() NSProvider.startSystemExtensionMode() Result: Connection is invalidated and not only that the client has to retry connection, nut also System Extension must reinitialize listener (execute step 1 and 2). However if I call NSProvider.startSystemExtensionMode() NSXPCListener initialized NSXPCListener.resume() It works as expected and even if the connection is invalidated/interrupted, client process can always reconnect and no other action is necessary in System Extension (no need to reinitialize XPC listener), In Apple docs about NSProvider.startSystemExtensionMode() it says that this method starts handling request, but in another online article written by Scott Knight I found that startSystemExtensionMode() also starts listener server. Is that right? PLease could you add this info into the docs if it is so? https://knight.sc/reverse%20engineering/2019/08/24/system-extension-internals.html I would like to use following logic: Call NSProvider.startSystemExtensionMode() only under certain circumstances - I have received some configuration that I need to process and do some setup. If I don't receive it, there is no reason to call startSystemExtensionMode() yet, I don't need to handle handleNewFlow() yet. Connect XPC client to System Extension under certain conditions. Ideally communicate with client even though System Extension is not handling network requests yet, that is without receiving handleNewFlow(). Basically I consider XPC and System Extension handling network requests as separate things. Is that correct, are they separate and independent? Does XPC communication really depend on calling startSystemExtensionMode()? Another potential issue: Is it possible that XPC listener fails to validate connection when client tries to connect before System Extension manages to complete init and park the main thread in CFRunLoop? Note: These querstions arose mostly from handling upgrades of System Extension (extension is already running, network filter is created and is connected and new version of the app upgrades System Exension). Thanks.
5
0
1.3k
Apr ’25
NetworkConnection throws EINVAL when receiving ping/pong control frames
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
5
0
202
3w
Change includeAllNetworks from NetworkExtension while tunnel is running
Hi, I saw that almost each OS version, on ios and macos, handles differently changing includeAllNetworks while the tunnel is running. On some the entire OS reports no-net, while others, specially latest versions, handle this fine. Can includeAllNetworks be changed while the tunnel is running, or the tunnel must be stopped and restarted with the new value? e.g. the tunnel is started with it set to false, but later is changed to true into VPN profile. And on the same note, regarding setTunnelNetworkSettings, can this be called multiple times while the tunnel is running? For example if the VPN server IP changes. Because what I've saw each call to setTunnelNetworkSettings after VPN connected results in at least DNS leaks, because the routing table is recreated. Let me know if it is easier to track to create separate questions. Thanks
5
0
1k
Mar ’25
adhoc ipa, installed on iOS 18 devices, udp and tcp cannot access the local network, such as 17.25.11.128
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+的设备就没几个,还不能内部测试了。请尽快联系我们,谢谢。
5
0
242
May ’25
Running headless app as root for handling VPN and launching microservices
Hello to all I have coded in swift a headless app, that launches 3 go microservices and itself. The app listens via unix domain sockets for commands from the microservices and executes different VPN related operations, using the NEVPNManager extension. Because there are certificates and VPN operations, the headless app and two Go microservices must run as root. The app and microservices run perfectly when I run in Xcode launching the swift app as root. However, I have been trying for some weeks already to modify the application so at startup it requests the password and runs as root or something similar, so all forked apps also run as root. I have not succeeded. I have tried many things, the last one was using SMApp but as the swift app is a headless app and not a CLI command app it can not be embedded. And CLI apps can not get the VPN entitlements. Can anybody please give me some pointers how can I launch the app so it requests the password and runs as root in background or what is the ideal framework here? thank you again.
5
0
233
Dec ’25
certificate validation in SwiftUI App fails
I'm writing an LDAP Browser app using SwiftUI. I tested my LDAP code using a command line app that uses the exact same libraries and it successfully connects to my LDAP server over a TLS connection. I did need to install the CA cert into the system keychain. The SwiftUI version, using the exact same code and parameters returns an "Unknown CA" error. It works fine without TLS. Can anyone explain why certificate validation is different for a GUI app?
5
0
282
Feb ’25
iPhone 17(iOS26) Unable to join the Wi-Fi(TKIP)
Device: iPhone 17 Series System: iOS 26.0.0 Wi-Fi: TKIP encryption protocol Question: Unable to join the network We have several products that are used by connecting to iPhone via Wi-Fi. Recently, many customers who have purchased the iPhone 17 series have reported that they are unable to connect to Wi-Fi. For Wi-Fi with TKIP encryption, after entering the password correctly to connect to the Wi-Fi, a pop-up appears stating "Unable to join the network.". Only Wi-Fi with WPA2-AES can be used normally. Before that, during the iPhone 11 era or even earlier, the TKIP encryption method was in normal use. However, the new iPhone models were incompatible with it, which obviously caused great inconvenience. I hope the engineers can fix this issue to support Wi-Fi with older encryption protocols.
5
0
512
4w
Replacing Packet Filter (pf) with Content Filter for VPN Firewall Use Case
Hi, We're in the process of following Apple’s guidance on transitioning away from Packet Filter (pf) and migrating to a Network Extension-based solution that functions as a firewall. During this transition, we've encountered several limitations with the current Content Filter API and wanted to share our findings. Our VPN client relies on firewall functionality to enforce strict adherence to split tunneling rules defined via the routing table. This ensures that no traffic leaks outside the VPN tunnel, which is critical for our users for a variety of reasons. To enforce this, our product currently uses interface-scoped rules to block all non-VPN traffic outside the tunnel. Replicating this behavior with the Content Filter API (NEFilterDataProvider) appears to be infeasible today. The key limitation we've encountered is that the current Content Filter API does not expose information about the network interface associated with a flow. As a workaround, we considered using the flow’s local endpoint IP to infer the interface, but this data is not available until after returning a verdict to peek into the flow’s data—at which point the connection has already been established. This can result in connection metadata leaking outside the tunnel, which may contain sensitive information depending on the connection. What is the recommended approach for this use case? NEFilterPacketProvider? This may work, but it has a negative impact on network performance. Using a Packet Tunnel Provider and purely relying on enforceRoutes? Would this indeed ensure that no traffic can leak by targeting a specific interface or by using a second VPN extension? And more broadly—especially if no such approach is currently feasible with the existing APIs—we're interpreting TN3165 as a signal that pf should be considered deprecated and may not be available in the next major macOS release. Is that a reasonable interpretation?
5
0
207
May ’25
Not getting packets in PacketTunnel on iOS
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() } } }
5
0
350
Feb ’25
NWConnection cancel: Do we need to wait for pending receive callbacks to be cancelled?
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?
5
0
161
4w
URL Session randomly returns requests extremely slowly!
Hi, I'm experiencing intermittent delays with URLSession where requests take 3-4 seconds to be sent, even though the actual server processing is fast. This happens randomly, maybe 10-20% of requests. The pattern I've noticed is I create my request I send off my request using try await urlSession.data(for: request) My middleware ends up receiving this request 4-7s after its been fired from the client-side The round trip ends up taking 4-7s! This hasn't been reproducible consistently at all on my end. I've also tried ephemeral URLSessions (so recreating the session instead of using .shared so no dead connections, but this doesn't seem to help at all) Completely lost on what to do. Please help!
5
0
161
Nov ’25
WebAuthenticationSession under a carrier-provided satellite network?
(related post: How to optimize my app for for a carrier-provided satellite network? ) I am trying to implement an app so that it works under a carrier-provided satellite network. The app uses (AS)WebAuthenticationSession for signing in. If the app is entitled to access a satellite network, will (AS)WebAuthenticationSession work as well? How about WKWebView and SFSafariViewController? Is there a way to test(simulate) a ultra-constrained network on a device or a simulator to see the expected behavior? Thanks,
5
0
417
Jul ’25
URLSession QUIC configuration
I want to configure one aspect of my networking configuration (the QUIC keepalive interval). This only seems to be configurable via Network.framework’s nw_quic_set_keepalive_interval. Is there any way to apply this to a URLSession? Or do I need to implement the whole connection management myself using Network.framework?
4
0
842
Jan ’25
macOS 15.3 Local Network Permission regressions
Hi folks, I would like to ask for clarification regarding Local Network Policy. I found 2 cases where I think the behaviour differs from the documentation. 1. Use case In a CI environment, we have multiple services (LaunchAgents) which require Local Network Access. We are fine by manually approving the Local Network Permission once (per service), but we also require these services to be able to self-update. Self update results in downloading the a binary with an (obviously) different UUID, which seems to result in re-triggering the Local Network Consent prompt. Strange thing: If I don't click either buttons (Allow of Reject), just restart macOS, it will result in an enabled entry in Privacy &amp; Security &gt; Local Network. I read a reply somewhere on this forum by an Apple engineer that the approval process is a mix of Bundle ID + UUID + other components, so I would expect a new binary with the same properties (but different UUID) to be already whitelisted. Is this behaviour intended? 2. Use Case Given the first issue, I decided to do this in the "right way". I was happy to read this sentence in the documentation: If you ship a launchd agent that’s not installed using SMAppService, make macOS aware of the responsible code by setting the AssociatedBundleIdentifiers property in your launchd property list. I have a properly setup (and code signed) Application, for which I have enabled Local Network permission in Privacy &amp; Security. I have a standalone LaunchAgent, which runs a long running binary from a user directory. The agent is managed with launchd, and in this sense it is "independent" from the main Application Bundle. I have setup AssociatedBundleIdentifiers in the Agent plist, to associate it with the Application. The TeamIdentifier of the 2 binaries are the same. Based on the documentation, this should be enough for my agent to signal macOS that the responsible code is the Application Bundle (which is already enabled from Local Network POV). Instead, once the LaunchAgent starts, the Local Network Consent popup appears for the binary. I would expect the Application to be the responsible code, thus no more Consent popup. Is this behaviour intended? I need this service to run as user, so I cannot just circumvent the Consent popup by running as a Daemon or Root. Nor I would like to manage the Agent with ServiceManagement. What do you guys think, have I misunderstood the documentation?
4
10
942
Feb ’25
Changes to Personal Hotspot in iOS 18.0
We've been directed here by Quinn in DTS. We use multicast/broadcast messages extensively in our physical products for discovery purposes. If, for whatever reason, our customers cannot get this to work on their home Wi-Fi network, we advise that they connect to an iPhone hotspot to confirm behaviour and perform firmware updates as needed. As of iOS 18, we're seeing odd behaviour when using Personal Hotspot. Interestingly, we're also seeing that client devices connected to the Hotspot network are not showing a Subnet Mask in the Wi-Fi Details screen in the iOS Settings app - I don't know if that's related. We're also seeing that screen show an IP address of 192.0.0.2 for all client iPhones connected to an iPhone Hotspot. Getting more specific, we're seeing that multicast messages are no longer being received by clients when connected to an iPhone Hotspot where the iPhone running the hotspot is running iOS 18.0 or newer. By "multicast", I mean we're using a BSD socket to send data to 255.255.255.255 I've confirmed that our app has the multicast entitlement, the user has granted Local Network permission, and we've created a small sample app that demonstrates this behaviour perfectly - when connected to any other test network, multicast messages are received correctly by clients. We've also confirmed that this behaviour doesn't happen when the iPhone running the hotspot is running older iOS versions. We've tried a number of iOS 17.x releases and a number of iOS 16.x releases specifically with our sample app, but have been using this exact code since our app's original iOS 9 deployment target and have had no issues until now.
4
0
531
Jan ’25
Automatic Background File Uploads
I have currently created an app which contains an upload button which when clicked upload health data using HealthKit to an AWS S3 bucket. Now I want to implement an automatic file upload mechanism which would mean that the app is installed and opened just once - and then the upload must happen on a schedule (once daily) from the background without ever having to open the app again. I've tried frameworks like NSURLSession and BackgroundTasks but nothing seems to work. Is this use case even possible to implement? Does iOS allow this? The file is just a few KBs in size. For reference, here is the Background Tasks code: import UIKit import BackgroundTasks import HealthKit class AppDelegate: NSObject, UIApplicationDelegate { let backgroundTaskIdentifier = "com.yourapp.healthdata.upload" func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool { // Register the background task BGTaskScheduler.shared.register(forTaskWithIdentifier: backgroundTaskIdentifier, using: nil) { task in self.handleHealthDataUpload(task: task as! BGAppRefreshTask) } // Schedule the first upload task scheduleDailyUpload() return true } // Schedule the background task for daily execution func scheduleDailyUpload() { print("[AppDelegate] Scheduling daily background task.") let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier) request.earliestBeginDate = Date(timeIntervalSinceNow: 24*60*60) do { try BGTaskScheduler.shared.submit(request) print("[AppDelegate] Daily background task scheduled.") } catch { print("[AppDelegate] Could not schedule daily background task: \(error.localizedDescription)") } } // Handle the background task when it's triggered by the system func handleHealthDataUpload(task: BGAppRefreshTask) { print("[AppDelegate] Background task triggered.") // Call your upload function with completion handler HealthStoreManager.shared.fetchAndUploadHealthData { success in if success { print("[AppDelegate] Upload completed successfully.") task.setTaskCompleted(success: true) // Schedule the next day's upload after a successful upload self.scheduleDailyUpload() } else { print("[AppDelegate] Upload failed.") task.setTaskCompleted(success: false) } } // Handle task expiration (e.g., if upload takes too long) task.expirationHandler = { print("[AppDelegate] Background task expired.") task.setTaskCompleted(success: false) } } }
4
0
484
Feb ’25
wifi connect fail
Dear Apple: In our app, we will call the - (void) applyConfiguration:(NEHotspotConfiguration *) configuration completionHandler:(void (^)(NSError * error)) completionHandler; interface of NEHotspotConfigurationManager on Apple devices. However, we are encountering a problem where the connection to the 2.4G hotspot fails, and the error is nil when it fails. We checked the Wi-Fi air interface and found that the Apple phone does not send a probe request before connecting to the hotspot. However, we are unclear why the Apple device does not send the probe request frame. Could you please help us understand when the probe request frame is not sent during the hotspot connection and how to trigger it to send the probe request frame every time? Thank you.
4
0
135
May ’25
URLSession.dataTask(with: URL) error: Type of expression is ambiguous without a type annotation
I'm a long-time developer, but pretty new to Swift. I'm trying to get information from a web service (and found code online that I adjusted to build the function below). (Note: AAA_Result -- referenced towards the end -- is another class in my project) Trouble is, I'm getting the subject error on the call to session.dataTask. Any help/suggestions/doc pointers will be greatly appreciated!!! var result: Bool = false var cancellable: AnyCancellable? self.name = name let params = "json={\"\"}}" // removed json details let base_url = URL(string: "https://aaa.yyy.com?params=\(params)&format=json")! // removed URL specifics do { let task = URLSession.shared.dataTask(with: base_url) { data, response, error in if let error = error { print("Error: \(error)") } guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else { print("Error \(String(describing: response))") } do { let decoder = JSONDecoder() let ar = try decoder.decode(AAA_Result.self, from: response.value) // removed specific details... result = true } catch { print(error) } } task.resume() } catch { print(error) } return result }
4
0
105
May ’25