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

Title: DNS Proxy Not Capturing Traffic When Public DNS Is Set in WiFi Settings
I'm working on a Network Extension using NEDNSProxyProvider to inspect DNS traffic. However, I've run into a couple of issues: DNS Proxy is not capturing traffic when a public DNS (like 8.8.8.8 or 1.1.1.1) is manually configured in the WiFi settings. It seems like the system bypasses the proxy in this case. Is this expected behavior? Is there a way to force DNS traffic through the proxy even if a public DNS is set? Using DNS Proxy and DNS Settings simultaneously doesn't work. Is there a known limitation or a correct way to combine these? How to set DNS or DNSSettings using DNSProxy? import NetworkExtension import SystemExtensions import SwiftUI protocol DNSProxyManagerDelegate { func managerStateDidChange(_ manager: DNSProxyManager) } class DNSProxyManager: NSObject { private let manager = NEDNSProxyManager.shared() var delegate: DNSProxyManagerDelegate? private(set) var isEnabled: Bool = false { didSet { delegate?.managerStateDidChange(self) } } var completion: (() -> Void)? override init() { super.init() self.load() } func toggle() { isEnabled ? disable() : start() } private func start() { let request = OSSystemExtensionRequest .activationRequest(forExtensionWithIdentifier: Constants.extensionBundleID, queue: DispatchQueue.main) request.delegate = self OSSystemExtensionManager.shared.submitRequest(request) log.info("Submitted extension activation request") } private func enable() { update { self.manager.localizedDescription = "DNS Proxy" let proto = NEDNSProxyProviderProtocol() proto.providerBundleIdentifier = Constants.extensionBundleID self.manager.providerProtocol = proto self.manager.isEnabled = true } } private func disable() { update { self.manager.isEnabled = false } } private func remove() { update { self.manager.removeFromPreferences { _ in self.isEnabled = self.manager.isEnabled } } } private func update(_ body: @escaping () -> Void) { self.manager.loadFromPreferences { (error) in if let error = error { log.error("Failed to load DNS manager: \(error)") return } self.manager.saveToPreferences { (error) in if let error = error { return } log.info("Saved DNS manager") self.isEnabled = self.manager.isEnabled } } } private func load() { manager.loadFromPreferences { error in guard error == nil else { return } self.isEnabled = self.manager.isEnabled } } } extension DNSProxyManager: OSSystemExtensionRequestDelegate { func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) { log.info("Extension activation request needs user approval") } func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) { log.error("Extension activation request failed: \(error)") } func request(_ request: OSSystemExtensionRequest, foundProperties properties: [OSSystemExtensionProperties]) { log.info("Extension activation request found properties: \(properties)") } func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) { guard result == .completed else { log.error("Unexpected result \(result.description) for system extension request") return } log.info("Extension activation request did finish with result: \(result.description)") enable() } func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction { log.info("Existing extension willt be replaced: \(existing.bundleIdentifier) -> \(ext.bundleIdentifier)") return .replace } } import NetworkExtension class DNSProxyProvider: NEDNSProxyProvider { var handlers: [String: FlowHandler] = [:] var isReady = false let queue = DispatchQueue(label: "DNSProxyProvider") override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) { completionHandler(nil) } override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { completionHandler() } override func handleNewUDPFlow(_ flow: NEAppProxyUDPFlow, initialRemoteEndpoint remoteEndpoint: NWEndpoint) -> Bool { let id = shortUUID() handlers[id] = FlowHandler(flow: flow, remoteEndpoint: remoteEndpoint, id: id, delegate: self) return true } override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { return false } } class FlowHandler { let id: String let flow: NEAppProxyUDPFlow let remoteEndpoint: NWHostEndpoint let delegate: FlowHandlerDelegate private var connections: [String: RemoteConnection] = [:] private var pendingPacketsByDomain: [String: [(packet: Data, endpoint: NWEndpoint, uniqueID: String, timestamp: Date)]] = [:] private let packetQueue = DispatchQueue(label: "com.flowhandler.packetQueue") init(flow: NEAppProxyUDPFlow, remoteEndpoint: NWEndpoint, id: String, delegate: FlowHandlerDelegate) { log.info("Flow received for \(id) flow: \(String(describing: flow))") self.flow = flow self.remoteEndpoint = remoteEndpoint as! NWHostEndpoint self.id = id self.delegate = delegate defer { start() } } deinit { closeAll(nil) } func start() { flow.open(withLocalEndpoint: flow.localEndpoint as? NWHostEndpoint) { error in if let error = error { self.delegate.flowClosed(self) return } self.readFromFlow() } } func readFromFlow() { self.flow.readDatagrams { packets, endpoint, error in if let error = error { self.closeAll(error) return } guard let packets = packets, let endpoints = endpoint, !packets.isEmpty, !endpoints.isEmpty else { self.closeAll(nil) return } self.processFlowPackets(packets, endpoints) self.readFromFlow() } } } Any insights or suggestions would be greatly appreciated. Thanks!
2
3
336
Apr ’25
Content Filter Permission Prompt Not Appearing in TestFlight
I added a Content Filter to my app, and when running it in Xcode (Debug/Release), I get the expected permission prompt: "Would like to filter network content (Allow / Don't Allow)". However, when I install the app via TestFlight, this prompt doesn’t appear at all, and the feature doesn’t work. Is there a special configuration required for TestFlight? Has anyone encountered this issue before? Thanks!
23
1
1.1k
1w
Title: Accessing Wi-Fi SSID for custom On-Demand logic in PacketTunnelProvider on macOS
We are developing a macOS VPN application using NEPacketTunnelProvider with a custom encryption protocol. We are using standard On-Demand VPN rules with Wi-Fi SSID matching but we want to add some additional feature to the native behaviour.  We want to control the 'conenect/disconnect' button status and allow the user to interact with the tunnel even when the on demand rule conditions are satisfied, is there a native way to do it? In case we need to implement our custom on-demand behaviour we need to access to this information: connected interface type ssid name and being informed when it changes so to trigger our logic, how to do it from the app side? we try to use CWWiFiClient along with ssidDidChangeForWiFiInterface monitoring, it returns just the interface name en0 and not the wifi ssid name. Is location access mandatory to access wifi SSID on macOS even if we have a NEPacketTunnelProvider? Please note that we bundle our Network Extension as an App Extension (not SystemExtension).
9
2
381
Jan ’26
Performance degradation of HTTP/3 requests in iOS app under specific network conditions
Hello Apple Support Team, We are experiencing a performance issue with HTTP/3 in our iOS application during testing. Problem Description: Network requests using HTTP/3 are significantly slower than expected. This issue occurs on both Wi-Fi and 4G networks, with both IPv4 and IPv6. The same setup worked correctly in an earlier experiment. Key Observations: The slowdown disappears when the device uses: · A personal hotspot. · Network Link Conditioner (with no limitations applied). · Internet sharing from a MacBook via USB (where traffic was also inspected with Wireshark without issues). The problem is specific to HTTP/3 and does not occur with HTTP/2. The issue is reproducible on iOS 15, 18.7, and the latest iOS 26 beta. HTTP/3 is confirmed to be active (via assumeHttp3Capable and Alt-Svc header). Crucially, the same backend endpoint works with normal performance on Android devices and using curl with HTTP/3 support from the same network. I've checked the CFNetwork logs in the Console but haven't found any suspicious errors or obvious clues that explain the slowdown. We are using a standard URLSession with basic configuration. Attempted to collect qlog diagnostics by setting the QUIC_LOG_DIRECTORY=~/ tmp environment variable, but the logs were not generated. Question: What could cause HTTP/3 performance to improve only when the device is connected through a hotspot, unrestricted Network Link Conditioner, or USB-tethered connection? The fact that Android and curl work correctly points to an issue specific to the iOS network stack. Are there known conditions or policies (e.g., related to network interface handling, QoS, or specific packet processing) that could lead to this behavior? Additionally, why might the qlog environment variable fail to produce logs, and are there other ways to obtain detailed HTTP/3 diagnostic information from iOS? Any guidance on further diagnostic steps or specific system logs to examine would be greatly appreciated. Thank you for your assistance.
6
0
461
Nov ’25
When updating a VPN app with `includeAllNetworks`, the newer instance of the packet tunnel is not started via on-demand rules
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?
7
3
652
Jan ’26
Trying to make the URL filter sample work
Hello, I've been experimenting with the new NEURLFilter API and so far the results are kind of strange. SimpleURLFilter sample contains a bloom filter that seems to be built from this dataset in pir-service-example. I was able to run SimpleURLFilter sample and configure it to use PIRService from the example repo. I also observed the requests that iOS has been sending: requesting config and then sending /queries request. What I haven't seen is any .deny verdict for any URL. Even when calling NEURLFilter.verdict(for: url) directly I cannot see a .deny verdict. Is there anything wrong with the sample or is there a known issue with NEURLFilter in the current beta (beta 8) that prevents it from working?
2
3
318
Aug ’25
URLSessionWebSocketTask reports closeCode as invalid when state is completed
I am using a URLSessionWebSocketTask. When trying to receive messages while the app is backgrounded, the receive() method fails with an NSError where the domain is NSPOSIXErrorDomain and the code is ECONNABORTED. That behavior is good. However, when this happens, the URLSessionWebSocketTask reports a closeCode of invalid, which is supposed to denote that the connection is still open. However, the connection state property is reporting completed. I feel that the closeCode property should be reporting something like abnormalClosure in this case. Either way, this seems like a bug or the documentation is incorrect.
2
3
208
Apr ’25
Xcode 16.4 and above build error with Network Extension and WireGuard library
I have added a Network Extension to my iOS project to use the WireGuard library. Everything was working fine up to Xcode 16, but after updating, I’m facing a build issue. The build fails with the following error: No such file or directory: '@rpath/WireGuardNetworkExtensioniOS.debug.dylib' I haven’t explicitly added any .dylib to my project. The Network Extension target builds and runs fine on Xcode 16.
2
3
195
Sep ’25
Disable URLSession auto retry policy
We are developing an iOS application that is interacting with HTTP APIs that requires us to put a unique UUID (a nonce) as an header on every request (obviously there's more than that, but that's irrilevant to the question here). If the same nonce is sent on two subsequent requests the server returns a 412 error. We should avoid generating this kind of errors as, if repeated, they may be flagged as a malicious activity by the HTTP APIs. We are using URLSession.shared.dataTaskPublisher(for: request) to call the HTTP APIs with request being generated with the unique nonce as an header. On our field tests we are seeing a few cases of the same HTTP request (same nonce) being repeated a few seconds on after the other. Our code has some retry logic only on 401 errors, but that involves a token refresh, and this is not what we are seeing from logs. We were able to replicate this behaviour on our own device using Network Link Conditioner with very bad performance, with XCode's Network inspector attached we can be certain that two HTTP requests with identical headers are actually made automatically, the first request has an "End Reason" of "Retry", the second is "Success" with Status 412. Our questions are: can we disable this behaviour? can we provide a new request for the retry (so that we can update headers)? Thanks, Francesco
7
3
356
Aug ’25
App Crashes on iOS 26 in Network.framework / boringssl – objc_release & memory corruption
Hello Apple Support Team, We are seeing a production crash on iOS 26 devices that appears to originate from Apple system frameworks rather than application code. 1. Crash Details OS Version: iOS 26.x App built with: Xcode 16 Devices: Multiple models (not device-specific) Exception Type: SIGSEGV SEGV_ACCERR Fault Address: 0x0000000000000100 Crashed Thread: 4 (network background queue) Crash trace summary: Last Exception : 0 libobjc.A.dylib _objc_release_x8 + 8 1 libboringssl.dylib _nw_protocol_boringssl_deallocate_options + 92 2 Network 0x000000019695207c 0x00000001968dc000 + 483452 3 libswiftCore.dylib __swift_release_dealloc + 56 4 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 5 Network 0x0000000196951f6c 0x00000001968dc000 + 483180 6 Network 0x0000000196952000 0x00000001968dc000 + 483328 7 libswiftCore.dylib __swift_release_dealloc + 56 8 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 9 libswiftCore.dylib void multiPayloadEnumFN<&handleRefCountsDestroy>(swift::TargetMetadata<swift::InProcess> const*, swift::LayoutStringReader1&, unsigned long&, unsigned char*) + 248 10 libswiftCore.dylib swift::swift_cvw_arrayDestroy(swift::OpaqueValue*, unsigned long, unsigned long, swift::TargetMetadata<swift::InProcess> const*) + 1172 11 libswiftCore.dylib _$sSp12deinitialize5countSvSi_tF + 40 12 CollectionsInternal ___swift_instantiateGenericMetadata + 1236 13 CollectionsInternal ___swift_instantiateGenericMetadata + 388 14 CollectionsInternal ___swift_instantiateGenericMetadata + 1044 15 libswiftCore.dylib __swift_release_dealloc + 56 16 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 17 Network 0x000000019695f9fc 0x00000001968dc000 + 539132 18 Network 0x000000019695f9bc 0x00000001968dc000 + 539068 19 libswiftCore.dylib __swift_release_dealloc + 56 20 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 21 libswiftCore.dylib swift_cvw_destroyImpl(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*) + 212 22 Network 0x0000000196def5d8 0x00000001968dc000 + 5322200 23 Network 0x0000000196ded130 0x00000001968dc000 + 5312816 24 libswiftCore.dylib __swift_release_dealloc + 56 25 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 26 Network 0x000000019695fde0 0x00000001968dc000 + 540128 27 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 28 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 29 libobjc.A.dylib __objc_rootDealloc + 72 30 Network 0x000000019695f99c 0x00000001968dc000 + 539036 31 Network 0x000000019695fae4 0x00000001968dc000 + 539364 32 Network 0x0000000196b078b8 0x00000001968dc000 + 2275512 33 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 34 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 35 libobjc.A.dylib __objc_rootDealloc + 72 36 Network 0x0000000196b07658 0x00000001968dc000 + 2274904 37 Network 0x00000001968e51d4 nw_queue_context_async_if_needed + 92 38 Network 0x0000000197686ea0 0x00000001968dc000 + 14331552 39 libswiftCore.dylib swift::swift_cvw_arrayDestroy(swift::OpaqueValue*, unsigned long, unsigned long, swift::TargetMetadata<swift::InProcess> const*) + 436 40 libswiftCore.dylib _$sSp12deinitialize5countSvSi_tF + 40 41 CollectionsInternal ___swift_instantiateGenericMetadata + 1236 42 CollectionsInternal ___swift_instantiateGenericMetadata + 388 43 CollectionsInternal ___swift_instantiateGenericMetadata + 1044 44 libswiftCore.dylib __swift_release_dealloc + 56 45 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 46 Network 0x000000019694a010 0x00000001968dc000 + 450576 47 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 48 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 49 libobjc.A.dylib __objc_rootDealloc + 72 50 Network 0x0000000196a330e0 0x00000001968dc000 + 1405152 51 Network 0x00000001974378e0 0x00000001968dc000 + 11909344 52 Network 0x0000000196a17178 0x00000001968dc000 + 1290616 53 libdispatch.dylib __dispatch_call_block_and_release + 32 54 libdispatch.dylib __dispatch_client_callout + 16 55 libdispatch.dylib _dispatch_workloop_invoke.cold.4 + 32 56 libdispatch.dylib __dispatch_workloop_invoke + 1980 57 libdispatch.dylib __dispatch_root_queue_drain_deferred_wlh + 292 58 libdispatch.dylib __dispatch_workloop_worker_thread + 692 59 libsystem_pthread.dylib __pthread_wqthread + 292 ------ Exception Type: SIGSEGV SEGV_ACCERR Exception Codes: fault addr: 0x0000000000000100 Crashed Thread: 4 2. Behavior & Context The crash occurs during normal HTTPS networking using standard URLSession (no direct usage of Network.framework nor boringssl APIs). It appears to be triggered during QUIC connection establishment or TLS fallback. The stack trace contains no application code frames — all symbols are from system libraries. The crash strongly indicates double-free, over-release, or dangling pointer inside nw_protocol_boringssl_options deallocation. 3. Questions for Apple Is this a known issue in iOS 26 within Network.framework / boringssl related to nw_protocol_boringssl_deallocate_options? What is the root cause of the over‑release / invalid objc_release in this path? Is there a workaround we can implement from the app side (e.g., disabling QUIC, adjusting TLS settings, or queue configuration)? Do you have a target iOS version or patch where this issue will be fixed? We can provide full crash logs and additional metrics upon request. 4. Additional Information Developed using Swift 5, with a deployment target of iOS 12+. Thank you for your support.
1
2
149
Mar ’26
Local Network permission on macOS 15 macOS 26: multicast behaves inconsistently and regularly drops
Problem description Since macOS Sequoia, our users have experienced issues with multicast traffic in our macOS app. Regularly, the app starts but cannot receive multicast, or multicast eventually stops mid-execution. The app sometimes asks again for Local Network permission, while it was already allowed so. Several versions of our app on a single machine are sometimes (but not always) shown as different instances in the System Settings > Privacy & Security > Local Network list. And when several instances are shown in that list, disabling one disables all of them, but it does not actually forbids the app from receiving multicast traffic. All of those issues are experienced by an increasing number of users after they update their system from macOS 14 to macOS 15 or 26, and many of them have reported networking issues during production-critical moments. We haven't been able to find the root cause of those issues, so we built a simple test app, called "FM Mac App Test", that can reproduce multicast issues. This app creates a GCDAsyncUdpSocket socket to receive multicast packets from a piece of hardware we also develop, and displays a simple UI showing if such packets are received. The app is entitled with "Custom Network Protocol", is built against x86_64 and arm64, and is archived (signed and notarized). We can share the source code if requested. Out of the many issues our main app exhibits, the test app showcases some: The app asks several times for Local Network permission, even after being allowed so previously. After allowing the app's Local Network and rebooting the machine, the System Settings > Privacy & Security > Local Network does not show the app, and the app asks again for Local Network access. The app shows a different Local Network Usage Description than in the project's plist. Several versions of the app appear as different instances in the Privacy list, and behave strangely. Toggling on or off one instance toggles the others. Only one version of the app seems affected by the setting, the other versions always seem to have access to Local Network even when the toggle is set to off. We even did see messages from different app versions in different user accounts. This seems to contradicts Apple's documentation that states user accounts have independent Privacy settings. Can you help us understand what we are missing (in terms of build settings, entitlements, proper archiving...) so our app conforms to what macOS expects for proper Local Network behavior? Related material Local Network Privacy breaks Application: this issue seemed related to ours, but the fix was to ensure different versions of the app have different UUIDs. We ensured that ourselves, to no improvement. Local Network FAQ Technote TN3179 Steps to Reproduce Test App is developed on Xcode 15.4 (15F31d) on macOS 14.5 (23F79), and runs on macOS 26.0.1 (25A362). We can share the source code if requested. On a clean install of macOS Tahoe (our test setup used macOS 26.0.1 on a Mac mini M2 8GB), we upload the app (version 5.1). We run the app, make sure the selected NIC is the proper one, and open the multicast socket. The app asks us to allow Local Network, we allow it. The alert shows a different Local Network Usage Description than the one we set in our project's plist. The app properly shows packets are received from the console on our LAN. We check the list in System Settings > Privacy & Security > Local Network, it includes our app properly allowed. We then reboot the machine. After reboot, the same list does not show the app anymore. We run the app, it asks again about Local Network access (still with incorrect Usage Description). We allow it again, but no console packet is received yet. Only after closing and reopening the socket are the console packets received. After a 2nd reboot, the System Settings > Privacy & Security > Local Network list shows correctly the app. The app seems to now run fine. We then upload an updated version of the same app (5.2), also built and notarized. The 2nd version is simulating when we send different versions of our main app to our users. The updated version has a different UUID than the 1st version. The updated version also asks for Local Network access, this time with proper Usage Description. A 3rd updated version of the app (5.3, also with unique UUID) behaves the same. The System Settings > Privacy & Security > Local Network list shows three instances of the app. We toggle off one of the app, all of them toggle off. The 1st version of the app (5.1) does not have local network access anymore, but both 2nd and 3rd versions do, while their toggle button seems off. We toggle on one of the app, all of them toggle on. All 3 versions have local network access.
19
2
813
2d
Need Inputs on Which Extension to Use
Hi all, I have a working macOS (Intel) system extension app that currently uses only a Content Filter (NEFilterDataProvider). I need to capture/log HTTP and HTTPS traffic in plain text, and I understand NETransparentProxyProvider is the right extension type for that. For HTTPS I will need TLS inspection / a MITM proxy — I’m new to that and unsure how complex it will be. For DNS data (in plain text), can I use the same extension, or do I need a separate extension type such as NEPacketTunnelProvider, NEFilterPacketProvider, or NEDNSProxyProvider? Current architecture: Two Xcode targets: MainApp and a SystemExtension target. The SystemExtension target contains multiple network extension types. MainApp ↔ SystemExtension communicate via a bidirectional NSXPC connection. I can already enable two extensions (Content Filter and TransparentProxy). With the NETransparentProxy, I still need to implement HTTPS capture. Questions I’d appreciate help with: Can NETransparentProxy capture the DNS fields I need (dns_hostname, dns_query_type, dns_response_code, dns_answer_number, etc.), or do I need an additional extension type to capture DNS in plain text? If a separate extension is required, is it possible or problematic to include that extension type (Packet Tunnel / DNS Proxy / etc.) in the same SystemExtension Xcode target as the TransparentProxy? Any recommended resources or guidance on TLS inspection / MITM proxy setup for capturing HTTPS logs? There are multiple DNS transport types — am I correct that capturing DNS over UDP (port 53) is not necessarily sufficient? Which DNS types should I plan to handle? I’ve read that TransparentProxy and other extension types (e.g., Packet Tunnel) cannot coexist in the same Xcode target. Is that true? Best approach for delivering logs from multiple extensions to the main app (is it feasible)? Or what’s the best way to capture logs so an external/independent process (or C/C++ daemon) can consume them? Required data to capture (not limited to): All HTTP/HTTPS (request, body, URL, response, etc.) DNS fields: dns_hostname, dns_query_type, dns_response_code, dns_answer_number, and other DNS data — all in plain text. I’ve read various resources but remain unclear which extension(s) to use and whether multiple extension types can be combined in one Xcode target. Please ask if you need more details. Thank you.
5
0
307
Jan ’26
Archived app failing to get root certificates for SSL websocket connection
I've had a Unreal Engine project that uses libwebsocket to make a websocket connection with SSL to a server. Recently I made a build using Unreal Engine 5.4.4 on MacOS Sequoia 15.5 and XCode 16.4 and for some reason the websocket connection now fails because it can't get the local issuer certificate. It fails to access the root certificate store on my device (Even though, running the project in the Unreal Editor works fine, it's only when making a packaged build with XCode that it breaks) I am not sure why this is suddenly happening now. If I run it in the Unreal editor on my macOS it works fine and connects. But when I make a packaged build which uses XCode to build, it can't get the local issuer certificate. I tried different code signing options, such as sign to run locally or just using sign automatically with a valid team, but I'm not sure if code signing is the cause of this issue or not. This app is only for development and not meant to be published, so that's why I had been using sign to run locally, and that used to work fine but not anymore. Any guidance would be appreciated, also any information on what may have changed that now causes this certificate issue to happen. I know Apple made changes and has made notarizing MacOS apps mandatory, but I'm not sure if that also means a non-notarized app will now no longer have access to the root certificate store of a device, in my research I haven't found anything about that specifically, but I'm wondering if any Apple engineers might know something about this that hasn't been put out publicly.
6
0
172
Nov ’25
Push notifications not delivered over Wi-Fi with includeAllNetworks = true regardless of excludeAPNS setting
We have a VPN app that uses NEPacketTunnelProvider with includeAllNetworks = true. We've encountered an issue where push notifications are not delivered over Wi-Fi while the tunnel is active in a pre-MFA quarantine state (tunnel is up but traffic is blocked on server side), regardless of whether excludeAPNS is set to true or false. Observed behavior Wi-Fi excludeAPNS = true - Notifications not delivered Wi-Fi excludeAPNS = false - Notifications not delivered Cellular excludeAPNS = true - Notifications delivered Cellular excludeAPNS = false - Notifications not delivered On cellular, the behavior matches our expectations: setting excludeAPNS = true allows APNS traffic to bypass the tunnel and notifications arrive; setting it to false routes APNS through the tunnel and notifications are blocked (as expected for a non-forwarding tunnel). On Wi-Fi, notifications fail to deliver in both cases. Our question Is this expected behavior when includeAllNetworks is enabled on Wi-Fi, or is this a known issue / bug with APNS delivery? Is there something else in the Wi-Fi networking path that includeAllNetworks affects beyond routing, which could prevent APNS from functioning even when the traffic is excluded from the tunnel? Sample Project Below is the minimal code that reproduces this issue. The project has two targets: a main app and a Network Extension. The tunnel provider captures all IPv4 and IPv6 traffic via default routes but does not forward packets — simulating a pre-MFA quarantine state. The main app configures the tunnel with includeAllNetworks = true and provides a UI toggle for excludeAPNS. PacketTunnelProvider.swift (Network Extension target): import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") let ipv4 = NEIPv4Settings(addresses: ["198.51.100.1"], subnetMasks: ["255.255.255.0"]) ipv4.includedRoutes = [NEIPv4Route.default()] settings.ipv4Settings = ipv4 let ipv6 = NEIPv6Settings(addresses: ["fd00::1"], networkPrefixLengths: [64]) ipv6.includedRoutes = [NEIPv6Route.default()] settings.ipv6Settings = ipv6 let dns = NEDNSSettings(servers: ["198.51.100.1"]) settings.dnsSettings = dns settings.mtu = 1400 setTunnelNetworkSettings(settings) { error in if let error = error { completionHandler(error) return } self.readPackets() completionHandler(nil) } } private func readPackets() { packetFlow.readPackets { [weak self] packets, protocols in self?.readPackets() } } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { if let handler = completionHandler { handler(messageData) } } override func sleep(completionHandler: @escaping () -> Void) { completionHandler() } override func wake() { } } ContentView.swift (Main app target) — trimmed to essentials: import SwiftUI import NetworkExtension struct ContentView: View { @State private var excludeAPNs = false @State private var manager: NETunnelProviderManager? var body: some View { VStack { Toggle("Exclude APNs", isOn: $excludeAPNs) .onChange(of: excludeAPNs) { Task { await saveAndReload() } } Button("Connect") { Task { await toggleVPN() } } } .padding() .task { await loadManager() } } private func loadManager() async { let managers = try? await NETunnelProviderManager.loadAllFromPreferences() if let existing = managers?.first { manager = existing } else { let m = NETunnelProviderManager() let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = "<your-extension-bundle-id>" proto.serverAddress = "127.0.0.1" proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs m.protocolConfiguration = proto m.localizedDescription = "TestVPN" m.isEnabled = true try? await m.saveToPreferences() try? await m.loadFromPreferences() manager = m } if let proto = manager?.protocolConfiguration as? NETunnelProviderProtocol { excludeAPNs = proto.excludeAPNs } } private func saveAndReload() async { guard let manager else { return } if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs } manager.isEnabled = true try? await manager.saveToPreferences() try? await manager.loadFromPreferences() } private func toggleVPN() async { guard let manager else { return } if manager.connection.status == .connected { manager.connection.stopVPNTunnel() } else { await saveAndReload() try? manager.connection.startVPNTunnel() } } } Steps to reproduce Build and run the sample project with above code on a physical iOS device. Connect to a Wi-Fi network. Set excludeAPNS = true using the toggle and tap Connect. Send a push notification to the device to a test app with remote notification capability (e.g., via a test push service or the push notification console). Observe that the notification is not delivered. Disconnect. Switch to cellular. Reconnect with the same settings. Send the same push notification — observe that it is delivered. Environment iOS 26.2 Xcode 26.2 Physical device (iPhone 15 Pro)
5
1
253
Mar ’26
App occasionally fails to connect to Access Point (iPhone17 / iOS26)
Hi, My app uses the NetworkExtension framework to connect to an access point. For some reason, my app occasionally fails to find and/or connect to my AP (which I know is online and beaconing on a given frequency). This roughly happens 1/10 times. I am using an iPhone 17, running iOS 26.0.1. I am connecting to a WPA2-Personal network. In the iPhone system logs, I see the following: Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: Dequeuing command type: "Scan" pending commands: 0 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceCopyPreparedScanResults: network records count: 0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: WiFi infra associated, NAN DISABLED, , DFS state Off, IR INACTIVE, llwLink ACTIVE, RTM-DP 0, allowing scans Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: isScanDisallowedByAwdl[1148] : InfraScanAllowed 1 (RTModeScan 0 NonSteering 0 assistDisc 0 HTMode 0 RTModeNeeded 0 Immin 0 ScanType 1 Flags 0 ScanOn2GOnly 0 DevAllows2G 1) Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x2(oldState 0) on:1, source:ScanManagerFamily, err:0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: setScanningState:: Scan request from ScanManagerFamily. Time since last scan(1.732 s) Number of channels(0), 2.4 only(no), isDFSScan 0, airplaying 0, scanningState 0x2 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x2(oldState 0) on:1, source:ScanManagerFamily, err:0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: Controller Scan Started, scan state 0 -> 2 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x0(oldState 2) on:0, source:ScanError, err:3766617154 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: setScanningState[23946]:: Scan complete for source(8)ScanError. Time(0.000 s), airplaying 0, scanningState 0x0 oldState 0x2 rtModeActive 0 (ProxSetup 0 curSchedState 3) Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x0(oldState 2) on:0, source:ScanError, err:3766617154 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: Controller Scan Done, scan state 2 -> 0 Oct 10 10:34:10 wifid(IO80211)[54] <Notice>: Apple80211IOCTLSetWrapper:6536 @[35563.366221] ifname['en0'] IOUC type 10/'APPLE80211_IOC_SCAN_REQ', len[5528] return -528350142/0xe0820442 Oct 10 10:34:10 wifid[54] <Notice>: [WiFiPolicy] {SCAN-} Completed Apple80211ScanAsync on en0 (0xe0820442) with 0 networks Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceCreateFilteredScanResults: null scanResults Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceCreateFilteredScanResults: rssiThresh 0, doTrimming 0, scanResultsCount: 0, trimmedScanResultsCount: 0, filteredScanResultsCount: 0, nullNetworksCount: 0 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerDispatchUserForcedAssociationCallback: result 1 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceManagerForcedAssociationCallback: failed to association error 1 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: WiFiLocalizationGetLocalizedString: lang='en_GB' key='WIFI_JOIN_NETWORK_FAILURE_TITLE' value='Unable to join the network \M-b\M^@\M^\%@\M-b\M^@\M^]' Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: WiFiLocalizationGetLocalizedString: lang='en_GB' key='WIFI_FAILURE_OK' value='OK' Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerUserForcedAssociationScanCallback: scan results were empty It looks like there is a scan error, and I see the error: failed to association error 1. I have also seen the iOS device find the SSID but fail to associate (associated error 2): Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiMetricsManagerCopyLinkChangeNetworkParams: updating AccessPointInfo: { DeviceNameElement = testssid; ManufacturerElement = " "; ModelName = " "; ModelNumber = " "; } Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiMetricsManagerCopyLinkChangeNetworkParams: minSupportDataRate 6, maxSupportDataRate 54 Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: Disassociated. Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiMetricsManagerUpdateDBAndSubmitAssociationFailure: Failed to append deauthSourceOUI to CA event Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiMetricsManagerUpdateDBAndSubmitAssociationFailure: Failed to append bssidOUI to CA event ..... <log omitted> ..... <log omitted> Oct 8 12:25:52 wifid(CoreWiFi)[54] <Notice>: [corewifi] END REQ [GET SSID] took 0.005530542s (pid=260 proc=mediaplaybackd bundleID=com.apple.mediaplaybackd codesignID=com.apple.mediaplaybackd service=com.apple.private.corewifi-xpc qos=21 intf=(null) uuid=D67EF err=-528342013 reply=(null) Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Presenting a CFUserNotification with reply port: 259427 on behalf of: wifid.54 Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Received request to activate alertItem: <SBUserNotificationAlert: 0xc20a49b80; title: Unable to join the network \M-b\M^@\M^\\134^Htestssid\134^?\M-b\M^@\M^]; source: wifid; pid: 54> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerUserForcedAssociationCallback: failed forced association Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Activation - Presenting <SBUserNotificationAlert: 0xc20a49b80; title: Unable to join the network \M-b\M^@\M^\\134^Htestssid\134^?\M-b\M^@\M^]; source: wifid; pid: 54> with presenter: <SBUnlockedAlertItemPresenter: 0xc1d9f6530> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerDispatchUserForcedAssociationCallback: result 2 Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Activation - Presenter:<SBUnlockedAlertItemPresenter: 0xc1d9f6530> will present presentation: <SBAlertItemPresentation: 0xc1cd40820; alertItem: <SBUserNotificationAlert: 0xc20a49b80; presented: NO>; presenter: <SBUnlockedAlertItemPresenter: 0xc1d9f6530>> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceManagerForcedAssociationCallback: failed to association error 2 Anyone able to help with this?
7
0
303
Nov ’25
NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
I'm implementing a NEDNSProxyProvider on macOS 15.x and macOS 26.x. The flow works correctly up to the last step — returning the DNS response to the client via writeDatagrams. Environment: macOS 15.x, 26.x Xcode 26.x NEDNSProxyProvider with NEAppProxyUDPFlow What I'm doing: override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { guard let udpFlow = flow as? NEAppProxyUDPFlow else { return false } udpFlow.readDatagrams { datagrams, endpoints, error in // 1. Read DNS request from client // 2. Forward to upstream DNS server via TCP // 3. Receive response from upstream // 4. Try to return response to client: udpFlow.writeDatagrams([responseData], sentBy: [endpoints.first!]) { error in // Always fails: "The datagram was too large" // responseData is 50-200 bytes — well within UDP limits } } return true } Investigation: I added logging to check the type of endpoints.first : // On macOS 15.0 and 26.3.1: // type(of: endpoints.first) → NWAddressEndpoint // Not NWHostEndpoint as expected On both macOS 15.4 and 26.3.1, readDatagrams returns [NWEndpoint] where each endpoint appears to be NWAddressEndpoint — a type that is not publicly documented. When I try to create NWHostEndpoint manually from hostname and port, and pass it to writeDatagrams, the error "The datagram was too large" still occurs in some cases. Questions: What is the correct endpoint type to pass to writeDatagrams on macOS 15.x, 26.x? Should we pass the exact same NWEndpoint objects returned by readDatagrams, or create new ones? NWEndpoint, NWHostEndpoint, and writeDatagrams are all deprecated in macOS 15. Is there a replacement API for NEAppProxyUDPFlow that works with nw_endpoint_t from the Network framework? Is the error "The datagram was too large" actually about the endpoint type rather than the data size? Any guidance would be appreciated. :-))
7
0
144
2d
Bonjour Conformance Test WARNING in Multicast DNS SHARED REPLY TIMING resolution
Hello and Good day! We are conducting Bonjour Conformance Test (BCT) for Printer device. BCT result is PASSED but with warning in Multicast DNS, specifically, WARNING: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION Other Shared Reply Timing is passed: PASSED: MULTIPLE QUESTIONS - SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION Environment: BCT Tool Version: 1.5.4 (15400) MacOS Sequioa 15.5 DUT Firmware : Linux Debian 9 Apple mDNSResponder 1790.80.10 Service types: _ipps._tcp, _uscans._tcp, _ipp._tcp, _uscan._tcp Router : NEC AtermWR8370N Setup: 1-to-1 [Mac->Router<-DUT connection] Based on debug.log, this is where WARNING occurs: NOTICE 2026-03-04 10:51:06.870187+0900 _shared_reply_timing 04103: Shared reply response times: min = 26ms, max = 114ms, avg = 65.50ms WARNING 2026-03-04 10:51:06.870361+0900 _shared_reply_timing 04136: 50 percent of the replies within the correct range fell in the interval 20ms and 46ms (should be close to 25%). PASSED (SHARED REPLY TIMING) In the same debug.log for MULTIPLE QUESTIONS - SHARED REPLY TIMING is PASSED: NOTICE 2026-03-04 10:52:29.912334+0900 _shared_reply_timing 04103: Shared reply response times: min = 22ms, max = 112ms, avg = 78.00ms DEBUG_2 2026-03-04 10:52:29.912849+0900 recv_packet 01997: received packet (558 bytes) PASSED (MULTIPLE QUESTIONS - SHARED REPLY TIMING) [Details] Looking at Bonjour_Conformance_Guideline.pdf https://download.aninterestingwebsite.com/Documentation/Bonjour_Conformance_Test_Guideline/Bonjour_Conformance_Guideline.pdf there were some differences: In 1.6.2 Expected Result: Test Result File of Test that All Tests Passed, this is not displayed: PASSED: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION And in II.8 Shared Reply Timing: (Ideally, 25% of the answers should fall in each 21ms quadrant of the range 20ms - 125ms.) and comparing to the debug.log, there was a discrepancy of the interval, because 20ms and 46ms is 26ms interval. From RFC6762 6. Responding, Ideal range is from 20ms-120ms Because of this, please advise on the questions below: I would like to know on the possible cause and resolution for these WARNINGS. And since in current BCT result, (Test result integrity signature is generated), I would like to know if this is acceptable for BCT certification. Thank you.
9
0
241
2w
Wi-Fi Aware between iOS 26 and Android device
Eager to see the Wi-Fi Aware communication between iPhone (iOS 26) and an Android device, I tried iOS 26 beta on my iPhone16. and tried below code snippet from provided example at https://aninterestingwebsite.com/documentation/wifiaware/building-peer-to-peer-apps. Idea is to first verify discovery of Android WiFiAware service on iOS. extension WAPublishableService { public static var simulationService: WAPublishableService { allServices[simulationServiceName]! } } extension WASubscribableService { public static var simulationService: WASubscribableService { allServices[simulationServiceName]! } } struct ContentView: View { @State private var showingDevicePicker = false @State private var pairedDevices: [WAPairedDevice] = [] // To hold discovered/paired devices var body: some View { VStack { Button("Discover Devices") { showingDevicePicker = true // Trigger the device picker presentation } .sheet(isPresented: $showingDevicePicker) { DevicePicker(.wifiAware(.connecting(to: .selected([]), from: .simulationService))) { endpoint in print("Paired Endpoint: \(endpoint)") } label: { Image(systemName: "plus") Text("Add Device") } fallback: { Image(systemName: "xmark.circle") Text("Unavailable") } } List(pairedDevices) { device in Text(device.name ?? "Unknown Device") } } } } With suggested entitlement of WiFiAware and info.plist of service info. Then I had Android device with WIFiAware service publishing service (service name set '_sat-simulation._udp') from this app https://github.com/anagramrice/NAN. But above iOS app is unable to find the service published from android device. Am I missing something? Note: the above Android-NAN app seems to be working fine between Android to Another Android.
21
2
1.8k
Sep ’25
Does URLSession support ticket-based TLS session resumption
My company has a server that supports ticket-based TLS session resumption (per RFC 5077). We have done Wireshark captures that show that our iOS client app, which uses URLSession for REST and WebSocket connections to the server, is not sending the TLS "session_ticket" extension in the Client Hello package that necessary to enable ticket-based resumption with the server. Is it expected that URLSession does not support ticket-based TLS session resumption? If "yes", is there any way to tell URLSession to enable ticket-based session resumption? the lower-level API set_protocol_options_set_tls_tickets_enabled() hints that the overall TLS / HTTP stack on IOS does support ticket-based resumption, but I can't see how to use that low-level API with URLSession. I can provide (lots) more technical details if necessary, but hopefully this is enough context to determine whether ticket-based TLS resumption is supported with URLSession. Any tips / clarifications would be greatly appreciated.
6
2
734
Aug ’25
Connection drops while using Content Filter & App Proxy Provider
I have a network extension that hosts a NEFilterDataProvider & NETransparentProxyProvider. One of the use case that this caters to is : Proxy some flows (depending on originating app) while Content filter is also filtering flows based on business logic. The issue I am running into happens when FilterDataProvider sees a flow & responds with filterDataVerdict(withFilterInbound: false, peekInboundBytes: 0, filterOutbound: true, peekOutboundBytes:1024 to handleNewFlow(_ flow: NEFilterFlow) [wants to peek more bytes on outbound connection before making a decision] TransparentProxyProvider sees the flow & responds with NO to handleNewFlow(_ flow: NEAppProxyFlow) as it is not interested in in proxying that flow. When this occurs, we see connection being dropped by kernel. I wanted to know if this is expected behavior. Logs when this occurs: 2026-02-06 14:57:09.725854-0600 0x17c918f Default 0x0 569 0 com.test.networkextension: (NetworkExtension) [com.apple.networkextension:] [Extension com.test.network]: provider rejected new flow TCP headless_shell[{length = 20, bytes = 0xe69023e655b6065e1a2f94fa508807fa43f6ac8a}] remote: 100.72.0.3:443 interface utun9 2026-02-06 14:57:09.725874-0600 0x17ca166 Debug 0x0 569 0 com.test.networkextension: (NetworkExtension) [com.apple.networkextension:] New flow verdict for D89B5B5D-793C-4940-D955-37BE33F18005: drop = NO remediate = NO needRules = NO shouldReport = YES pause = NO urlAppendString = NO filterInbound = NO peekInboundBytes = 0 filterOutbound = YES peekOutboundBytes = 1024 statisticsReportFrequency = low 2026-02-06 14:57:09.726009-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Closing reads (sending SHUT_WR), closed by plugin (flow error: 0) 2026-02-06 14:57:09.726028-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Closing writes, sending SHUT_RD 2026-02-06 14:57:09.726040-0600 0x17ca24a Debug 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Dropping the director 2026-02-06 14:57:09.726047-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Destroying, client tx 0, client rx 0, kernel rx 0, kernel tx 0 I wanted to know how neagent is handling this when for a flow, filterDataProvider wants to look at the traffic while transparentProxy is not interested in handling that flow
3
0
131
Feb ’26
Title: DNS Proxy Not Capturing Traffic When Public DNS Is Set in WiFi Settings
I'm working on a Network Extension using NEDNSProxyProvider to inspect DNS traffic. However, I've run into a couple of issues: DNS Proxy is not capturing traffic when a public DNS (like 8.8.8.8 or 1.1.1.1) is manually configured in the WiFi settings. It seems like the system bypasses the proxy in this case. Is this expected behavior? Is there a way to force DNS traffic through the proxy even if a public DNS is set? Using DNS Proxy and DNS Settings simultaneously doesn't work. Is there a known limitation or a correct way to combine these? How to set DNS or DNSSettings using DNSProxy? import NetworkExtension import SystemExtensions import SwiftUI protocol DNSProxyManagerDelegate { func managerStateDidChange(_ manager: DNSProxyManager) } class DNSProxyManager: NSObject { private let manager = NEDNSProxyManager.shared() var delegate: DNSProxyManagerDelegate? private(set) var isEnabled: Bool = false { didSet { delegate?.managerStateDidChange(self) } } var completion: (() -> Void)? override init() { super.init() self.load() } func toggle() { isEnabled ? disable() : start() } private func start() { let request = OSSystemExtensionRequest .activationRequest(forExtensionWithIdentifier: Constants.extensionBundleID, queue: DispatchQueue.main) request.delegate = self OSSystemExtensionManager.shared.submitRequest(request) log.info("Submitted extension activation request") } private func enable() { update { self.manager.localizedDescription = "DNS Proxy" let proto = NEDNSProxyProviderProtocol() proto.providerBundleIdentifier = Constants.extensionBundleID self.manager.providerProtocol = proto self.manager.isEnabled = true } } private func disable() { update { self.manager.isEnabled = false } } private func remove() { update { self.manager.removeFromPreferences { _ in self.isEnabled = self.manager.isEnabled } } } private func update(_ body: @escaping () -> Void) { self.manager.loadFromPreferences { (error) in if let error = error { log.error("Failed to load DNS manager: \(error)") return } self.manager.saveToPreferences { (error) in if let error = error { return } log.info("Saved DNS manager") self.isEnabled = self.manager.isEnabled } } } private func load() { manager.loadFromPreferences { error in guard error == nil else { return } self.isEnabled = self.manager.isEnabled } } } extension DNSProxyManager: OSSystemExtensionRequestDelegate { func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) { log.info("Extension activation request needs user approval") } func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) { log.error("Extension activation request failed: \(error)") } func request(_ request: OSSystemExtensionRequest, foundProperties properties: [OSSystemExtensionProperties]) { log.info("Extension activation request found properties: \(properties)") } func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) { guard result == .completed else { log.error("Unexpected result \(result.description) for system extension request") return } log.info("Extension activation request did finish with result: \(result.description)") enable() } func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction { log.info("Existing extension willt be replaced: \(existing.bundleIdentifier) -> \(ext.bundleIdentifier)") return .replace } } import NetworkExtension class DNSProxyProvider: NEDNSProxyProvider { var handlers: [String: FlowHandler] = [:] var isReady = false let queue = DispatchQueue(label: "DNSProxyProvider") override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) { completionHandler(nil) } override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { completionHandler() } override func handleNewUDPFlow(_ flow: NEAppProxyUDPFlow, initialRemoteEndpoint remoteEndpoint: NWEndpoint) -> Bool { let id = shortUUID() handlers[id] = FlowHandler(flow: flow, remoteEndpoint: remoteEndpoint, id: id, delegate: self) return true } override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { return false } } class FlowHandler { let id: String let flow: NEAppProxyUDPFlow let remoteEndpoint: NWHostEndpoint let delegate: FlowHandlerDelegate private var connections: [String: RemoteConnection] = [:] private var pendingPacketsByDomain: [String: [(packet: Data, endpoint: NWEndpoint, uniqueID: String, timestamp: Date)]] = [:] private let packetQueue = DispatchQueue(label: "com.flowhandler.packetQueue") init(flow: NEAppProxyUDPFlow, remoteEndpoint: NWEndpoint, id: String, delegate: FlowHandlerDelegate) { log.info("Flow received for \(id) flow: \(String(describing: flow))") self.flow = flow self.remoteEndpoint = remoteEndpoint as! NWHostEndpoint self.id = id self.delegate = delegate defer { start() } } deinit { closeAll(nil) } func start() { flow.open(withLocalEndpoint: flow.localEndpoint as? NWHostEndpoint) { error in if let error = error { self.delegate.flowClosed(self) return } self.readFromFlow() } } func readFromFlow() { self.flow.readDatagrams { packets, endpoint, error in if let error = error { self.closeAll(error) return } guard let packets = packets, let endpoints = endpoint, !packets.isEmpty, !endpoints.isEmpty else { self.closeAll(nil) return } self.processFlowPackets(packets, endpoints) self.readFromFlow() } } } Any insights or suggestions would be greatly appreciated. Thanks!
Replies
2
Boosts
3
Views
336
Activity
Apr ’25
Content Filter Permission Prompt Not Appearing in TestFlight
I added a Content Filter to my app, and when running it in Xcode (Debug/Release), I get the expected permission prompt: "Would like to filter network content (Allow / Don't Allow)". However, when I install the app via TestFlight, this prompt doesn’t appear at all, and the feature doesn’t work. Is there a special configuration required for TestFlight? Has anyone encountered this issue before? Thanks!
Replies
23
Boosts
1
Views
1.1k
Activity
1w
Title: Accessing Wi-Fi SSID for custom On-Demand logic in PacketTunnelProvider on macOS
We are developing a macOS VPN application using NEPacketTunnelProvider with a custom encryption protocol. We are using standard On-Demand VPN rules with Wi-Fi SSID matching but we want to add some additional feature to the native behaviour.  We want to control the 'conenect/disconnect' button status and allow the user to interact with the tunnel even when the on demand rule conditions are satisfied, is there a native way to do it? In case we need to implement our custom on-demand behaviour we need to access to this information: connected interface type ssid name and being informed when it changes so to trigger our logic, how to do it from the app side? we try to use CWWiFiClient along with ssidDidChangeForWiFiInterface monitoring, it returns just the interface name en0 and not the wifi ssid name. Is location access mandatory to access wifi SSID on macOS even if we have a NEPacketTunnelProvider? Please note that we bundle our Network Extension as an App Extension (not SystemExtension).
Replies
9
Boosts
2
Views
381
Activity
Jan ’26
Performance degradation of HTTP/3 requests in iOS app under specific network conditions
Hello Apple Support Team, We are experiencing a performance issue with HTTP/3 in our iOS application during testing. Problem Description: Network requests using HTTP/3 are significantly slower than expected. This issue occurs on both Wi-Fi and 4G networks, with both IPv4 and IPv6. The same setup worked correctly in an earlier experiment. Key Observations: The slowdown disappears when the device uses: · A personal hotspot. · Network Link Conditioner (with no limitations applied). · Internet sharing from a MacBook via USB (where traffic was also inspected with Wireshark without issues). The problem is specific to HTTP/3 and does not occur with HTTP/2. The issue is reproducible on iOS 15, 18.7, and the latest iOS 26 beta. HTTP/3 is confirmed to be active (via assumeHttp3Capable and Alt-Svc header). Crucially, the same backend endpoint works with normal performance on Android devices and using curl with HTTP/3 support from the same network. I've checked the CFNetwork logs in the Console but haven't found any suspicious errors or obvious clues that explain the slowdown. We are using a standard URLSession with basic configuration. Attempted to collect qlog diagnostics by setting the QUIC_LOG_DIRECTORY=~/ tmp environment variable, but the logs were not generated. Question: What could cause HTTP/3 performance to improve only when the device is connected through a hotspot, unrestricted Network Link Conditioner, or USB-tethered connection? The fact that Android and curl work correctly points to an issue specific to the iOS network stack. Are there known conditions or policies (e.g., related to network interface handling, QoS, or specific packet processing) that could lead to this behavior? Additionally, why might the qlog environment variable fail to produce logs, and are there other ways to obtain detailed HTTP/3 diagnostic information from iOS? Any guidance on further diagnostic steps or specific system logs to examine would be greatly appreciated. Thank you for your assistance.
Replies
6
Boosts
0
Views
461
Activity
Nov ’25
When updating a VPN app with `includeAllNetworks`, the newer instance of the packet tunnel is not started via on-demand rules
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?
Replies
7
Boosts
3
Views
652
Activity
Jan ’26
Trying to make the URL filter sample work
Hello, I've been experimenting with the new NEURLFilter API and so far the results are kind of strange. SimpleURLFilter sample contains a bloom filter that seems to be built from this dataset in pir-service-example. I was able to run SimpleURLFilter sample and configure it to use PIRService from the example repo. I also observed the requests that iOS has been sending: requesting config and then sending /queries request. What I haven't seen is any .deny verdict for any URL. Even when calling NEURLFilter.verdict(for: url) directly I cannot see a .deny verdict. Is there anything wrong with the sample or is there a known issue with NEURLFilter in the current beta (beta 8) that prevents it from working?
Replies
2
Boosts
3
Views
318
Activity
Aug ’25
URLSessionWebSocketTask reports closeCode as invalid when state is completed
I am using a URLSessionWebSocketTask. When trying to receive messages while the app is backgrounded, the receive() method fails with an NSError where the domain is NSPOSIXErrorDomain and the code is ECONNABORTED. That behavior is good. However, when this happens, the URLSessionWebSocketTask reports a closeCode of invalid, which is supposed to denote that the connection is still open. However, the connection state property is reporting completed. I feel that the closeCode property should be reporting something like abnormalClosure in this case. Either way, this seems like a bug or the documentation is incorrect.
Replies
2
Boosts
3
Views
208
Activity
Apr ’25
Xcode 16.4 and above build error with Network Extension and WireGuard library
I have added a Network Extension to my iOS project to use the WireGuard library. Everything was working fine up to Xcode 16, but after updating, I’m facing a build issue. The build fails with the following error: No such file or directory: '@rpath/WireGuardNetworkExtensioniOS.debug.dylib' I haven’t explicitly added any .dylib to my project. The Network Extension target builds and runs fine on Xcode 16.
Replies
2
Boosts
3
Views
195
Activity
Sep ’25
Disable URLSession auto retry policy
We are developing an iOS application that is interacting with HTTP APIs that requires us to put a unique UUID (a nonce) as an header on every request (obviously there's more than that, but that's irrilevant to the question here). If the same nonce is sent on two subsequent requests the server returns a 412 error. We should avoid generating this kind of errors as, if repeated, they may be flagged as a malicious activity by the HTTP APIs. We are using URLSession.shared.dataTaskPublisher(for: request) to call the HTTP APIs with request being generated with the unique nonce as an header. On our field tests we are seeing a few cases of the same HTTP request (same nonce) being repeated a few seconds on after the other. Our code has some retry logic only on 401 errors, but that involves a token refresh, and this is not what we are seeing from logs. We were able to replicate this behaviour on our own device using Network Link Conditioner with very bad performance, with XCode's Network inspector attached we can be certain that two HTTP requests with identical headers are actually made automatically, the first request has an "End Reason" of "Retry", the second is "Success" with Status 412. Our questions are: can we disable this behaviour? can we provide a new request for the retry (so that we can update headers)? Thanks, Francesco
Replies
7
Boosts
3
Views
356
Activity
Aug ’25
App Crashes on iOS 26 in Network.framework / boringssl – objc_release & memory corruption
Hello Apple Support Team, We are seeing a production crash on iOS 26 devices that appears to originate from Apple system frameworks rather than application code. 1. Crash Details OS Version: iOS 26.x App built with: Xcode 16 Devices: Multiple models (not device-specific) Exception Type: SIGSEGV SEGV_ACCERR Fault Address: 0x0000000000000100 Crashed Thread: 4 (network background queue) Crash trace summary: Last Exception : 0 libobjc.A.dylib _objc_release_x8 + 8 1 libboringssl.dylib _nw_protocol_boringssl_deallocate_options + 92 2 Network 0x000000019695207c 0x00000001968dc000 + 483452 3 libswiftCore.dylib __swift_release_dealloc + 56 4 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 5 Network 0x0000000196951f6c 0x00000001968dc000 + 483180 6 Network 0x0000000196952000 0x00000001968dc000 + 483328 7 libswiftCore.dylib __swift_release_dealloc + 56 8 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 9 libswiftCore.dylib void multiPayloadEnumFN<&handleRefCountsDestroy>(swift::TargetMetadata<swift::InProcess> const*, swift::LayoutStringReader1&, unsigned long&, unsigned char*) + 248 10 libswiftCore.dylib swift::swift_cvw_arrayDestroy(swift::OpaqueValue*, unsigned long, unsigned long, swift::TargetMetadata<swift::InProcess> const*) + 1172 11 libswiftCore.dylib _$sSp12deinitialize5countSvSi_tF + 40 12 CollectionsInternal ___swift_instantiateGenericMetadata + 1236 13 CollectionsInternal ___swift_instantiateGenericMetadata + 388 14 CollectionsInternal ___swift_instantiateGenericMetadata + 1044 15 libswiftCore.dylib __swift_release_dealloc + 56 16 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 17 Network 0x000000019695f9fc 0x00000001968dc000 + 539132 18 Network 0x000000019695f9bc 0x00000001968dc000 + 539068 19 libswiftCore.dylib __swift_release_dealloc + 56 20 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 21 libswiftCore.dylib swift_cvw_destroyImpl(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*) + 212 22 Network 0x0000000196def5d8 0x00000001968dc000 + 5322200 23 Network 0x0000000196ded130 0x00000001968dc000 + 5312816 24 libswiftCore.dylib __swift_release_dealloc + 56 25 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 26 Network 0x000000019695fde0 0x00000001968dc000 + 540128 27 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 28 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 29 libobjc.A.dylib __objc_rootDealloc + 72 30 Network 0x000000019695f99c 0x00000001968dc000 + 539036 31 Network 0x000000019695fae4 0x00000001968dc000 + 539364 32 Network 0x0000000196b078b8 0x00000001968dc000 + 2275512 33 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 34 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 35 libobjc.A.dylib __objc_rootDealloc + 72 36 Network 0x0000000196b07658 0x00000001968dc000 + 2274904 37 Network 0x00000001968e51d4 nw_queue_context_async_if_needed + 92 38 Network 0x0000000197686ea0 0x00000001968dc000 + 14331552 39 libswiftCore.dylib swift::swift_cvw_arrayDestroy(swift::OpaqueValue*, unsigned long, unsigned long, swift::TargetMetadata<swift::InProcess> const*) + 436 40 libswiftCore.dylib _$sSp12deinitialize5countSvSi_tF + 40 41 CollectionsInternal ___swift_instantiateGenericMetadata + 1236 42 CollectionsInternal ___swift_instantiateGenericMetadata + 388 43 CollectionsInternal ___swift_instantiateGenericMetadata + 1044 44 libswiftCore.dylib __swift_release_dealloc + 56 45 libswiftCore.dylib bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 152 46 Network 0x000000019694a010 0x00000001968dc000 + 450576 47 libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 116 48 libobjc.A.dylib objc_destructInstance_nonnull_realized(objc_object*) + 76 49 libobjc.A.dylib __objc_rootDealloc + 72 50 Network 0x0000000196a330e0 0x00000001968dc000 + 1405152 51 Network 0x00000001974378e0 0x00000001968dc000 + 11909344 52 Network 0x0000000196a17178 0x00000001968dc000 + 1290616 53 libdispatch.dylib __dispatch_call_block_and_release + 32 54 libdispatch.dylib __dispatch_client_callout + 16 55 libdispatch.dylib _dispatch_workloop_invoke.cold.4 + 32 56 libdispatch.dylib __dispatch_workloop_invoke + 1980 57 libdispatch.dylib __dispatch_root_queue_drain_deferred_wlh + 292 58 libdispatch.dylib __dispatch_workloop_worker_thread + 692 59 libsystem_pthread.dylib __pthread_wqthread + 292 ------ Exception Type: SIGSEGV SEGV_ACCERR Exception Codes: fault addr: 0x0000000000000100 Crashed Thread: 4 2. Behavior & Context The crash occurs during normal HTTPS networking using standard URLSession (no direct usage of Network.framework nor boringssl APIs). It appears to be triggered during QUIC connection establishment or TLS fallback. The stack trace contains no application code frames — all symbols are from system libraries. The crash strongly indicates double-free, over-release, or dangling pointer inside nw_protocol_boringssl_options deallocation. 3. Questions for Apple Is this a known issue in iOS 26 within Network.framework / boringssl related to nw_protocol_boringssl_deallocate_options? What is the root cause of the over‑release / invalid objc_release in this path? Is there a workaround we can implement from the app side (e.g., disabling QUIC, adjusting TLS settings, or queue configuration)? Do you have a target iOS version or patch where this issue will be fixed? We can provide full crash logs and additional metrics upon request. 4. Additional Information Developed using Swift 5, with a deployment target of iOS 12+. Thank you for your support.
Replies
1
Boosts
2
Views
149
Activity
Mar ’26
Local Network permission on macOS 15 macOS 26: multicast behaves inconsistently and regularly drops
Problem description Since macOS Sequoia, our users have experienced issues with multicast traffic in our macOS app. Regularly, the app starts but cannot receive multicast, or multicast eventually stops mid-execution. The app sometimes asks again for Local Network permission, while it was already allowed so. Several versions of our app on a single machine are sometimes (but not always) shown as different instances in the System Settings > Privacy & Security > Local Network list. And when several instances are shown in that list, disabling one disables all of them, but it does not actually forbids the app from receiving multicast traffic. All of those issues are experienced by an increasing number of users after they update their system from macOS 14 to macOS 15 or 26, and many of them have reported networking issues during production-critical moments. We haven't been able to find the root cause of those issues, so we built a simple test app, called "FM Mac App Test", that can reproduce multicast issues. This app creates a GCDAsyncUdpSocket socket to receive multicast packets from a piece of hardware we also develop, and displays a simple UI showing if such packets are received. The app is entitled with "Custom Network Protocol", is built against x86_64 and arm64, and is archived (signed and notarized). We can share the source code if requested. Out of the many issues our main app exhibits, the test app showcases some: The app asks several times for Local Network permission, even after being allowed so previously. After allowing the app's Local Network and rebooting the machine, the System Settings > Privacy & Security > Local Network does not show the app, and the app asks again for Local Network access. The app shows a different Local Network Usage Description than in the project's plist. Several versions of the app appear as different instances in the Privacy list, and behave strangely. Toggling on or off one instance toggles the others. Only one version of the app seems affected by the setting, the other versions always seem to have access to Local Network even when the toggle is set to off. We even did see messages from different app versions in different user accounts. This seems to contradicts Apple's documentation that states user accounts have independent Privacy settings. Can you help us understand what we are missing (in terms of build settings, entitlements, proper archiving...) so our app conforms to what macOS expects for proper Local Network behavior? Related material Local Network Privacy breaks Application: this issue seemed related to ours, but the fix was to ensure different versions of the app have different UUIDs. We ensured that ourselves, to no improvement. Local Network FAQ Technote TN3179 Steps to Reproduce Test App is developed on Xcode 15.4 (15F31d) on macOS 14.5 (23F79), and runs on macOS 26.0.1 (25A362). We can share the source code if requested. On a clean install of macOS Tahoe (our test setup used macOS 26.0.1 on a Mac mini M2 8GB), we upload the app (version 5.1). We run the app, make sure the selected NIC is the proper one, and open the multicast socket. The app asks us to allow Local Network, we allow it. The alert shows a different Local Network Usage Description than the one we set in our project's plist. The app properly shows packets are received from the console on our LAN. We check the list in System Settings > Privacy & Security > Local Network, it includes our app properly allowed. We then reboot the machine. After reboot, the same list does not show the app anymore. We run the app, it asks again about Local Network access (still with incorrect Usage Description). We allow it again, but no console packet is received yet. Only after closing and reopening the socket are the console packets received. After a 2nd reboot, the System Settings > Privacy & Security > Local Network list shows correctly the app. The app seems to now run fine. We then upload an updated version of the same app (5.2), also built and notarized. The 2nd version is simulating when we send different versions of our main app to our users. The updated version has a different UUID than the 1st version. The updated version also asks for Local Network access, this time with proper Usage Description. A 3rd updated version of the app (5.3, also with unique UUID) behaves the same. The System Settings > Privacy & Security > Local Network list shows three instances of the app. We toggle off one of the app, all of them toggle off. The 1st version of the app (5.1) does not have local network access anymore, but both 2nd and 3rd versions do, while their toggle button seems off. We toggle on one of the app, all of them toggle on. All 3 versions have local network access.
Replies
19
Boosts
2
Views
813
Activity
2d
Need Inputs on Which Extension to Use
Hi all, I have a working macOS (Intel) system extension app that currently uses only a Content Filter (NEFilterDataProvider). I need to capture/log HTTP and HTTPS traffic in plain text, and I understand NETransparentProxyProvider is the right extension type for that. For HTTPS I will need TLS inspection / a MITM proxy — I’m new to that and unsure how complex it will be. For DNS data (in plain text), can I use the same extension, or do I need a separate extension type such as NEPacketTunnelProvider, NEFilterPacketProvider, or NEDNSProxyProvider? Current architecture: Two Xcode targets: MainApp and a SystemExtension target. The SystemExtension target contains multiple network extension types. MainApp ↔ SystemExtension communicate via a bidirectional NSXPC connection. I can already enable two extensions (Content Filter and TransparentProxy). With the NETransparentProxy, I still need to implement HTTPS capture. Questions I’d appreciate help with: Can NETransparentProxy capture the DNS fields I need (dns_hostname, dns_query_type, dns_response_code, dns_answer_number, etc.), or do I need an additional extension type to capture DNS in plain text? If a separate extension is required, is it possible or problematic to include that extension type (Packet Tunnel / DNS Proxy / etc.) in the same SystemExtension Xcode target as the TransparentProxy? Any recommended resources or guidance on TLS inspection / MITM proxy setup for capturing HTTPS logs? There are multiple DNS transport types — am I correct that capturing DNS over UDP (port 53) is not necessarily sufficient? Which DNS types should I plan to handle? I’ve read that TransparentProxy and other extension types (e.g., Packet Tunnel) cannot coexist in the same Xcode target. Is that true? Best approach for delivering logs from multiple extensions to the main app (is it feasible)? Or what’s the best way to capture logs so an external/independent process (or C/C++ daemon) can consume them? Required data to capture (not limited to): All HTTP/HTTPS (request, body, URL, response, etc.) DNS fields: dns_hostname, dns_query_type, dns_response_code, dns_answer_number, and other DNS data — all in plain text. I’ve read various resources but remain unclear which extension(s) to use and whether multiple extension types can be combined in one Xcode target. Please ask if you need more details. Thank you.
Replies
5
Boosts
0
Views
307
Activity
Jan ’26
Archived app failing to get root certificates for SSL websocket connection
I've had a Unreal Engine project that uses libwebsocket to make a websocket connection with SSL to a server. Recently I made a build using Unreal Engine 5.4.4 on MacOS Sequoia 15.5 and XCode 16.4 and for some reason the websocket connection now fails because it can't get the local issuer certificate. It fails to access the root certificate store on my device (Even though, running the project in the Unreal Editor works fine, it's only when making a packaged build with XCode that it breaks) I am not sure why this is suddenly happening now. If I run it in the Unreal editor on my macOS it works fine and connects. But when I make a packaged build which uses XCode to build, it can't get the local issuer certificate. I tried different code signing options, such as sign to run locally or just using sign automatically with a valid team, but I'm not sure if code signing is the cause of this issue or not. This app is only for development and not meant to be published, so that's why I had been using sign to run locally, and that used to work fine but not anymore. Any guidance would be appreciated, also any information on what may have changed that now causes this certificate issue to happen. I know Apple made changes and has made notarizing MacOS apps mandatory, but I'm not sure if that also means a non-notarized app will now no longer have access to the root certificate store of a device, in my research I haven't found anything about that specifically, but I'm wondering if any Apple engineers might know something about this that hasn't been put out publicly.
Replies
6
Boosts
0
Views
172
Activity
Nov ’25
Push notifications not delivered over Wi-Fi with includeAllNetworks = true regardless of excludeAPNS setting
We have a VPN app that uses NEPacketTunnelProvider with includeAllNetworks = true. We've encountered an issue where push notifications are not delivered over Wi-Fi while the tunnel is active in a pre-MFA quarantine state (tunnel is up but traffic is blocked on server side), regardless of whether excludeAPNS is set to true or false. Observed behavior Wi-Fi excludeAPNS = true - Notifications not delivered Wi-Fi excludeAPNS = false - Notifications not delivered Cellular excludeAPNS = true - Notifications delivered Cellular excludeAPNS = false - Notifications not delivered On cellular, the behavior matches our expectations: setting excludeAPNS = true allows APNS traffic to bypass the tunnel and notifications arrive; setting it to false routes APNS through the tunnel and notifications are blocked (as expected for a non-forwarding tunnel). On Wi-Fi, notifications fail to deliver in both cases. Our question Is this expected behavior when includeAllNetworks is enabled on Wi-Fi, or is this a known issue / bug with APNS delivery? Is there something else in the Wi-Fi networking path that includeAllNetworks affects beyond routing, which could prevent APNS from functioning even when the traffic is excluded from the tunnel? Sample Project Below is the minimal code that reproduces this issue. The project has two targets: a main app and a Network Extension. The tunnel provider captures all IPv4 and IPv6 traffic via default routes but does not forward packets — simulating a pre-MFA quarantine state. The main app configures the tunnel with includeAllNetworks = true and provides a UI toggle for excludeAPNS. PacketTunnelProvider.swift (Network Extension target): import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") let ipv4 = NEIPv4Settings(addresses: ["198.51.100.1"], subnetMasks: ["255.255.255.0"]) ipv4.includedRoutes = [NEIPv4Route.default()] settings.ipv4Settings = ipv4 let ipv6 = NEIPv6Settings(addresses: ["fd00::1"], networkPrefixLengths: [64]) ipv6.includedRoutes = [NEIPv6Route.default()] settings.ipv6Settings = ipv6 let dns = NEDNSSettings(servers: ["198.51.100.1"]) settings.dnsSettings = dns settings.mtu = 1400 setTunnelNetworkSettings(settings) { error in if let error = error { completionHandler(error) return } self.readPackets() completionHandler(nil) } } private func readPackets() { packetFlow.readPackets { [weak self] packets, protocols in self?.readPackets() } } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { if let handler = completionHandler { handler(messageData) } } override func sleep(completionHandler: @escaping () -> Void) { completionHandler() } override func wake() { } } ContentView.swift (Main app target) — trimmed to essentials: import SwiftUI import NetworkExtension struct ContentView: View { @State private var excludeAPNs = false @State private var manager: NETunnelProviderManager? var body: some View { VStack { Toggle("Exclude APNs", isOn: $excludeAPNs) .onChange(of: excludeAPNs) { Task { await saveAndReload() } } Button("Connect") { Task { await toggleVPN() } } } .padding() .task { await loadManager() } } private func loadManager() async { let managers = try? await NETunnelProviderManager.loadAllFromPreferences() if let existing = managers?.first { manager = existing } else { let m = NETunnelProviderManager() let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = "<your-extension-bundle-id>" proto.serverAddress = "127.0.0.1" proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs m.protocolConfiguration = proto m.localizedDescription = "TestVPN" m.isEnabled = true try? await m.saveToPreferences() try? await m.loadFromPreferences() manager = m } if let proto = manager?.protocolConfiguration as? NETunnelProviderProtocol { excludeAPNs = proto.excludeAPNs } } private func saveAndReload() async { guard let manager else { return } if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs } manager.isEnabled = true try? await manager.saveToPreferences() try? await manager.loadFromPreferences() } private func toggleVPN() async { guard let manager else { return } if manager.connection.status == .connected { manager.connection.stopVPNTunnel() } else { await saveAndReload() try? manager.connection.startVPNTunnel() } } } Steps to reproduce Build and run the sample project with above code on a physical iOS device. Connect to a Wi-Fi network. Set excludeAPNS = true using the toggle and tap Connect. Send a push notification to the device to a test app with remote notification capability (e.g., via a test push service or the push notification console). Observe that the notification is not delivered. Disconnect. Switch to cellular. Reconnect with the same settings. Send the same push notification — observe that it is delivered. Environment iOS 26.2 Xcode 26.2 Physical device (iPhone 15 Pro)
Replies
5
Boosts
1
Views
253
Activity
Mar ’26
App occasionally fails to connect to Access Point (iPhone17 / iOS26)
Hi, My app uses the NetworkExtension framework to connect to an access point. For some reason, my app occasionally fails to find and/or connect to my AP (which I know is online and beaconing on a given frequency). This roughly happens 1/10 times. I am using an iPhone 17, running iOS 26.0.1. I am connecting to a WPA2-Personal network. In the iPhone system logs, I see the following: Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: Dequeuing command type: "Scan" pending commands: 0 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceCopyPreparedScanResults: network records count: 0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: WiFi infra associated, NAN DISABLED, , DFS state Off, IR INACTIVE, llwLink ACTIVE, RTM-DP 0, allowing scans Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: isScanDisallowedByAwdl[1148] : InfraScanAllowed 1 (RTModeScan 0 NonSteering 0 assistDisc 0 HTMode 0 RTModeNeeded 0 Immin 0 ScanType 1 Flags 0 ScanOn2GOnly 0 DevAllows2G 1) Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x2(oldState 0) on:1, source:ScanManagerFamily, err:0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: setScanningState:: Scan request from ScanManagerFamily. Time since last scan(1.732 s) Number of channels(0), 2.4 only(no), isDFSScan 0, airplaying 0, scanningState 0x2 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x2(oldState 0) on:1, source:ScanManagerFamily, err:0 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: Controller Scan Started, scan state 0 -> 2 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x0(oldState 2) on:0, source:ScanError, err:3766617154 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: setScanningState[23946]:: Scan complete for source(8)ScanError. Time(0.000 s), airplaying 0, scanningState 0x0 oldState 0x2 rtModeActive 0 (ProxSetup 0 curSchedState 3) Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: IO80211PeerManager::setScanningState:5756:_scanningState:0x0(oldState 2) on:0, source:ScanError, err:3766617154 Oct 10 10:34:10 kernel()[0] <Notice>: wlan0:com.apple.p2p: Controller Scan Done, scan state 2 -> 0 Oct 10 10:34:10 wifid(IO80211)[54] <Notice>: Apple80211IOCTLSetWrapper:6536 @[35563.366221] ifname['en0'] IOUC type 10/'APPLE80211_IOC_SCAN_REQ', len[5528] return -528350142/0xe0820442 Oct 10 10:34:10 wifid[54] <Notice>: [WiFiPolicy] {SCAN-} Completed Apple80211ScanAsync on en0 (0xe0820442) with 0 networks Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceCreateFilteredScanResults: null scanResults Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceCreateFilteredScanResults: rssiThresh 0, doTrimming 0, scanResultsCount: 0, trimmedScanResultsCount: 0, filteredScanResultsCount: 0, nullNetworksCount: 0 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerDispatchUserForcedAssociationCallback: result 1 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceManagerForcedAssociationCallback: failed to association error 1 Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: WiFiLocalizationGetLocalizedString: lang='en_GB' key='WIFI_JOIN_NETWORK_FAILURE_TITLE' value='Unable to join the network \M-b\M^@\M^\%@\M-b\M^@\M^]' Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: WiFiLocalizationGetLocalizedString: lang='en_GB' key='WIFI_FAILURE_OK' value='OK' Oct 10 10:34:10 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerUserForcedAssociationScanCallback: scan results were empty It looks like there is a scan error, and I see the error: failed to association error 1. I have also seen the iOS device find the SSID but fail to associate (associated error 2): Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiMetricsManagerCopyLinkChangeNetworkParams: updating AccessPointInfo: { DeviceNameElement = testssid; ManufacturerElement = " "; ModelName = " "; ModelNumber = " "; } Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiMetricsManagerCopyLinkChangeNetworkParams: minSupportDataRate 6, maxSupportDataRate 54 Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: Disassociated. Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiMetricsManagerUpdateDBAndSubmitAssociationFailure: Failed to append deauthSourceOUI to CA event Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiMetricsManagerUpdateDBAndSubmitAssociationFailure: Failed to append bssidOUI to CA event ..... <log omitted> ..... <log omitted> Oct 8 12:25:52 wifid(CoreWiFi)[54] <Notice>: [corewifi] END REQ [GET SSID] took 0.005530542s (pid=260 proc=mediaplaybackd bundleID=com.apple.mediaplaybackd codesignID=com.apple.mediaplaybackd service=com.apple.private.corewifi-xpc qos=21 intf=(null) uuid=D67EF err=-528342013 reply=(null) Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Presenting a CFUserNotification with reply port: 259427 on behalf of: wifid.54 Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Received request to activate alertItem: <SBUserNotificationAlert: 0xc20a49b80; title: Unable to join the network \M-b\M^@\M^\\134^Htestssid\134^?\M-b\M^@\M^]; source: wifid; pid: 54> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerUserForcedAssociationCallback: failed forced association Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Activation - Presenting <SBUserNotificationAlert: 0xc20a49b80; title: Unable to join the network \M-b\M^@\M^\\134^Htestssid\134^?\M-b\M^@\M^]; source: wifid; pid: 54> with presenter: <SBUnlockedAlertItemPresenter: 0xc1d9f6530> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Notice>: __WiFiDeviceManagerDispatchUserForcedAssociationCallback: result 2 Oct 8 12:25:52 SpringBoard(SpringBoard)[244] <Notice>: Activation - Presenter:<SBUnlockedAlertItemPresenter: 0xc1d9f6530> will present presentation: <SBAlertItemPresentation: 0xc1cd40820; alertItem: <SBUserNotificationAlert: 0xc20a49b80; presented: NO>; presenter: <SBUnlockedAlertItemPresenter: 0xc1d9f6530>> Oct 8 12:25:52 wifid(WiFiPolicy)[54] <Error>: __WiFiDeviceManagerForcedAssociationCallback: failed to association error 2 Anyone able to help with this?
Replies
7
Boosts
0
Views
303
Activity
Nov ’25
NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
I'm implementing a NEDNSProxyProvider on macOS 15.x and macOS 26.x. The flow works correctly up to the last step — returning the DNS response to the client via writeDatagrams. Environment: macOS 15.x, 26.x Xcode 26.x NEDNSProxyProvider with NEAppProxyUDPFlow What I'm doing: override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { guard let udpFlow = flow as? NEAppProxyUDPFlow else { return false } udpFlow.readDatagrams { datagrams, endpoints, error in // 1. Read DNS request from client // 2. Forward to upstream DNS server via TCP // 3. Receive response from upstream // 4. Try to return response to client: udpFlow.writeDatagrams([responseData], sentBy: [endpoints.first!]) { error in // Always fails: "The datagram was too large" // responseData is 50-200 bytes — well within UDP limits } } return true } Investigation: I added logging to check the type of endpoints.first : // On macOS 15.0 and 26.3.1: // type(of: endpoints.first) → NWAddressEndpoint // Not NWHostEndpoint as expected On both macOS 15.4 and 26.3.1, readDatagrams returns [NWEndpoint] where each endpoint appears to be NWAddressEndpoint — a type that is not publicly documented. When I try to create NWHostEndpoint manually from hostname and port, and pass it to writeDatagrams, the error "The datagram was too large" still occurs in some cases. Questions: What is the correct endpoint type to pass to writeDatagrams on macOS 15.x, 26.x? Should we pass the exact same NWEndpoint objects returned by readDatagrams, or create new ones? NWEndpoint, NWHostEndpoint, and writeDatagrams are all deprecated in macOS 15. Is there a replacement API for NEAppProxyUDPFlow that works with nw_endpoint_t from the Network framework? Is the error "The datagram was too large" actually about the endpoint type rather than the data size? Any guidance would be appreciated. :-))
Replies
7
Boosts
0
Views
144
Activity
2d
Bonjour Conformance Test WARNING in Multicast DNS SHARED REPLY TIMING resolution
Hello and Good day! We are conducting Bonjour Conformance Test (BCT) for Printer device. BCT result is PASSED but with warning in Multicast DNS, specifically, WARNING: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION Other Shared Reply Timing is passed: PASSED: MULTIPLE QUESTIONS - SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION Environment: BCT Tool Version: 1.5.4 (15400) MacOS Sequioa 15.5 DUT Firmware : Linux Debian 9 Apple mDNSResponder 1790.80.10 Service types: _ipps._tcp, _uscans._tcp, _ipp._tcp, _uscan._tcp Router : NEC AtermWR8370N Setup: 1-to-1 [Mac->Router<-DUT connection] Based on debug.log, this is where WARNING occurs: NOTICE 2026-03-04 10:51:06.870187+0900 _shared_reply_timing 04103: Shared reply response times: min = 26ms, max = 114ms, avg = 65.50ms WARNING 2026-03-04 10:51:06.870361+0900 _shared_reply_timing 04136: 50 percent of the replies within the correct range fell in the interval 20ms and 46ms (should be close to 25%). PASSED (SHARED REPLY TIMING) In the same debug.log for MULTIPLE QUESTIONS - SHARED REPLY TIMING is PASSED: NOTICE 2026-03-04 10:52:29.912334+0900 _shared_reply_timing 04103: Shared reply response times: min = 22ms, max = 112ms, avg = 78.00ms DEBUG_2 2026-03-04 10:52:29.912849+0900 recv_packet 01997: received packet (558 bytes) PASSED (MULTIPLE QUESTIONS - SHARED REPLY TIMING) [Details] Looking at Bonjour_Conformance_Guideline.pdf https://download.aninterestingwebsite.com/Documentation/Bonjour_Conformance_Test_Guideline/Bonjour_Conformance_Guideline.pdf there were some differences: In 1.6.2 Expected Result: Test Result File of Test that All Tests Passed, this is not displayed: PASSED: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION And in II.8 Shared Reply Timing: (Ideally, 25% of the answers should fall in each 21ms quadrant of the range 20ms - 125ms.) and comparing to the debug.log, there was a discrepancy of the interval, because 20ms and 46ms is 26ms interval. From RFC6762 6. Responding, Ideal range is from 20ms-120ms Because of this, please advise on the questions below: I would like to know on the possible cause and resolution for these WARNINGS. And since in current BCT result, (Test result integrity signature is generated), I would like to know if this is acceptable for BCT certification. Thank you.
Replies
9
Boosts
0
Views
241
Activity
2w
Wi-Fi Aware between iOS 26 and Android device
Eager to see the Wi-Fi Aware communication between iPhone (iOS 26) and an Android device, I tried iOS 26 beta on my iPhone16. and tried below code snippet from provided example at https://aninterestingwebsite.com/documentation/wifiaware/building-peer-to-peer-apps. Idea is to first verify discovery of Android WiFiAware service on iOS. extension WAPublishableService { public static var simulationService: WAPublishableService { allServices[simulationServiceName]! } } extension WASubscribableService { public static var simulationService: WASubscribableService { allServices[simulationServiceName]! } } struct ContentView: View { @State private var showingDevicePicker = false @State private var pairedDevices: [WAPairedDevice] = [] // To hold discovered/paired devices var body: some View { VStack { Button("Discover Devices") { showingDevicePicker = true // Trigger the device picker presentation } .sheet(isPresented: $showingDevicePicker) { DevicePicker(.wifiAware(.connecting(to: .selected([]), from: .simulationService))) { endpoint in print("Paired Endpoint: \(endpoint)") } label: { Image(systemName: "plus") Text("Add Device") } fallback: { Image(systemName: "xmark.circle") Text("Unavailable") } } List(pairedDevices) { device in Text(device.name ?? "Unknown Device") } } } } With suggested entitlement of WiFiAware and info.plist of service info. Then I had Android device with WIFiAware service publishing service (service name set '_sat-simulation._udp') from this app https://github.com/anagramrice/NAN. But above iOS app is unable to find the service published from android device. Am I missing something? Note: the above Android-NAN app seems to be working fine between Android to Another Android.
Replies
21
Boosts
2
Views
1.8k
Activity
Sep ’25
Does URLSession support ticket-based TLS session resumption
My company has a server that supports ticket-based TLS session resumption (per RFC 5077). We have done Wireshark captures that show that our iOS client app, which uses URLSession for REST and WebSocket connections to the server, is not sending the TLS "session_ticket" extension in the Client Hello package that necessary to enable ticket-based resumption with the server. Is it expected that URLSession does not support ticket-based TLS session resumption? If "yes", is there any way to tell URLSession to enable ticket-based session resumption? the lower-level API set_protocol_options_set_tls_tickets_enabled() hints that the overall TLS / HTTP stack on IOS does support ticket-based resumption, but I can't see how to use that low-level API with URLSession. I can provide (lots) more technical details if necessary, but hopefully this is enough context to determine whether ticket-based TLS resumption is supported with URLSession. Any tips / clarifications would be greatly appreciated.
Replies
6
Boosts
2
Views
734
Activity
Aug ’25
Connection drops while using Content Filter & App Proxy Provider
I have a network extension that hosts a NEFilterDataProvider & NETransparentProxyProvider. One of the use case that this caters to is : Proxy some flows (depending on originating app) while Content filter is also filtering flows based on business logic. The issue I am running into happens when FilterDataProvider sees a flow & responds with filterDataVerdict(withFilterInbound: false, peekInboundBytes: 0, filterOutbound: true, peekOutboundBytes:1024 to handleNewFlow(_ flow: NEFilterFlow) [wants to peek more bytes on outbound connection before making a decision] TransparentProxyProvider sees the flow & responds with NO to handleNewFlow(_ flow: NEAppProxyFlow) as it is not interested in in proxying that flow. When this occurs, we see connection being dropped by kernel. I wanted to know if this is expected behavior. Logs when this occurs: 2026-02-06 14:57:09.725854-0600 0x17c918f Default 0x0 569 0 com.test.networkextension: (NetworkExtension) [com.apple.networkextension:] [Extension com.test.network]: provider rejected new flow TCP headless_shell[{length = 20, bytes = 0xe69023e655b6065e1a2f94fa508807fa43f6ac8a}] remote: 100.72.0.3:443 interface utun9 2026-02-06 14:57:09.725874-0600 0x17ca166 Debug 0x0 569 0 com.test.networkextension: (NetworkExtension) [com.apple.networkextension:] New flow verdict for D89B5B5D-793C-4940-D955-37BE33F18005: drop = NO remediate = NO needRules = NO shouldReport = YES pause = NO urlAppendString = NO filterInbound = NO peekInboundBytes = 0 filterOutbound = YES peekOutboundBytes = 1024 statisticsReportFrequency = low 2026-02-06 14:57:09.726009-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Closing reads (sending SHUT_WR), closed by plugin (flow error: 0) 2026-02-06 14:57:09.726028-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Closing writes, sending SHUT_RD 2026-02-06 14:57:09.726040-0600 0x17ca24a Debug 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Dropping the director 2026-02-06 14:57:09.726047-0600 0x17ca24a Default 0x0 569 0 com.test.networkextension: (libnetworkextension.dylib) [com.apple.networkextension:] (410011084): Destroying, client tx 0, client rx 0, kernel rx 0, kernel tx 0 I wanted to know how neagent is handling this when for a flow, filterDataProvider wants to look at the traffic while transparentProxy is not interested in handling that flow
Replies
3
Boosts
0
Views
131
Activity
Feb ’26