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

Expected behavior of searchDomains
Based on https://developer.apple.com/documentation/networkextension/nednssettings/searchdomains , we expect the values mentioned in searchDomains to be appended to a single label DNS query. However, we are not seeing this behavior. We have a packetTunnelProvider VPN, where we set searchDomains to a dns suffix (for ex: test.com) and we set matchDomains to applications and suffix (for ex: abc.com and test.com) . When a user tries to access https://myapp , we expect to see a DNS query packet for myapp.test.com . However, this is not happening when matchDomainsNoSearch is set to true. https://developer.apple.com/documentation/networkextension/nednssettings/matchdomainsnosearch When matchDomainsNoSearch is set to false, we see dns queries for myapp.test.com and myapp.abc.com. What is the expected behavior of searchDomains?
6
0
143
6d
How to add more cipher suites
I want to add more cipher suites. I use NWConnection to make a connection. Before I use sec_protocol_options_append_tls_ciphersuite method to add more cipher suites, I found that Apple provided 20 cipher suites shown in the client hello packet. But after I added three more cipher suites, I found that nothing changed, and still original 20 cipher suites shown in the client hello packet when I made a new connection. The following is the code about connection. I want to add three more cipher suites: tls_ciphersuite_t.ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, tls_ciphersuite_t.ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, tls_ciphersuite_t.ECDHE_RSA_WITH_AES_256_CBC_SHA384 Can you give me some advice about how to add more cipher suites? Thanks. By the way, I working on a MacOS app. Xcode version: 16 MacOS version: 15.6
1
0
177
Dec ’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
302
Dec ’25
Socket Becomes Unresponsive in Local Connectivity Extension After Lock Screen
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 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!
1
0
80
Mar ’25
DNS updates and Apple Private Relay - major issue
After dropping an A-record TTL to 60 secs (it was previously no higher than 600 secs for several weeks) and making an IP change for a small business website on Monday, I took down the old web service just over 24 hours later on Tuesday evening. We then had reports of some customers not being able to access the website on Wednesday morning. On investigation using my iPhone it would appear that Apple Private Relay is still directing clients to the old IP address. It's just as well I have iCloud+ as I would never have seen this issue otherwise and would have been none the wiser as to why some customers were having problems. Has anyone else seen this and/or have a fix other than waiting longer? Do you know how long it takes for Apple Private Relay to update? This isn't expected behaviour of DNS? I spoke to someone at Apple yesterday and there wasn't much they can do. I hope they're escalating internally as almost 3 days later it's still pointing users to the old IP address despite having ample time for proper DNS propagation.
2
0
177
Nov ’25
On Host Names
For important background information, read Extra-ordinary Networking before reading this. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" On Host Names I commonly see questions like How do I get the device’s host name? This question doesn’t make sense without more context. Apple systems have a variety of things that you might consider to be the host name: The user-assigned device name — This is a user-visible value, for example, Guy Smiley. People set this in Settings > General > About > Name. The local host name — This is a DNS name used by Bonjour, for example, guy-smiley.local. By default this is algorithmically derived from the user-assigned device name. On macOS, people can override this in Settings > General > Sharing > Local hostname. The reverse DNS name associated with the various IP addresses assigned to the device’s various network interfaces That last one is pretty much useless. You can’t get a single host name because there isn’t a single IP address. For more on that, see Don’t Try to Get the Device’s IP Address. The other two have well-defined answers, although those answers vary by platform. I’ll talk more about that below. Before getting to that, however, let’s look at the big picture. Big Picture The use cases for the user-assigned device name are pretty clear. I rarely see folks confused about that. Another use case for this stuff is that you’ve started a server and you want to tell the user how to connect to it. I discuss this in detail in Showing Connection Information in an iOS Server. However, most folks who run into problems like this do so because they’re suffering from one of the following misconceptions: The device has a DNS name. Its DNS name is unique. Its DNS name doesn’t change. Its DNS name is in some way useful for networking. Some of these may be true in some specific circumstances, but none of them are true in all circumstances. These issues are not unique to Apple platforms — if you look at the Posix spec for gethostname, it says nothing about DNS! — but folks tend to notice these problems more on Apple platforms because Apple devices are often deployed to highly dynamic network environments. So, before you start using the APIs discussed in this post, think carefully about your assumptions. And if you actually do want to work with DNS, there are two cases to consider: If you’re looking for the local host name, use the APIs discussed above. In other cases, it’s likely that the APIs in this post will not be helpful and you’d be better off focusing on DNS APIs [1]. [1] The API I recommend for this is DNS-SD. See the DNS section in TN3151 Choosing the right networking API. macOS To get the user-assigned device name, call the SCDynamicStoreCopyComputerName(_:_:) function. For example: let userAssignedDeviceName = SCDynamicStoreCopyComputerName(nil, nil) as String? To get the local host name, call the SCDynamicStoreCopyLocalHostName(_:) function. For example: let localHostName = SCDynamicStoreCopyLocalHostName(nil) as String? IMPORTANT This returns just the name label. To form a local host name, append .local.. Both routines return an optional result; code defensively! If you’re displaying these values to the user, use the System Configuration framework dynamic store notification mechanism to keep your UI up to date. iOS and Friends On iOS, iPadOS, tvOS, and visionOS, get the user-assigned device name from the name property on UIDevice. IMPORTANT Access to this is now restricted. For more on that, see the documentation for the com.apple.developer.device-information.user-assigned-device-name entitlement. There is no direct mechanism to get the local host name. Other APIs There are a wide variety of other APIs that purport to return the host name. These include: gethostname The name property on NSHost [1] The hostName property on NSProcessInfo (ProcessInfo in Swift) These are problematic for a number of reasons: They have a complex implementation that makes it hard to predict what value you’ll get back. They might end up trying to infer the host name from the network environment. The existing behaviour is hard to change due to compatibility concerns. Some of them are marked as to-be-deprecated. IMPORTANT The second issue is particularly problematic, because it involves synchronous DNS requests [2]. That’s slow in general. Worse yet, if the network environment is restricted in some way, these calls can be very slow, taking about 30 seconds to time out. Given these problems, it’s generally best to avoid calling these routines at all. [1] It also has a names property, which is a little closer to reality but still not particularly useful. [2] Actually, that’s not true for gethostname. Rather, that call just returns whatever was last set by sethostname. This is always fast. The System Configuration framework infrastructure calls sethostname to update the host name as the system state changes.
0
0
222
Mar ’25
Connecting to a service found by Bonjour isn't working.
I'm using NWBrowser to search for a server that I hosted. The browser does find my service but when it tries to connect to it, it gets stuck in the preparing phase in NWConnection.stateUpdateHandler. When I hardcode the local IP address of my computer (where the server is hosted) into NWConnection it works perfectly fine and is able to connect. When it gets stuck in the preparing phase, it gives me the warnings and error messages in the image below. You can also see that the service name is correct and it is found. I have tried _http._tcp and _ssh._tcp types and neither work. This is what my code looks like: func findServerAndConnect(port: UInt16) { print("Searching for server...") let browser = NWBrowser(for: .bonjour(type: "_ssh._tcp", domain: "local."), using: .tcp) browser.browseResultsChangedHandler = { results, _ in print("Found results: \(results)") for result in results { if case let NWEndpoint.service(name, type_, domain, interface) = result.endpoint { if name == "PocketPadServer" { print("Found service: \(name) of type \(type_) in domain \(domain) on interface \(interface)") // Construct the full service name, including type and domain let fullServiceName = "\(name).\(type_).\(domain)" print("Full service name: \(fullServiceName), \(result.endpoint)") self.connect(to: result.endpoint, port: port) browser.cancel() break } } } } browser.start(queue: .main) } func connect(to endpoint: NWEndpoint, port: UInt16) { print("Connecting to \(endpoint) on port \(port)...") // endpoint = NWEndpoint( let tcpParams = NWProtocolTCP.Options() tcpParams.enableFastOpen = true tcpParams.keepaliveIdle = 2 let params = NWParameters(tls: nil, tcp: tcpParams) params.includePeerToPeer = true // connection = NWConnection(host: NWEndpoint.Host("xx.xxx.xxx.xxx"), port: NWEndpoint.Port(3000), using: params) connection = NWConnection(to: endpoint, using: params) connection?.pathUpdateHandler = { path in print("Connection path update: \(path)") if path.status == .satisfied { print("Connection path is satisfied") } else { print("Connection path is not satisfied: \(path.status)") } } connection?.stateUpdateHandler = { newState in DispatchQueue.main.async { switch newState { case .ready: print("Connected to server") self.pairing = true self.receiveMessage() case .failed(let error): print("Connection failed: \(error)") self.isConnected = false case .waiting(let error): print("Waiting for connection... \(error)") self.isConnected = false case .cancelled: print("Connection cancelled") self.isConnected = false case .preparing: print("Preparing connection...") self.isConnected = false default: print("Connection state changed: \(newState)") break } } } connection?.start(queue: .main) }
4
0
144
Apr ’25
Bonjour Conformance Test - Multiple Instance in Single Device
We are currently working on a zero-configuration networking compliant device thru avahi-daemon. Our Device want to have multiple Instance name for different services. Example InstanceA._ipps._tcp.local. InstanceA._ipp._tcp.local. InstanceB._ipps._tcp.local. InstanceB._ipp._tcp.local. Will BCT confuse this as multiple device connected in the network and cause it to fail? Does Bonjour only allows only a Single Instance name with multiple services?
1
0
98
Apr ’25
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
265
Nov ’25
Network Extension Provider Packaging
This is a topic that’s come up a few times on the forums, so I thought I’d write up a summary of the issues I’m aware of. If you have questions or comments, start a new thread in the App & System Services > Networking subtopic and tag it with Network Extension. That way I’ll be sure to see it go by. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Network Extension Provider Packaging There are two ways to package a network extension provider: App extension ( appex ) System extension ( sysex ) Different provider types support different packaging on different platforms. See TN3134 Network Extension provider deployment for the details. Some providers, most notably packet tunnel providers on macOS, support both appex and sysex packaging. Sysex packaging has a number of advantages: It supports direct distribution, using Developer ID signing. It better matches the networking stack on macOS. An appex is tied to the logged in user, whereas a sysex, and the networking stack itself, is global to the system as a whole. Given that, it generally makes sense to package your Network Extension (NE) provider as a sysex on macOS. If you’re creating a new product that’s fine, but if you have an existing iOS product that you want to bring to macOS, you have to account for the differences brought on by the move to sysex packaging. Similarly, if you have an existing sysex product on macOS that you want to bring to iOS, you have to account for the appex packaging. This post summarises those changes. Keep the following in mind while reading this post: The information here applies to all NE providers that can be packaged as either an appex or a sysex. When this post uses a specific provider type in an example, it’s just an example. Unless otherwise noted, any information about iOS also applies to iPadOS, tvOS, and visionOS. Process Lifecycle With appex packaging, the system typically starts a new process for each instance of your NE provider. For example, with a packet tunnel provider: When the users starts the VPN, the system creates a process and then instantiates and starts the NE provider in that process. When the user stops the VPN, the system stops the NE provider and then terminates the process running it. If the user starts the VPN again, the system creates an entirely new process and instantiates and starts the NE provider in that. In contrast, with sysex packaging there’s typically a single process that runs all off the sysex’s NE providers. Returning to the packet tunnel provider example: When the users starts the VPN, the system instantiates and starts the NE provider in the sysex process. When the user stops the VPN, the system stops and deallocates the NE provider instances, but leaves the sysex process running. If the user starts the VPN again, the system instantiates and starts a new instances of the NE provider in the sysex process. This lifecycle reflects how the system runs the NE provider, which in turn has important consequences on what the NE provider can do: An appex acts like a launchd agent [1], in that it runs in a user context and has access to that user’s state. A sysex is effectively a launchd daemon. It runs in a context that’s global to the system as a whole. It does not have access to any single user’s state. Indeed, there might be no user logged in, or multiple users logged in. The following sections explore some consequences of the NE provider lifecycle. [1] It’s not actually run as a launchd agent. Rather, there’s a system launchd agent that acts as the host for the app extension. App Groups With an app extension, the app extension and its container app run as the same user. Thus it’s trivial to share state between them using an app group container. Note When talking about extensions on Apple platforms, the container app is the app in which the extension is embedded and the host app is the app using the extension. For network extensions the host app is the system itself. That’s not the case with a system extension. The system extension runs as root whereas the container app runs an the user who launched it. While both programs can claim access to the same app group, the app group container location they receive will be different. For the system extension that location will be inside the home directory for the root user. For the container app the location will be inside the home directory of the user who launched it. This does not mean that app groups are useless in a Network Extension app. App groups are also a factor in communicating between the container app and its extensions, the subject of the next section. IMPORTANT App groups have a long and complex history on macOS. For the full story, see App Groups: macOS vs iOS: Working Towards Harmony. Communicating with Extensions With an app extension there are two communication options: App-provider messages App groups App-provider messages are supported by NE directly. In the container app, send a message to the provider by calling sendProviderMessage(_:responseHandler:) method. In the appex, receive that message by overriding the handleAppMessage(_:completionHandler:) method. An appex can also implement inter-process communication (IPC) using various system IPC primitives. Both the container app and the appex claim access to the app group via the com.apple.security.application-groups entitlement. They can then set up IPC using various APIs, as explain in the documentation for that entitlement. With a system extension the story is very different. App-provider messages are supported, but they are rarely used. Rather, most products use XPC for their communication. In the sysex, publish a named XPC endpoint by setting the NEMachServiceName property in its Info.plist. Listen for XPC connections on that endpoint using the XPC API of your choice. Note For more information about the available XPC APIs, see XPC Resources. In the container app, connect to that named XPC endpoint using the XPC Mach service name API. For example, with NSXPCConnection, initialise the connection with init(machServiceName:options:), passing in the string from NEMachServiceName. To maximise security, set the .privileged flag. Note XPC Resources has a link to a post that explains why this flag is important. If the container app is sandboxed — necessary if you ship on the Mac App Store — then the endpoint name must be prefixed by an app group ID that’s accessible to that app, lest the App Sandbox deny the connection. See the app groups documentation for the specifics. When implementing an XPC listener in your sysex, keep in mind that: Your sysex’s named XPC endpoint is registered in the global namespace. Any process on the system can open a connection to it [1]. Your XPC listener must be prepared for this. If you want to restrict connections to just your container app, see XPC Resources for a link to a post that explains how to do that. Even if you restrict access in that way, it’s still possible for multiple instances of your container app to be running simultaneously, each with its own connection to your sysex. This happens, for example, if there are multiple GUI users logged in and different users run your container app. Design your XPC protocol with this in mind. Your sysex only gets one named XPC endpoint, and thus one XPC listener. If your sysex includes multiple NE providers, take that into account when you design your XPC protocol. [1] Assuming that connection isn’t blocked by some other mechanism, like the App Sandbox. Inter-provider Communication A sysex can include multiple types of NE providers. For example, a single sysex might include a content filter and a DNS proxy provider. In that case the system instantiates all of the NE providers in the same sysex process. These instances can communicate without using IPC, for example, by storing shared state in global variables (with suitable locking, of course). It’s also possible for a single container app to contain multiple sysexen, each including a single NE provider. In that case the system instantiates the NE providers in separate processes, one for each sysex. If these providers need to communicate, they have to use IPC. In the appex case, the system instantiates each provider in its own process. If two providers need to communicate, they have to use IPC. Managing Secrets An appex runs in a user context and thus can store secrets, like VPN credentials, in the keychain. On macOS this includes both the data protection keychain and the file-based keychain. It can also use a keychain access group to share secrets with its container app. See Sharing access to keychain items among a collection of apps. Note If you’re not familiar with the different types of keychain available on macOS, see TN3137 On Mac keychain APIs and implementations. A sysex runs in the global context and thus doesn’t have access to user state. It also doesn’t have access to the data protection keychain. It must use the file-based keychain, and specifically the System keychain. That means there’s no good way to share secrets with the container app. Instead, do all your keychain operations in the sysex. If the container app needs to work with a secret, have it pass that request to the sysex via IPC. For example, if the user wants to use a digital identity as a VPN credential, have the container app get the PKCS#12 data and password and then pass that to the sysex so that it can import the digital identity into the keychain. Memory Limits iOS imposes strict memory limits an NE provider appexen [1]. macOS imposes no memory limits on NE provider appexen or sysexen. [1] While these limits are not documented officially, you can get a rough handle on the current limits by reading the posts in this thread. Frameworks If you want to share code between a Mac app and its embedded appex, use a structure like this: MyApp.app/ Contents/ MacOS/ MyApp PlugIns/ MyExtension.appex/ Contents/ MacOS/ MyExtension … Frameworks/ MyFramework.framework/ … There’s one copy of the framework, in the app’s Frameworks directory, and both the app and the appex reference it. This approach works for an appex because the system always loads the appex from your app’s bundle. It does not work for a sysex. When you activate a sysex, the system copies it to a protected location. If that sysex references a framework in its container app, it will fail to start because that framework isn’t copied along with the sysex. The solution is to structure your app like this: MyApp.app/ Contents/ MacOS/ MyApp Library/ SystemExtensions/ MyExtension.systemextension/ Contents/ MacOS/ MyExtension Frameworks/ MyFramework.framework/ … … That is, have both the app and the sysex load the framework from the sysex’s Frameworks directory. When the system copies the sysex to its protected location, it’ll also copy the framework, allowing the sysex to load it. To make this work you have to change the default rpath configuration set up by Xcode. Read Dynamic Library Standard Setup for Apps to learn how that works and then tweak things so that: The framework is embedded in the sysex, not the container app. The container app has an additional LC_RPATH load command for the sysex’s Frameworks directory (@executable_path/../Library/SystemExtensions/MyExtension.systemextension/Contents/Frameworks). The sysex’s LC_RPATH load command doesn’t reference the container app’s Frameworks directory (@executable_path/../../../../Frameworks) but instead points to the sysex’s Framweorks directory (@executable_path/../Frameworks). Entitlements When you build an app with an embedded NE extension, both the app and the extension must be signed with the com.apple.developer.networking.networkextension entitlement. This is a restricted entitlement, that is, it must be authorised by a provisioning profile. The value of this entitlement is an array, and the values in that array differ depend on your distribution channel: If you distribute your app directly with Developer ID signing, use the values with the -systemextension suffix. Otherwise — including when you distribute the app on the App Store and when signing for development — use the values without that suffix. Make sure you authorise these values with your provisioning profile. If, for example, you use an App Store distribution profile with a Developer ID signed app, things won’t work because the profile doesn’t authorise the right values. In general, the easiest option is to use Xcode’s automatic code signing. However, watch out for the pitfall described in Exporting a Developer ID Network Extension. Revision History 2025-11-06 Added the Entitlements section. Explained that, with sysex packaging, multiple instances of your container app might connect simultaneously with your sysex. 2025-09-17 First posted.
0
0
152
Nov ’25
How can a Network Extension notify or trigger tasks in the main app when it’s backgrounded or killed?
I’m developing a iOS VPN app, and I need to execute a task in the main app even when it’s in the background or killed state. I know the Network Extension continues running during those times. Is there a way for the extension to immediately notify the app or trigger a task on the app side?
1
0
92
Sep ’25
“Wi-Fi Aware Sample” on Phone quit unexpectedly.
The app “Wi-Fi Aware Sample” on Bojie的iPhone quit unexpectedly. Domain: IDEDebugSessionErrorDomain Code: 20 Failure Reason: Message from debugger: The LLDB RPC server has crashed. You may need to manually terminate your process. The crash log is located in ~/Library/Logs/DiagnosticReports and has a prefix 'lldb-rpc-server'. Please file a bug and attach the most recent crash log. User Info: { DVTErrorCreationDateKey = "2025-09-17 10:26:56 +0000"; IDEDebugSessionErrorUserInfoUnavailabilityError = "Error Domain=com.apple.dt.deviceprep Code=-10 "Fetching debug symbols for Bojie\U7684iPhone" UserInfo={NSLocalizedRecoverySuggestion=Xcode will continue when the operation completes., NSLocalizedDescription=Fetching debug symbols for Bojie\U7684iPhone}"; IDERunOperationFailingWorker = DBGLLDBLauncher; } Event Metadata: com.apple.dt.IDERunOperationWorkerFinished : { "device_identifier" = "00008101-001E29E01E63003A"; "device_isCoreDevice" = 1; "device_model" = "iPhone13,3"; "device_osBuild" = "26.0 (23A341)"; "device_osBuild_monotonic" = 2300034100; "device_os_variant" = 1; "device_platform" = "com.apple.platform.iphoneos"; "device_platform_family" = 2; "device_reality" = 1; "device_thinningType" = "iPhone13,3"; "device_transport" = 1; "dvt_coredevice_version" = "477.23"; "dvt_coredevice_version_monotonic" = 477023000000000; "dvt_coresimulator_version" = 1043; "dvt_coresimulator_version_monotonic" = 1043000000000000; "dvt_mobiledevice_version" = "1818.0.1"; "dvt_mobiledevice_version_monotonic" = 1818000001000000; "launchSession_schemeCommand" = Run; "launchSession_schemeCommand_enum" = 1; "launchSession_targetArch" = arm64; "launchSession_targetArch_enum" = 6; "operation_duration_ms" = 1922640; "operation_errorCode" = 20; "operation_errorDomain" = IDEDebugSessionErrorDomain; "operation_errorWorker" = DBGLLDBLauncher; "operation_error_reportable" = 1; "operation_name" = IDERunOperationWorkerGroup; "operation_unavailabilityErrorCode" = "-10"; "operation_unavailabilityErrorDomain" = "com.apple.dt.deviceprep"; "param_consoleMode" = 1; "param_debugger_attachToExtensions" = 0; "param_debugger_attachToXPC" = 1; "param_debugger_type" = 3; "param_destination_isProxy" = 0; "param_destination_platform" = "com.apple.platform.iphoneos"; "param_diag_MainThreadChecker_stopOnIssue" = 0; "param_diag_MallocStackLogging_enableDuringAttach" = 0; "param_diag_MallocStackLogging_enableForXPC" = 1; "param_diag_allowLocationSimulation" = 1; "param_diag_checker_mtc_enable" = 1; "param_diag_checker_tpc_enable" = 1; "param_diag_gpu_frameCapture_enable" = 0; "param_diag_gpu_shaderValidation_enable" = 0; "param_diag_gpu_validation_enable" = 0; "param_diag_guardMalloc_enable" = 0; "param_diag_memoryGraphOnResourceException" = 0; "param_diag_queueDebugging_enable" = 1; "param_diag_runtimeProfile_generate" = 0; "param_diag_sanitizer_asan_enable" = 0; "param_diag_sanitizer_tsan_enable" = 0; "param_diag_sanitizer_tsan_stopOnIssue" = 0; "param_diag_sanitizer_ubsan_enable" = 0; "param_diag_sanitizer_ubsan_stopOnIssue" = 0; "param_diag_showNonLocalizedStrings" = 0; "param_diag_viewDebugging_enabled" = 1; "param_diag_viewDebugging_insertDylibOnLaunch" = 1; "param_install_style" = 2; "param_launcher_UID" = 2; "param_launcher_allowDeviceSensorReplayData" = 0; "param_launcher_kind" = 0; "param_launcher_style" = 99; "param_launcher_substyle" = 0; "param_lldbVersion_component_idx_1" = 0; "param_lldbVersion_monotonic" = 170300230950; "param_runnable_appExtensionHostRunMode" = 0; "param_runnable_productType" = "com.apple.product-type.application"; "param_testing_launchedForTesting" = 0; "param_testing_suppressSimulatorApp" = 0; "param_testing_usingCLI" = 0; "sdk_canonicalName" = "iphoneos26.0"; "sdk_osVersion" = "26.0"; "sdk_platformID" = 2; "sdk_variant" = iphoneos; "sdk_version_monotonic" = 2300527605; } System Information macOS Version 15.5 (Build 24F74) Xcode 26.0 (24141.31) (Build 17A5241o) Timestamp: 2025-09-17T18:26:56+08:00
3
0
198
Sep ’25
DMG Distribution for macOS App with App Extension — Should I Use System Extension Instead?
Hi everyone, I’m currently developing a macOS app that is distributed via a DMG file on our website. The app includes an App Extension (appex) for Network Extension functionality. I’m wondering if distributing via DMG on the web requires the app extension to be implemented as a System Extension instead of an App Extension. Is it necessary to migrate to System Extension for web-based DMG distribution, or can I continue using App Extension as is? Any insights or recommendations would be greatly appreciated. Thank you!
1
0
60
Aug ’25
Crash on "Dispatch queue: NEFlow queue" when __88-[NEExtensionAppProxyProviderContext setInitialFlowDivertControlSocket:extraValidation:]_block_invoke.90
I observed the following crash: Code Type: ARM-64 (Native) Parent Process: launchd [1] User ID: 0 Date/Time: 2025-10-07 13:48:29.082 OS Version: macOS 15.6 (24G84) Report Version: 12 Anonymous UUID: 8B651788-4B2E-7869-516B-1DA0D60F3744 Crashed Thread: 3 Dispatch queue: NEFlow queue Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000054 ... Thread 3 Crashed: Dispatch queue: NEFlow queue 0 libdispatch.dylib 0x000000019af6da34 dispatch_async + 192 1 libnetworkextension.dylib 0x00000001b0cf8580 __flow_startup_block_invoke.216 + 124 2 com.apple.NetworkExtension 0x00000001adf97da8 __88-[NEExtensionAppProxyProviderContext setInitialFlowDivertControlSocket:extraValidation:]_block_invoke.90 + 860 3 libnetworkextension.dylib 0x00000001b0cf8140 __flow_startup_block_invoke.214 + 172 4 libdispatch.dylib 0x000000019af67b2c _dispatch_call_block_and_release + 32 5 libdispatch.dylib 0x000000019af8185c _dispatch_client_callout + 16 6 libdispatch.dylib 0x000000019af70350 _dispatch_lane_serial_drain + 740 7 libdispatch.dylib 0x000000019af70e2c _dispatch_lane_invoke + 388 8 libdispatch.dylib 0x000000019af7b264 _dispatch_root_queue_drain_deferred_wlh + 292 9 libdispatch.dylib 0x000000019af7aae8 _dispatch_workloop_worker_thread + 540 10 libsystem_pthread.dylib 0x000000019b11be64 _pthread_wqthread + 292 11 libsystem_pthread.dylib 0x000000019b11ab74 start_wqthread + 8 ... It appears that the crash is caused by the flow director queue becoming NULL when dispatch_async is called (accessing address 0x0000000000000054). Meanwhile, my transparent proxy was still running. I'm wondering if this is a known issue or if anyone else has encountered the same problem. @eskimo
2
0
442
Oct ’25
[networkextesion] dnsproxy
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
5
0
307
Feb ’25
Crash when deallocating NEAppProxyFlow
Hello, I'm working on a Transparent Proxy and when the proxy is being stopped, I'm stopping all the flows by calling flow.closeWriteWithError(POSIXError(.ECANCELED)) flow.closeReadWithError(POSIXError(.ECANCELED)) Then all the flows are deallocated. When deallocating the flow the crash occurs: OS Version: macOS 14.1.2 (23B92) Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000018c2ef704 Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [553] Thread 32 Crashed:: Dispatch queue: <my dispatch queue> 0 CoreFoundation 0x18c2ef704 CF_IS_OBJC + 76 1 CoreFoundation 0x18c23f61c CFErrorGetDomain + 32 2 libnetworkextension.dylib 0x19fe56a00 flow_error_to_errno + 28 3 libnetworkextension.dylib 0x19fe56920 flow_handle_pending_write_requests + 216 4 libnetworkextension.dylib 0x19fe5667c __NEFlowDeallocate + 380 5 CoreFoundation 0x18c2efe28 _CFRelease + 292 6 NetworkExtension 0x19d208390 -[NEAppProxyFlow dealloc] + 36 Is there any way to debug what is happening and if it's related to closing the flow with POSIXError? Thank you
3
0
213
Jul ’25
Need Help with TUN Writeback
Hi everyone, I'm currently experimenting with building a simple DNS filter using Apple's Packet Tunnel framework. Here's the flow I'm trying to implement: Create a TUN interface Set up a UDP socket Read packets via packetFlow.readPackets Parse the raw IP packet Forward the UDP payload through the socket Receive the response from the server Reconstruct the IP packet with the response Write it back to the TUN interface using packetFlow.writePackets Here’s an example of an intercepted IP packet (DNS request): 45 00 00 3c 15 c4 00 00 40 11 93 d1 c0 a8 00 64 08 08 08 08 ed 6e 00 35 00 28 e5 c9 7f da 01 00 00 01 00 00 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 And here’s the IP packet I tried writing back into the TUN interface (DNS response): 45 00 00 89 5e 37 40 00 40 11 0b 11 08 08 08 08 c0 a8 00 64 00 35 ed 6e 00 75 91 e8 7f da 81 80 00 01 00 04 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 05 00 01 00 00 0c fb 00 11 04 74 69 6d 65 01 67 07 61 61 70 6c 69 6d 67 c0 17 c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 fd c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 7d c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 54 fb Unfortunately, it seems the packet is not being written back correctly to the TUN interface. I'm not seeing any expected DNS response behavior on the device. Also, I noticed that after creating the TUN, the interface address shows up as 0.0.0.0:0 in Xcode. The system log includes this message when connecting the VPN: NWPath does not have valid interface: satisfied (Path is satisfied), interface: utun20[endc_sub6], ipv4, dns, expensive, uses cellular Does anyone know how to properly initialize the TUN so that the system recognizes it with a valid IP configuration? Or why my written-back packet might be getting ignored? Any help would be appreciated!
1
0
86
Jul ’25