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

DHCP broken when device wakeup
Many times the device totally lost connectivity, WIFI is completely down, no ip was assigned after device wakeup. From system log I can see BPF socket for DHCP was closed and detached right after attached to en0 in DHCP INIT phase, as result even the DHCP server sent back OFFER(I see server sent OFFER back from packet capture), but there is no persistent BPF socket since it is closed reception during the entire INIT phase. It is definitely an OS issue, is it a known issue? Please help understand Why BPF socket was close right after sending DISCOVER? Default 0x0 0 0 kernel: bpf26 attached to en0 by configd:331 2026-03-25 14:06:33.625851+0100 0x31dea Default 0x0 0 0 kernel: bpf26 closed and detached from en0 fcount 0 dcount 0 by configd:331 System log and packet capture attach, please check.
6
0
127
6d
UDP Broadcast with Network
I'm relatively new to socket networking, and am migrating an older project from CocoaAsyncSocket to Swift's native Network. The project utilises GCDAsyncUdpSocket.enableBroadcast(_ flag: Bool), but I don't know how to replicate this in Network. How do I enable UDP Broadcast on NWConnection?
1
0
80
6d
Regression / Feature Request: Jumbo Frame (MTU 9000) support missing in AppleUserECM for RTL8156 2.5G USB adapters
Hello, I am currently developing a headless macOS daemon (HarmonBridge) that requires extremely low-latency, high-bandwidth UDP video streaming between a Mac and a Linux host over a dedicated 2.5GbE/5GbE local network link. We are utilizing widely available Realtek RTL8156 / RTL8156B based USB 2.5G network adapters. Under macOS, these adapters default to the generic com.apple.DriverKit.AppleUserECM driver. The hardware itself natively supports Jumbo Frames (MTU 9000), but the DriverKit implementation artificially restricts the MTU cap to 1500 bytes. Because we are forced through MTU 1500, we are incurring significant performance penalties: Excessive IP fragmentation for our large UDP video payloads. Unnecessary CPU overhead due to increased hardware interrupts and header processing at 2.5Gbps speeds. For a latency-critical application like ours, reducing CPU interrupts and utilizing true hardware-level Jumbo Frames is essential. My Questions: Is there an undocumented boot-arg or network sysctl parameter that permits overriding the AppleUserECM 1500 MTU hard-limit for 2.5G USB adapters on Apple Silicon? Are there any roadmap plans from the DriverKit/Networking team to re-enable standard Jumbo Frame negotiation for RTL8156 hardware using the generic ECM driver? If the answer to both is no, does Apple grant NetworkingDriverKit Entitlements to independent developers specifically for the purpose of writing custom hardware overrides to patch missing MTU features in the default ECM stack? Because AppleUserECM effectively acts as a gatekeeper to the underlying MAC/PHY capabilities of these modern USB NICs, any guidance on achieving wire-native MTU 9000 under the current DriverKit paradigm would be hugely appreciated. Thank you!
3
1
143
1w
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
188
1w
NWHotSpotConfiguration not providing a helpful error message
I have the following code that is attempting to set up Hotspot 2.0 using an EAP-TLS configuration. I am importing a pk12 file and using those certificates. I have tried all manner of permutations for the configuration, and have narrowed down all the errors I was getting and now I am just getting a generic: Error: invalid EAP settings. I have tried adding the identity separately and either get an entitlements issue which I can't figure out why since I have added the required network extension sharing groups, or a duplicate item error, meaning it was already correctly added. The certificate and configuration are correctly working through an Android app already. static let accessGroup: String? = { guard let prefix = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as? String else { print("Could not load group") return nil } return "\(prefix)com.apple.networkextensionsharing" }() static func setupHotspot(data: CertificateData) { let h20 = NEHotspotHS20Settings(domainName: data.realm, roamingEnabled: false) h20.naiRealmNames = [data.realm] var result: CFArray? let options: [CFString: Any] = [ kSecImportExportPassphrase: "**********", kSecAttrLabel: "ident:\(data.user)", kSecAttrAccessGroup: accessGroup!, kSecReturnPersistentRef: true ] let status = SecPKCS12Import(data.p12 as CFData, options as CFDictionary, &result) guard status == errSecSuccess, let importResult = result as? [[String: Any]], let resultDict = importResult.first else { print("P12 Import failed: \(status)") return } let identity = resultDict[kSecImportItemIdentity as String] as! SecIdentity let eap = NEHotspotEAPSettings() eap.supportedEAPTypes = [NEHotspotEAPSettings.EAPType.EAPTLS.rawValue as NSNumber] eap.isTLSClientCertificateRequired = true eap.trustedServerNames = [ data.realm ] eap.outerIdentity = "anonymous" guard eap.setIdentity( identity ) else { print("setIdentity failed") return } let configuration = NEHotspotConfiguration(hs20Settings: h20, eapSettings: eap) NEHotspotConfigurationManager.shared.apply(configuration) { error in if let error = error { print("Error: \(error.localizedDescription)") } else { print("Success") } } }
3
0
67
1w
No internet after reboot for 90s
Development environment: Xcode 26.4, macOS 26.3.1 Run-time configuration: iOS 18.7.6 and higher We have an application running on supervised devices, with an MDM profile typically deployed via jamf. The profile enables a Content Filter, with the two flags "Socket Filter" and "Browser Filter" set to true. On the device side, we implement the content filter as a network extension via: a class FilterDataProvider extending NEFilterDataProvider, a class FilterControlProvider extending NEFilerControlProvider. For the record, the FilterDataProvider overrides the handle*() methods to allow all traffic; the handleNewFlow() simply reports the new connection to FilterControlProvider for analysis. Problem: some customers reported that after a reboot of their device, they would not get access to the internet for up to 60s/90s. We have not been able to reproduce the problem on our own devices. What we see is that, even with our app uninstalled, without any Content Filter, it takes roughly 20s to 25s for a device to have internet access, so we can probably consider this 20s delay as a baseline. But would you be aware of a reason that would explain the delay observed by these customers? More details: We have conducted some tests on our devices, with extended logging. In particular: we have added an internet probe in the app that is triggered when the app starts up: it will try to connect to apple.com every 2s and report success or failure, we also have a network monitor (nw_path_monitor_set_update_handler) that reacts to network stack status updates and logs the said status. A typical boot up sequence shows the following: the boot time is 7:59:05, the app starts up at 7:59:30 (manually launched when the device is ready), the probe fails and keeps failing, the content filter is initialized/started up 7:59:53 and is ready at 7:59:55, the network monitor shows that the network stack is connected (status = nw_path_status_satisfied) right after that, and the probe succeeds in connecting 2s later. In other words, internet is available about 50s after boot time, 25s after app startup (i.e. after the device is actually ready). For some customers, this 25s delay can go up to 60/90s.
1
0
47
1w
`NEProxySettings.matchDomains` / `exceptionList` not working as expected in `NEPacketTunnelProvider` (domain-scoped proxy not applied, and exceptions not bypassed)
I’m working on an iOS Network Extension where a NEPacketTunnelProviderconfigures a local HTTP/HTTPS proxy usingNEPacketTunnelNetworkSettings.proxySettings. Per NEProxySettings.exceptionList docs: If the destination host name of an HTTP connection matches one of these patterns then the proxy settings will not be used for the connection. However, I’m seeing two distinct issues: Issue A (exception bypass not working): HTTPS traffic to a host that matches exceptionList still reaches the proxy. Issue B (domain-scoped proxy not applied): When matchDomains is set to match a specific domain (example: ["googlevideo.com"]), I still observe its traffic in some apps is not proxied. If I remove the domain from matchDomains, the same traffic is proxied. Environment OS: iOS (reproduced with 26.4 and other versions) Devices: Reproduced with several iPhones (likely iPads as well) Xcode: 26.3 Extension: NEPacketTunnelProvider Minimal Repro (code) This is the minimal configuration. Toggle between CONFIG A / CONFIG B to reproduce each issue. import NetworkExtension final class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel( options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void ) { let proxyPort = 12345 // proxy listening port let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8") let proxySettings = NEProxySettings() proxySettings.httpEnabled = true proxySettings.httpsEnabled = true proxySettings.httpServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address proxySettings.httpsServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address // CONFIG A: proxy all domains, but exclude some domains // proxySettings.matchDomains can be set to match all domains // proxySettings.exceptionList = ["*.cdninstagram.com", "cdninstagram.com"] // CONFIG B: proxy only a specific domain // proxySettings.matchDomains = ["googlevideo.com"] settings.proxySettings = proxySettings setTunnelNetworkSettings(settings) { error in completionHandler(error) } } } Repro steps Issue A (exceptionList bypass not working) Enable the VPN configuration and start the tunnel with CONFIG A (exceptionList = ["*.cdninstagram.com", "cdninstagram.com"]). Open the Instagram app to trigger HTTPS connections to *.cdninstagram.com Inspect proxy logs: cdninstagram.com traffic is still received by the proxy. Safari comparison: If I access URLs that trigger the same *.cdninstagram.com hosts from Safari, it can behave as expected. When the traffic is triggered from the Instagram app, the excluded host still reaches the proxy as CONNECT, which is unexpected. Issue B (matchDomains not applied for YouTube traffic) Start the tunnel with CONFIG B (matchDomains = ["googlevideo.com"]). Open the YouTube app and start playing a video (traffic typically targets *.googlevideo.com). Inspect proxy logs: googlevideo.com traffic is not received by the proxy. Remove the host from matchDomains and observe that googlevideo.com traffic is received by the proxy. Safari comparison: If I access a googlevideo.com host from Safari while matchDomains = ["googlevideo.com"], it behaves as expected (proxied). In contrast, the YouTube app’s googlevideo.com traffic is not proxied unless I match all domains. Expected Issue A Connections to *.cdninstagram.com in the Instagram app should not use the proxy and should not reach the local proxy server. Issue B With matchDomains = ["googlevideo.com"], traffic to *.googlevideo.com (YouTube video traffic) should be proxied and therefore reach the local proxy. Actual Issue A The local proxy still receives the request as: CONNECT scontent-mad1-1.cdninstagram.com:443 HTTP/1.1 So the bypass does not happen. Issue B With matchDomains = ["googlevideo.com"], I still observe googlevideo.com traffic in the YouTube app that is not delivered to the proxy. When all traffic is proxied, the same traffic is delivered to the proxy.
1
1
91
1w
Network Extension "Signature check failed" after archive with Developer ID — works in Xcode debug
I have a macOS VPN app with a Network Extension (packet tunnel provider) distributed outside the App Store via Developer ID. Everything works perfectly when running from Xcode. After archiving and exporting for Developer ID distribution, the extension launches but immediately gets killed by nesessionmanager. The error: Signature check failed: code failed to satisfy specified code requirement(s) followed by: started with PID 0 status changed to disconnected, last stop reason Plugin failed What makes this interesting: the extension process does launch. AMFI approves it, taskgated-helper validates the provisioning profile and says allowing entitlement(s) due to provisioning profile, the sandbox is applied, PacketTunnelProvider is created — but then Apple's Security framework internally fails the designated requirement check and nesessionmanager kills the session. Key log sequence: taskgated-helper: Checking profile: Developer ID - MacOS WireGuardExtension taskgated-helper: allowing entitlement(s) for com.xx.xx.WireGuardNetworkExtension due to provisioning profile (isUPP: 1) WireGuardNetworkExtensionMac: AppSandbox request successful WireGuardNetworkExtensionMac: creating principle object: PacketTunnelProvider WireGuardNetworkExtensionMac: Signature check failed: code failed to satisfy specified code requirement(s) nesessionmanager: started with PID 0 error (null) nesessionmanager: status changed to disconnected, last stop reason Plugin failed Setup: macOS 15, Xcode 16 Developer ID Application certificate Manual code signing, Developer ID provisioning profiles with Network Extensions capability Extension in Contents/PlugIns/ (standard appex, not System Extension) Extension entitlement: packet-tunnel-provider-systemextension NSExtensionPointIdentifier: com.apple.networkextension.packet-tunnel codesign --verify --deep --strict PASSES on the exported app Hardened runtime enabled on all targets What I've verified: Both app and extension have matching TeamIdentifier Both are signed with the same Developer ID Application certificate The designated requirement correctly references the cert's OIDs The provisioning profiles are valid and taskgated-helper explicitly approves them No custom signature validation code exists in the extension — the "Signature check failed" comes from Apple's Security framework What I've tried (all produce the same error): Normal Xcode archive + export (Direct Distribution) Manual build + sign script (bypassing Xcode export entirely) Stripping all signatures and re-signing from scratch Different provisioning profiles (freshly generated) Comparison with official WireGuard app: I noticed the official WireGuard macOS app (which works with Developer ID) uses packet-tunnel-provider (without -systemextension suffix) in its entitlements. My app uses packet-tunnel-provider-systemextension. However, I cannot switch to the non-systemextension variant because the provisioning profiles from Apple Developer portal always include the -systemextension variants when "Network Extensions" capability is enabled, and AMFI rejects the mismatch. Questions: Is there a known issue with packet-tunnel-provider-systemextension entitlement + PlugIn-based Network Extension + Developer ID signing? Should the extension be using packet-tunnel-provider (without -systemextension) for Developer ID distribution? If so, how do I get a provisioning profile that allows it? The "Signature check failed" happens after taskgated-helper approves the profile — what additional code requirement check is the NE framework performing, and how can I satisfy it? Any guidance would be appreciated. I've exhausted all signing approaches I can think of.
3
0
108
1w
Debugging a Network Extension Provider
I regularly see folks struggle to debug their Network Extension providers. For an app, and indeed various app extensions, debugging is as simple as choosing Product > Run in Xcode. That’s not the case with a Network Extension provider, so I thought I’d collect together some hints and tips to help you get started. If you have any comments or questions, create a new thread here on DevForums. Put it in the App & System Services > Networking and tag it with Network Extension. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Debugging a Network Extension Provider Debugging a Network Extension provider presents some challenges; its not as simple as choosing Product > Run in Xcode. Rather, you have to run the extension first and then choose Debug > Attach to Process. Attaching is simple, it’s the running part that causes all the problems. When you first start out it can be a challenge to get your extension to run at all. Add a First Light Log Point The first step is to check whether the system is actually starting your extension. My advice is to add a first light log point, a log point on the first line of code that you control. The exact mechanics of this depend on your development, your deployment target, and your NE provider’s packaging. In all cases, however, I recommend that you log to the system log. The system log has a bunch of cool features. If you’re curious, see Your Friend the System Log. The key advantage is that your log entries are mixed in with system log entries, which makes it easier to see what else is going on when your extension loads, or fails to load. IMPORTANT Use a unique subsystem and category for your log entries. This makes it easier to find them in the system log. For more information about Network Extension packaging options, see TN3134 Network Extension provider deployment. Logging in Swift If you’re using Swift, the best logging API depends on your deployment target. On modern systems — macOS 11 and later, iOS 14 and later, and aligned OS releases — it’s best to use the Logger API, which is shiny and new and super Swift friendly. For example: let log = Logger(subsystem: "com.example.galactic-mega-builds", category: "earth") let client = "The Mice" let answer = 42 log.log(level: .debug, "run complete, client: \(client), answer: \(answer, privacy: .private)") If you support older systems, use the older, more C-like API: let log = OSLog(subsystem: "com.example.galactic-mega-builds", category: "earth") let client = "The Mice" let answer = 42 os_log(.debug, log: log, "run complete, client: %@, answer: %{private}d", client as NSString, answer) Logging in C If you prefer a C-based language, life is simpler because you only have one choice: #import <os/log.h> os_log_t log = os_log_create("com.example.galactic-mega-builds", "earth"); const char * client = "The Mice"; int answer = 42; os_log_debug(log, "run complete, client: %s, answer: %{private}d", client, answer); Add a First Light Log Point to Your App Extension If your Network Extension provider is packaged as an app extension, the best place for your first light log point is an override of the provider’s initialiser. There are a variety of ways you could structure this but here’s one possibility: import NetworkExtension import os.log class PacketTunnelProvider: NEPacketTunnelProvider { static let log = Logger(subsystem: "com.example.myvpnapp", category: "packet-tunnel") override init() { self.log = Self.log log.log(level: .debug, "first light") super.init() } let log: Logger … rest of your code here … } This uses a Swift static property to ensure that the log is constructed in a race-free manner, something that’s handy for all sorts of reasons. It’s possible for your code to run before this initialiser — for example, if you have a C++ static constructor — but that’s something that’s best to avoid. Add a First Light Log Point to Your System Extension If your Network Extension provider is packaged as a system extension, add your first light log point to main.swift. Here’s one way you might structure that: import NetworkExtension func main() -> Never { autoreleasepool { let log = PacketTunnelProvider.log log.log(level: .debug, "first light") NEProvider.startSystemExtensionMode() } dispatchMain() } main() See how the main function gets the log object from the static property on PacketTunnelProvider. I told you that’d come in handy (-: Again, it’s possible for your code to run before this but, again, that’s something that’s best to avoid. App Extension Hints Both iOS and macOS allow you to package your Network Extension provider as an app extension. On iOS this is super reliable. I’ve never seen any weirdness there. That’s not true on macOS. macOS lets the user put apps anywhere; they don’t have to be placed in the Applications directory. macOS maintains a database, the Launch Services database, of all the apps it knows about and their capabilities. The app extension infrastructure uses that database to find and load app extensions. It’s not uncommon for this database to get confused, which prevents Network Extension from loading your provider’s app extension. This is particularly common on developer machines, where you are building and rebuilding your app over and over again. The best way to avoid problems is to have a single copy of your app extension’s container app on the system. So, while you’re developing your app extension, delete any other copies of your app that might be lying around. If you run into problems you may be able to fix them using: lsregister, to interrogate and manipulate the Launch Services database pluginkit, to interrogate and manipulate the app extension state [1] IMPORTANT Both of these tools are for debugging only; they are not considered API. Also, lsregister is not on the default path; find it at /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister. For more details about pluginkit, see the pluginkit man page. When debugging a Network Extension provider, add buttons to make it easy to save and remove your provider’s configuration. For example, if you’re working on a packet tunnel provider you might add: A Save Config button that calls the saveToPreferences(completionHandler:) method to save the tunnel configuration you want to test with A Remove Config button that calls the removeFromPreferences(completionHandler:) method to remove your tunnel configuration These come in handy when you want to start again from scratch. Just click Remove Config and then Save Config and you’ve wiped the slate clean. You don’t have to leave these buttons in your final product, but it’s good to have them during bring up. [1] This tool is named after the PluginKit framework, a private framework used to load this type of app extension. It’s distinct from the ExtensionKit framework which is a new, public API for managing extensions. System Extension Hints macOS allows you to package your Network Extension provider as a system extension. For this to work the container app must be in the Applications directory [1]. Copying it across each time you rebuild your app is a chore. To avoid that, add a Build post-action script: Select your app’s scheme and choose Product > Scheme > Edit Scheme. On the left, select Build. Click the chevron to disclose all the options. Select Post-actions. In the main area, click the add (+) button and select New Run Script Action. In the “Provide build settings from” popup, select your app target. In the script field, enter this script: ditto "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "/Applications/${FULL_PRODUCT_NAME}" Now, each time you build your app, this script will copy it to the Applications directory. Build your app now, both to confirm that this works and to enable the next step. The next issue you’ll find is that choosing Product > Run runs the app from the build products directory rather than the Applications directory. To fix that: Edit your app’s scheme again. On the left, select Run. In the main area, select the Info tab. From the Executable popup, choose Other. Select the copy of your app in the Applications directory. Now, when you choose Product > Run, Xcode will run that copy rather than the one in the build products directory. Neat-o! For your system extension to run your container app must activate it. As with the Save Config and Remote Config buttons described earlier, it’s good to add easy-to-access buttons to activate and deactivate your system extension. With an app extension the system automatically terminates your extension process when you rebuild it. This is not the case with a system extension; you’ll have to deactivate and then reactivate it each time. Each activation must be approved in System Settings > Privacy & Security. To make that easier, leave System Settings running all the time. This debug cycle leaves deactivated but not removed system extensions installed on your system. These go away when you restart, so do that from time to time. Once a day is just fine. macOS includes a tool, systemextensionctl, to interrogate and manipulate system extension state. The workflow described above does not require that you use it, but it’s good to keep in mind. Its man page is largely content free so run the tool with no arguments to get help. [1] Unless you disable System Integrity Protection, but who wants to do that? You Can Attach with the Debugger Once your extension is running, attach with the debugger using one of two commands: To attach to an app extension, choose Debug > Attach to Process > YourAppExName. To attach to a system extension, choose Debug > Attach to Process by PID or Name. Make sure to select Debug Process As root. System extensions run as root so the attach will fail if you select Debug Process As Me. But Should You? Debugging networking code with a debugger is less than ideal because it’s common for in-progress network requests to time out while you’re stopped in the debugger. Debugging Network Extension providers this way is especially tricky because of the extra steps you have to take to get your provider running. So, while you can attach with the debugger, and that’s a great option in some cases, it’s often better not to do that. Rather, consider the following approach: Write the core logic of your provider so that you can unit test each subsystem outside of the provider. This may require some scaffolding but the time you take to set that up will pay off once you encounter your first gnarly problem. Add good logging to your provider to help debug problems that show up during integration testing. I recommend that you treat your logging as a feature of your product. Carefully consider where to add log points and at what level to log. Check this logging code into your source code repository and ship it — or at least the bulk of it — as part of your final product. This logging will be super helpful when it comes to debugging problems that only show up in the field. Remember that, when using the system log, log points that are present but don’t actually log anything are very cheap. In most cases it’s fine to leave these in your final product. Now go back and read Your Friend the System Log because it’s full of useful hints and tips on how to use the system log to debug the really hard problems. General Hints and Tips Install the Network Diagnostics and VPN (Network Extension) profiles [1] on your test device. These enable more logging and, most critically, the recording of private data. For more info about that last point, see… you guessed it… Your Friend the System Log. Get these profiles from our Bug Reporting > Profiles and Logs page. When you’re bringing up a Network Extension provider, do your initial testing with a tiny test app. I regularly see folks start out by running Safari and that’s less than ideal. Safari is a huge app with lots of complexity, so if things go wrong it’s hard to tell where to look. I usually create a small test app to use during bring up. The exact function of this test app varies by provider type. For example: If I’m building a packet tunnel provider, I might have a test function that makes an outgoing TCP connection to an IP address. Once I get that working I add another function that makes an outgoing TCP connection to a DNS name. Then I start testing UDP. And so on. Similarly for a content filter, but then it makes sense to add a test that runs a request using URLSession and another one to bring up a WKWebView. If I’m building a DNS proxy provider, my test app might use CFHost to run a simple name-to-address query. Also, consider doing your bring up on the Mac even if your final target is iOS. macOS has a bunch of handy tools for debugging networking issues, including: dig for DNS queries nc for TCP and UDP connections netstat to display the state of the networking stack tcpdump for recording a packet trace [2] Read their respective man pages for all the details. On the other hand, the build / run / debug cycle is simpler on iOS than it is on macOS, especially when you’re building a system extension on macOS. Even if your ultimate goal is to build a macOS-only system extension, if your provider type supports app extension packaging then you should consider whether it makes sense to adopt that packaging just for to speed up your development. If you do decide to try this, be aware that a packaging change can affect your code. See Network Extension Provider Packaging for more on that. [1] The latter is not a profile on macOS, but just a set of instructions. [2] You can use an RVI packet trace on iOS but it’s an extra setup step. Revision History 2026-04-01 Added a suggestion about provider packaging to the General Hints and Tips section. 2023-12-15 Fixed a particularly egregious typo (and spelling error in a section title, no less!). 2023-04-02 Fixed one of the steps in Sytem Extension Hints.
0
0
4.3k
1w
Random global network outage triggered by NEFilterDataProvider extension – only reboot helps, reinstall doesn't
I’m encountering a persistent issue with my Network Extension (specifically NEFilterDataProvider) and would really appreciate any insights. The extension generally works as expected, but after some time — especially after sleep/wake cycles or network changes — a global network outage occurs. During this state, no network traffic works: pings fail, browsers can’t load pages, etc. As soon as I stop the extension (by disabling it in System Preferences), the network immediately recovers. If I re-enable it, the outage returns instantly. I’ve also noticed that once this happens, the extension stops receiving callbacks like handleNewFlow(), and reinstalling the app or restarting the extension doesn’t help. The only thing that resolves the issue is rebooting the system. After reboot, the extension works fine again — until the problem reoccurs later. I asked AI about this behavior, and it suggested the possibility that the kernel might have marked the extension as untrusted, causing the system to intentionally block all network traffic as a safety mechanism. Has anyone experienced similar behavior with NEFilterDataProvider? Could there be a way to detect or prevent this state without rebooting? Is there any logging or diagnostic data I should collect when it happens again? Any guidance or pointers would be greatly appreciated. Thanks in advance!
9
0
238
1w
Crash in NetConnection::dequeue When Spawning URLSessionTasks in Loop
I'm encountering a null pointer dereference crash pointing to the internals of CFNetwork library code on iOS. I'm spawning URLSessionTasks at a decently fast rate (~1-5 per second), with the goal being to generate application layer network traffic. I can reliably encounter this crash pointing to NetConnection::dequeue right after a new task has been spawned and had the resume method called. I suspect that this is perhaps a race condition or some delegate/session object lifecycle bug. The crash appears to be more easily reproduced with a higher rate of spawning URLSessionTasks. I've included the JSON crash file, the lldb stack trace, and the source code of my URLSession(Task) usage. urlsession_stuff_stacktrace.txt urlsession_stuff_source.txt urlsession_crash_report.txt
1
0
69
1w
IPhone fails to connect with Xcode in presence of multiple WebContentFilters
I am facing an intermittent problem where iPhones are failing to pair/connect with Xcode under Xcode -> Windows -> Devices and Simulators. This happens when more than one web content filters are present, for instance, I have my web content filter (FilterSockets true, FilterGrade Firewall) and there is also Sentinel One web content filter with same configuration. Note: We are not blocking any flow from remoted / remotepairingd / core device service / MDRemoteServiceSupport etc processes. But they do get paused and resumed at times for our internal traffic verification logic. So, we are trying to understand what impact our content filter may be having on this iPhone Pairing?? If we stop either one of the filters the problem goes away. I have tracked the network traffic to the phone, and it seems to be using a ethernet interface (en5/en10) over the USB-C cable. I can see endpoints like this: localEndpoint = fe80::7:afff:fea1:edb8%en5.54442 remoteEndpoint = fe80::7:afff:fea1:ed47%en5.49813 I also see remoted process has the below ports open : sudo lsof -nP -iTCP -iUDP | grep remoted remoted 376 root 4u IPv6 0xce4a89bddba37bce 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57395->[fe80:15::7:afff:fea1:ed47]:58783 (ESTABLISHED) remoted 376 root 6u IPv6 0xf20811f6922613c7 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57396 (LISTEN) remoted 376 root 7u IPv6 0x2c393a52251fcc56 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57397 (LISTEN) remoted 376 root 8u IPv6 0xcb9c311b0ec1d6a0 0t0 TCP [fd6e:8a96:a57d::2]:57398 (LISTEN) remoted 376 root 9u IPv6 0xc582859e0623fe4e 0t0 TCP [fd6e:8a96:a57d::2]:57399 (LISTEN) remoted 376 root 10u IPv6 0x2f7d9cee24a44c5b 0t0 TCP [fd6e:8a96:a57d::2]:57400->[fd6e:8a96:a57d::1]:60448 (ESTABLISHED) remoted 376 root 11u IPv6 0xbdb7003643659de 0t0 TCP [fd07:2e7e:2a83::2]:57419 (LISTEN) remoted 376 root 12u IPv6 0x569a5b649ff8f957 0t0 TCP [fd07:2e7e:2a83::2]:57420 (LISTEN) remoted 376 root 13u IPv6 0xa034657978a7da29 0t0 TCP [fd07:2e7e:2a83::2]:57421->[fd07:2e7e:2a83::1]:61729 (ESTABLISHED) But due to the dynamic nature of port and IPs used we are not able to decide on an effective early bypass NEFilterRule. We don't want to use a very broad bypass criteria like all link local IPs etc. Any help will be greatly appreciated.
1
2
70
1w
Inquiry Regarding USB Network Connectivity Between an iPad (Wi‑Fi Model) and an Embedded Linux Device
Inquiry) Inquiry Regarding USB Network Connectivity Between an iPad (Wi‑Fi Model) and an Embedded Linux Device An embedded device (OS: Linux) is connected to an iPad (Wi‑Fi model) using a USB‑C cable. The ipheth driver is installed on the embedded device, and the iPad is recognized correctly. A web server is running on the embedded device. To launch a browser on the iPad and access the web server running on the embedded device via a USB network connection. Based on our verification, the iPad is not assigned an IP address, and therefore communication with the web server on the embedded device is not possible. We would appreciate it if you could provide guidance on the following questions. We would like to assign an IP address to the iPad (Wi‑Fi Model) so that it can communicate with the embedded device over a USB network connection. Is there a way to achieve this through the standard settings on the iPad? If this cannot be achieved through settings alone, are there any existing applications that provide this functionality? If no such application currently exists, is it technically possible to develop an application that enables this capability on iPadOS? Information) The USB‑C port on the embedded device is fixed in HOST mode. The embedded device operates as the USB host, and the iPad operates as a USB device. When a cellular model iPad is connected and “Personal Hotspot” is enabled, an IP address is assigned via DHCP, and we have confirmed that the web server can be accessed from the iPad’s browser. We are investigating whether a similar solution is possible with a Wi‑Fi model iPad.
1
0
69
1w
Can NWConnection.receive(minimumIncompleteLength:maximumLength:) return nil data for UDP while connection remains .ready?
I’m using Network Framework with UDP and calling: connection.receive(minimumIncompleteLength: 1, maximumLength: 1500) { data, context, isComplete, error in ... // Some Logic } Is it possible for this completion handler to be called with data==nil if I haven't received any kind of error, i.e., error==nil and the connection is still in the .ready state?
7
0
212
1w
test NEAppProxyProvider without MDM?
This discussion is for iOS/iPadOS. I've written an NEAppProxyProvider network extension. I'd like to test it. I thought that using the "NETestAppMapping" dictionary was a way to get there, but when I try to instantiate an NEAppProxyProviderManager to try to install stuff, the console tells me "must be MDM managed" and I get nowhere. So can someone tell me, can I at least test the idea without needing to first get MDM going? I'd like to know if how I'm approaching the core problem even makes sense. My custom application needs to stream video, via the SRT protocol, to some place like youtube or castr. The problem is that in the environment we are in (big convention centers), our devices are on a LAN, but the connection from the LAN out to the rest of the world just sucks. Surprisingly, cellular has better performance. So I am trying to do the perverse thing of forcing traffix that is NOT local to go out over cellular. And traffic that is completely local (i.e. talking to a purely local server/other devices on the LAN) happens over ethernet. [To simplify things, wifi is not connected.] Is an app proxy the right tool for this? Is there any other tool? Unfortunately, I cannot rewrite the code to force everything through Apple's Network framework, which is the one place I know we can say "use cellular." [E.g. URLSession() has absolutely no way of forcing cellular, and even so, the low level streaming library I use is written with raw sockets, and its not feasible for me to rewrite it.] Any other suggestions of how to accomplish this "send non-local traffic to cellular, all local traffic out over ethernet" gratefully welcomed!
9
0
135
1w
Understanding '.waiting' state in NWConnection.State for UDP
While going through the documentation for NWConnection, there seems to be state known as .waiting which means that the connection is waiting for a path change. For TCP, the state is understandable and can occur under some scenarios. But for the case of UDP, I have following queries: Why do we need .waiting state for the case of UDP? Even if we do need .waiting state for UDP, when all does this state occurs?
1
0
75
1w
WiFi WPA3 Cypher Problem
I've submitted a couple of pieces of feedback regarding broken WPA3 support on iOS 26 for the iPhone 17 Pro Max, and I've seen various access point vendors report that the GCMP256 cypher is not working. If you use WPA2, there is no issue. The problem I'm running into comes down to WPA3 being mandatory on 6 GHz. Some vendors have reported that disabling GCMP256 on Cisco Meraki hardware solves the problem. No other major vendor exposes this level of options. Does anyone know if it's possible to get more verbose diagnostic information out of the WiFi stack? I need actual information about why the negotiation fails, the technician-level stuff.
2
0
74
1w
URL Filter OHTTP Gateway
Hello team, We are using below example https://github.com/apple/pir-service-example as a starting point to setup PIR server for our backend, but I am not really understanding what else we need in this example to configure OHTTP gateway. Any help will be appreciated.
Replies
1
Boosts
0
Views
51
Activity
6d
DHCP broken when device wakeup
Many times the device totally lost connectivity, WIFI is completely down, no ip was assigned after device wakeup. From system log I can see BPF socket for DHCP was closed and detached right after attached to en0 in DHCP INIT phase, as result even the DHCP server sent back OFFER(I see server sent OFFER back from packet capture), but there is no persistent BPF socket since it is closed reception during the entire INIT phase. It is definitely an OS issue, is it a known issue? Please help understand Why BPF socket was close right after sending DISCOVER? Default 0x0 0 0 kernel: bpf26 attached to en0 by configd:331 2026-03-25 14:06:33.625851+0100 0x31dea Default 0x0 0 0 kernel: bpf26 closed and detached from en0 fcount 0 dcount 0 by configd:331 System log and packet capture attach, please check.
Replies
6
Boosts
0
Views
127
Activity
6d
UDP Broadcast with Network
I'm relatively new to socket networking, and am migrating an older project from CocoaAsyncSocket to Swift's native Network. The project utilises GCDAsyncUdpSocket.enableBroadcast(_ flag: Bool), but I don't know how to replicate this in Network. How do I enable UDP Broadcast on NWConnection?
Replies
1
Boosts
0
Views
80
Activity
6d
Regression / Feature Request: Jumbo Frame (MTU 9000) support missing in AppleUserECM for RTL8156 2.5G USB adapters
Hello, I am currently developing a headless macOS daemon (HarmonBridge) that requires extremely low-latency, high-bandwidth UDP video streaming between a Mac and a Linux host over a dedicated 2.5GbE/5GbE local network link. We are utilizing widely available Realtek RTL8156 / RTL8156B based USB 2.5G network adapters. Under macOS, these adapters default to the generic com.apple.DriverKit.AppleUserECM driver. The hardware itself natively supports Jumbo Frames (MTU 9000), but the DriverKit implementation artificially restricts the MTU cap to 1500 bytes. Because we are forced through MTU 1500, we are incurring significant performance penalties: Excessive IP fragmentation for our large UDP video payloads. Unnecessary CPU overhead due to increased hardware interrupts and header processing at 2.5Gbps speeds. For a latency-critical application like ours, reducing CPU interrupts and utilizing true hardware-level Jumbo Frames is essential. My Questions: Is there an undocumented boot-arg or network sysctl parameter that permits overriding the AppleUserECM 1500 MTU hard-limit for 2.5G USB adapters on Apple Silicon? Are there any roadmap plans from the DriverKit/Networking team to re-enable standard Jumbo Frame negotiation for RTL8156 hardware using the generic ECM driver? If the answer to both is no, does Apple grant NetworkingDriverKit Entitlements to independent developers specifically for the purpose of writing custom hardware overrides to patch missing MTU features in the default ECM stack? Because AppleUserECM effectively acts as a gatekeeper to the underlying MAC/PHY capabilities of these modern USB NICs, any guidance on achieving wire-native MTU 9000 under the current DriverKit paradigm would be hugely appreciated. Thank you!
Replies
3
Boosts
1
Views
143
Activity
1w
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
188
Activity
1w
NWHotSpotConfiguration not providing a helpful error message
I have the following code that is attempting to set up Hotspot 2.0 using an EAP-TLS configuration. I am importing a pk12 file and using those certificates. I have tried all manner of permutations for the configuration, and have narrowed down all the errors I was getting and now I am just getting a generic: Error: invalid EAP settings. I have tried adding the identity separately and either get an entitlements issue which I can't figure out why since I have added the required network extension sharing groups, or a duplicate item error, meaning it was already correctly added. The certificate and configuration are correctly working through an Android app already. static let accessGroup: String? = { guard let prefix = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as? String else { print("Could not load group") return nil } return "\(prefix)com.apple.networkextensionsharing" }() static func setupHotspot(data: CertificateData) { let h20 = NEHotspotHS20Settings(domainName: data.realm, roamingEnabled: false) h20.naiRealmNames = [data.realm] var result: CFArray? let options: [CFString: Any] = [ kSecImportExportPassphrase: "**********", kSecAttrLabel: "ident:\(data.user)", kSecAttrAccessGroup: accessGroup!, kSecReturnPersistentRef: true ] let status = SecPKCS12Import(data.p12 as CFData, options as CFDictionary, &result) guard status == errSecSuccess, let importResult = result as? [[String: Any]], let resultDict = importResult.first else { print("P12 Import failed: \(status)") return } let identity = resultDict[kSecImportItemIdentity as String] as! SecIdentity let eap = NEHotspotEAPSettings() eap.supportedEAPTypes = [NEHotspotEAPSettings.EAPType.EAPTLS.rawValue as NSNumber] eap.isTLSClientCertificateRequired = true eap.trustedServerNames = [ data.realm ] eap.outerIdentity = "anonymous" guard eap.setIdentity( identity ) else { print("setIdentity failed") return } let configuration = NEHotspotConfiguration(hs20Settings: h20, eapSettings: eap) NEHotspotConfigurationManager.shared.apply(configuration) { error in if let error = error { print("Error: \(error.localizedDescription)") } else { print("Success") } } }
Replies
3
Boosts
0
Views
67
Activity
1w
No internet after reboot for 90s
Development environment: Xcode 26.4, macOS 26.3.1 Run-time configuration: iOS 18.7.6 and higher We have an application running on supervised devices, with an MDM profile typically deployed via jamf. The profile enables a Content Filter, with the two flags "Socket Filter" and "Browser Filter" set to true. On the device side, we implement the content filter as a network extension via: a class FilterDataProvider extending NEFilterDataProvider, a class FilterControlProvider extending NEFilerControlProvider. For the record, the FilterDataProvider overrides the handle*() methods to allow all traffic; the handleNewFlow() simply reports the new connection to FilterControlProvider for analysis. Problem: some customers reported that after a reboot of their device, they would not get access to the internet for up to 60s/90s. We have not been able to reproduce the problem on our own devices. What we see is that, even with our app uninstalled, without any Content Filter, it takes roughly 20s to 25s for a device to have internet access, so we can probably consider this 20s delay as a baseline. But would you be aware of a reason that would explain the delay observed by these customers? More details: We have conducted some tests on our devices, with extended logging. In particular: we have added an internet probe in the app that is triggered when the app starts up: it will try to connect to apple.com every 2s and report success or failure, we also have a network monitor (nw_path_monitor_set_update_handler) that reacts to network stack status updates and logs the said status. A typical boot up sequence shows the following: the boot time is 7:59:05, the app starts up at 7:59:30 (manually launched when the device is ready), the probe fails and keeps failing, the content filter is initialized/started up 7:59:53 and is ready at 7:59:55, the network monitor shows that the network stack is connected (status = nw_path_status_satisfied) right after that, and the probe succeeds in connecting 2s later. In other words, internet is available about 50s after boot time, 25s after app startup (i.e. after the device is actually ready). For some customers, this 25s delay can go up to 60/90s.
Replies
1
Boosts
0
Views
47
Activity
1w
`NEProxySettings.matchDomains` / `exceptionList` not working as expected in `NEPacketTunnelProvider` (domain-scoped proxy not applied, and exceptions not bypassed)
I’m working on an iOS Network Extension where a NEPacketTunnelProviderconfigures a local HTTP/HTTPS proxy usingNEPacketTunnelNetworkSettings.proxySettings. Per NEProxySettings.exceptionList docs: If the destination host name of an HTTP connection matches one of these patterns then the proxy settings will not be used for the connection. However, I’m seeing two distinct issues: Issue A (exception bypass not working): HTTPS traffic to a host that matches exceptionList still reaches the proxy. Issue B (domain-scoped proxy not applied): When matchDomains is set to match a specific domain (example: ["googlevideo.com"]), I still observe its traffic in some apps is not proxied. If I remove the domain from matchDomains, the same traffic is proxied. Environment OS: iOS (reproduced with 26.4 and other versions) Devices: Reproduced with several iPhones (likely iPads as well) Xcode: 26.3 Extension: NEPacketTunnelProvider Minimal Repro (code) This is the minimal configuration. Toggle between CONFIG A / CONFIG B to reproduce each issue. import NetworkExtension final class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel( options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void ) { let proxyPort = 12345 // proxy listening port let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8") let proxySettings = NEProxySettings() proxySettings.httpEnabled = true proxySettings.httpsEnabled = true proxySettings.httpServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address proxySettings.httpsServer = NEProxyServer(address: "1.2.3.4", port: proxyPort) // proxy listening address // CONFIG A: proxy all domains, but exclude some domains // proxySettings.matchDomains can be set to match all domains // proxySettings.exceptionList = ["*.cdninstagram.com", "cdninstagram.com"] // CONFIG B: proxy only a specific domain // proxySettings.matchDomains = ["googlevideo.com"] settings.proxySettings = proxySettings setTunnelNetworkSettings(settings) { error in completionHandler(error) } } } Repro steps Issue A (exceptionList bypass not working) Enable the VPN configuration and start the tunnel with CONFIG A (exceptionList = ["*.cdninstagram.com", "cdninstagram.com"]). Open the Instagram app to trigger HTTPS connections to *.cdninstagram.com Inspect proxy logs: cdninstagram.com traffic is still received by the proxy. Safari comparison: If I access URLs that trigger the same *.cdninstagram.com hosts from Safari, it can behave as expected. When the traffic is triggered from the Instagram app, the excluded host still reaches the proxy as CONNECT, which is unexpected. Issue B (matchDomains not applied for YouTube traffic) Start the tunnel with CONFIG B (matchDomains = ["googlevideo.com"]). Open the YouTube app and start playing a video (traffic typically targets *.googlevideo.com). Inspect proxy logs: googlevideo.com traffic is not received by the proxy. Remove the host from matchDomains and observe that googlevideo.com traffic is received by the proxy. Safari comparison: If I access a googlevideo.com host from Safari while matchDomains = ["googlevideo.com"], it behaves as expected (proxied). In contrast, the YouTube app’s googlevideo.com traffic is not proxied unless I match all domains. Expected Issue A Connections to *.cdninstagram.com in the Instagram app should not use the proxy and should not reach the local proxy server. Issue B With matchDomains = ["googlevideo.com"], traffic to *.googlevideo.com (YouTube video traffic) should be proxied and therefore reach the local proxy. Actual Issue A The local proxy still receives the request as: CONNECT scontent-mad1-1.cdninstagram.com:443 HTTP/1.1 So the bypass does not happen. Issue B With matchDomains = ["googlevideo.com"], I still observe googlevideo.com traffic in the YouTube app that is not delivered to the proxy. When all traffic is proxied, the same traffic is delivered to the proxy.
Replies
1
Boosts
1
Views
91
Activity
1w
URL Filter Network Extension
Hello team, I have implemented sample project for URL Filtering as well as setup PIR server at backend but currently I am facing a major issue, If PIR server is re started then the app shows error code 9 every time until. and unless I disconnect and connect it back to internet
Replies
1
Boosts
0
Views
86
Activity
1w
Network Extension "Signature check failed" after archive with Developer ID — works in Xcode debug
I have a macOS VPN app with a Network Extension (packet tunnel provider) distributed outside the App Store via Developer ID. Everything works perfectly when running from Xcode. After archiving and exporting for Developer ID distribution, the extension launches but immediately gets killed by nesessionmanager. The error: Signature check failed: code failed to satisfy specified code requirement(s) followed by: started with PID 0 status changed to disconnected, last stop reason Plugin failed What makes this interesting: the extension process does launch. AMFI approves it, taskgated-helper validates the provisioning profile and says allowing entitlement(s) due to provisioning profile, the sandbox is applied, PacketTunnelProvider is created — but then Apple's Security framework internally fails the designated requirement check and nesessionmanager kills the session. Key log sequence: taskgated-helper: Checking profile: Developer ID - MacOS WireGuardExtension taskgated-helper: allowing entitlement(s) for com.xx.xx.WireGuardNetworkExtension due to provisioning profile (isUPP: 1) WireGuardNetworkExtensionMac: AppSandbox request successful WireGuardNetworkExtensionMac: creating principle object: PacketTunnelProvider WireGuardNetworkExtensionMac: Signature check failed: code failed to satisfy specified code requirement(s) nesessionmanager: started with PID 0 error (null) nesessionmanager: status changed to disconnected, last stop reason Plugin failed Setup: macOS 15, Xcode 16 Developer ID Application certificate Manual code signing, Developer ID provisioning profiles with Network Extensions capability Extension in Contents/PlugIns/ (standard appex, not System Extension) Extension entitlement: packet-tunnel-provider-systemextension NSExtensionPointIdentifier: com.apple.networkextension.packet-tunnel codesign --verify --deep --strict PASSES on the exported app Hardened runtime enabled on all targets What I've verified: Both app and extension have matching TeamIdentifier Both are signed with the same Developer ID Application certificate The designated requirement correctly references the cert's OIDs The provisioning profiles are valid and taskgated-helper explicitly approves them No custom signature validation code exists in the extension — the "Signature check failed" comes from Apple's Security framework What I've tried (all produce the same error): Normal Xcode archive + export (Direct Distribution) Manual build + sign script (bypassing Xcode export entirely) Stripping all signatures and re-signing from scratch Different provisioning profiles (freshly generated) Comparison with official WireGuard app: I noticed the official WireGuard macOS app (which works with Developer ID) uses packet-tunnel-provider (without -systemextension suffix) in its entitlements. My app uses packet-tunnel-provider-systemextension. However, I cannot switch to the non-systemextension variant because the provisioning profiles from Apple Developer portal always include the -systemextension variants when "Network Extensions" capability is enabled, and AMFI rejects the mismatch. Questions: Is there a known issue with packet-tunnel-provider-systemextension entitlement + PlugIn-based Network Extension + Developer ID signing? Should the extension be using packet-tunnel-provider (without -systemextension) for Developer ID distribution? If so, how do I get a provisioning profile that allows it? The "Signature check failed" happens after taskgated-helper approves the profile — what additional code requirement check is the NE framework performing, and how can I satisfy it? Any guidance would be appreciated. I've exhausted all signing approaches I can think of.
Replies
3
Boosts
0
Views
108
Activity
1w
Debugging a Network Extension Provider
I regularly see folks struggle to debug their Network Extension providers. For an app, and indeed various app extensions, debugging is as simple as choosing Product > Run in Xcode. That’s not the case with a Network Extension provider, so I thought I’d collect together some hints and tips to help you get started. If you have any comments or questions, create a new thread here on DevForums. Put it in the App & System Services > Networking and tag it with Network Extension. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Debugging a Network Extension Provider Debugging a Network Extension provider presents some challenges; its not as simple as choosing Product > Run in Xcode. Rather, you have to run the extension first and then choose Debug > Attach to Process. Attaching is simple, it’s the running part that causes all the problems. When you first start out it can be a challenge to get your extension to run at all. Add a First Light Log Point The first step is to check whether the system is actually starting your extension. My advice is to add a first light log point, a log point on the first line of code that you control. The exact mechanics of this depend on your development, your deployment target, and your NE provider’s packaging. In all cases, however, I recommend that you log to the system log. The system log has a bunch of cool features. If you’re curious, see Your Friend the System Log. The key advantage is that your log entries are mixed in with system log entries, which makes it easier to see what else is going on when your extension loads, or fails to load. IMPORTANT Use a unique subsystem and category for your log entries. This makes it easier to find them in the system log. For more information about Network Extension packaging options, see TN3134 Network Extension provider deployment. Logging in Swift If you’re using Swift, the best logging API depends on your deployment target. On modern systems — macOS 11 and later, iOS 14 and later, and aligned OS releases — it’s best to use the Logger API, which is shiny and new and super Swift friendly. For example: let log = Logger(subsystem: "com.example.galactic-mega-builds", category: "earth") let client = "The Mice" let answer = 42 log.log(level: .debug, "run complete, client: \(client), answer: \(answer, privacy: .private)") If you support older systems, use the older, more C-like API: let log = OSLog(subsystem: "com.example.galactic-mega-builds", category: "earth") let client = "The Mice" let answer = 42 os_log(.debug, log: log, "run complete, client: %@, answer: %{private}d", client as NSString, answer) Logging in C If you prefer a C-based language, life is simpler because you only have one choice: #import <os/log.h> os_log_t log = os_log_create("com.example.galactic-mega-builds", "earth"); const char * client = "The Mice"; int answer = 42; os_log_debug(log, "run complete, client: %s, answer: %{private}d", client, answer); Add a First Light Log Point to Your App Extension If your Network Extension provider is packaged as an app extension, the best place for your first light log point is an override of the provider’s initialiser. There are a variety of ways you could structure this but here’s one possibility: import NetworkExtension import os.log class PacketTunnelProvider: NEPacketTunnelProvider { static let log = Logger(subsystem: "com.example.myvpnapp", category: "packet-tunnel") override init() { self.log = Self.log log.log(level: .debug, "first light") super.init() } let log: Logger … rest of your code here … } This uses a Swift static property to ensure that the log is constructed in a race-free manner, something that’s handy for all sorts of reasons. It’s possible for your code to run before this initialiser — for example, if you have a C++ static constructor — but that’s something that’s best to avoid. Add a First Light Log Point to Your System Extension If your Network Extension provider is packaged as a system extension, add your first light log point to main.swift. Here’s one way you might structure that: import NetworkExtension func main() -> Never { autoreleasepool { let log = PacketTunnelProvider.log log.log(level: .debug, "first light") NEProvider.startSystemExtensionMode() } dispatchMain() } main() See how the main function gets the log object from the static property on PacketTunnelProvider. I told you that’d come in handy (-: Again, it’s possible for your code to run before this but, again, that’s something that’s best to avoid. App Extension Hints Both iOS and macOS allow you to package your Network Extension provider as an app extension. On iOS this is super reliable. I’ve never seen any weirdness there. That’s not true on macOS. macOS lets the user put apps anywhere; they don’t have to be placed in the Applications directory. macOS maintains a database, the Launch Services database, of all the apps it knows about and their capabilities. The app extension infrastructure uses that database to find and load app extensions. It’s not uncommon for this database to get confused, which prevents Network Extension from loading your provider’s app extension. This is particularly common on developer machines, where you are building and rebuilding your app over and over again. The best way to avoid problems is to have a single copy of your app extension’s container app on the system. So, while you’re developing your app extension, delete any other copies of your app that might be lying around. If you run into problems you may be able to fix them using: lsregister, to interrogate and manipulate the Launch Services database pluginkit, to interrogate and manipulate the app extension state [1] IMPORTANT Both of these tools are for debugging only; they are not considered API. Also, lsregister is not on the default path; find it at /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister. For more details about pluginkit, see the pluginkit man page. When debugging a Network Extension provider, add buttons to make it easy to save and remove your provider’s configuration. For example, if you’re working on a packet tunnel provider you might add: A Save Config button that calls the saveToPreferences(completionHandler:) method to save the tunnel configuration you want to test with A Remove Config button that calls the removeFromPreferences(completionHandler:) method to remove your tunnel configuration These come in handy when you want to start again from scratch. Just click Remove Config and then Save Config and you’ve wiped the slate clean. You don’t have to leave these buttons in your final product, but it’s good to have them during bring up. [1] This tool is named after the PluginKit framework, a private framework used to load this type of app extension. It’s distinct from the ExtensionKit framework which is a new, public API for managing extensions. System Extension Hints macOS allows you to package your Network Extension provider as a system extension. For this to work the container app must be in the Applications directory [1]. Copying it across each time you rebuild your app is a chore. To avoid that, add a Build post-action script: Select your app’s scheme and choose Product > Scheme > Edit Scheme. On the left, select Build. Click the chevron to disclose all the options. Select Post-actions. In the main area, click the add (+) button and select New Run Script Action. In the “Provide build settings from” popup, select your app target. In the script field, enter this script: ditto "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "/Applications/${FULL_PRODUCT_NAME}" Now, each time you build your app, this script will copy it to the Applications directory. Build your app now, both to confirm that this works and to enable the next step. The next issue you’ll find is that choosing Product > Run runs the app from the build products directory rather than the Applications directory. To fix that: Edit your app’s scheme again. On the left, select Run. In the main area, select the Info tab. From the Executable popup, choose Other. Select the copy of your app in the Applications directory. Now, when you choose Product > Run, Xcode will run that copy rather than the one in the build products directory. Neat-o! For your system extension to run your container app must activate it. As with the Save Config and Remote Config buttons described earlier, it’s good to add easy-to-access buttons to activate and deactivate your system extension. With an app extension the system automatically terminates your extension process when you rebuild it. This is not the case with a system extension; you’ll have to deactivate and then reactivate it each time. Each activation must be approved in System Settings > Privacy & Security. To make that easier, leave System Settings running all the time. This debug cycle leaves deactivated but not removed system extensions installed on your system. These go away when you restart, so do that from time to time. Once a day is just fine. macOS includes a tool, systemextensionctl, to interrogate and manipulate system extension state. The workflow described above does not require that you use it, but it’s good to keep in mind. Its man page is largely content free so run the tool with no arguments to get help. [1] Unless you disable System Integrity Protection, but who wants to do that? You Can Attach with the Debugger Once your extension is running, attach with the debugger using one of two commands: To attach to an app extension, choose Debug > Attach to Process > YourAppExName. To attach to a system extension, choose Debug > Attach to Process by PID or Name. Make sure to select Debug Process As root. System extensions run as root so the attach will fail if you select Debug Process As Me. But Should You? Debugging networking code with a debugger is less than ideal because it’s common for in-progress network requests to time out while you’re stopped in the debugger. Debugging Network Extension providers this way is especially tricky because of the extra steps you have to take to get your provider running. So, while you can attach with the debugger, and that’s a great option in some cases, it’s often better not to do that. Rather, consider the following approach: Write the core logic of your provider so that you can unit test each subsystem outside of the provider. This may require some scaffolding but the time you take to set that up will pay off once you encounter your first gnarly problem. Add good logging to your provider to help debug problems that show up during integration testing. I recommend that you treat your logging as a feature of your product. Carefully consider where to add log points and at what level to log. Check this logging code into your source code repository and ship it — or at least the bulk of it — as part of your final product. This logging will be super helpful when it comes to debugging problems that only show up in the field. Remember that, when using the system log, log points that are present but don’t actually log anything are very cheap. In most cases it’s fine to leave these in your final product. Now go back and read Your Friend the System Log because it’s full of useful hints and tips on how to use the system log to debug the really hard problems. General Hints and Tips Install the Network Diagnostics and VPN (Network Extension) profiles [1] on your test device. These enable more logging and, most critically, the recording of private data. For more info about that last point, see… you guessed it… Your Friend the System Log. Get these profiles from our Bug Reporting > Profiles and Logs page. When you’re bringing up a Network Extension provider, do your initial testing with a tiny test app. I regularly see folks start out by running Safari and that’s less than ideal. Safari is a huge app with lots of complexity, so if things go wrong it’s hard to tell where to look. I usually create a small test app to use during bring up. The exact function of this test app varies by provider type. For example: If I’m building a packet tunnel provider, I might have a test function that makes an outgoing TCP connection to an IP address. Once I get that working I add another function that makes an outgoing TCP connection to a DNS name. Then I start testing UDP. And so on. Similarly for a content filter, but then it makes sense to add a test that runs a request using URLSession and another one to bring up a WKWebView. If I’m building a DNS proxy provider, my test app might use CFHost to run a simple name-to-address query. Also, consider doing your bring up on the Mac even if your final target is iOS. macOS has a bunch of handy tools for debugging networking issues, including: dig for DNS queries nc for TCP and UDP connections netstat to display the state of the networking stack tcpdump for recording a packet trace [2] Read their respective man pages for all the details. On the other hand, the build / run / debug cycle is simpler on iOS than it is on macOS, especially when you’re building a system extension on macOS. Even if your ultimate goal is to build a macOS-only system extension, if your provider type supports app extension packaging then you should consider whether it makes sense to adopt that packaging just for to speed up your development. If you do decide to try this, be aware that a packaging change can affect your code. See Network Extension Provider Packaging for more on that. [1] The latter is not a profile on macOS, but just a set of instructions. [2] You can use an RVI packet trace on iOS but it’s an extra setup step. Revision History 2026-04-01 Added a suggestion about provider packaging to the General Hints and Tips section. 2023-12-15 Fixed a particularly egregious typo (and spelling error in a section title, no less!). 2023-04-02 Fixed one of the steps in Sytem Extension Hints.
Replies
0
Boosts
0
Views
4.3k
Activity
1w
Random global network outage triggered by NEFilterDataProvider extension – only reboot helps, reinstall doesn't
I’m encountering a persistent issue with my Network Extension (specifically NEFilterDataProvider) and would really appreciate any insights. The extension generally works as expected, but after some time — especially after sleep/wake cycles or network changes — a global network outage occurs. During this state, no network traffic works: pings fail, browsers can’t load pages, etc. As soon as I stop the extension (by disabling it in System Preferences), the network immediately recovers. If I re-enable it, the outage returns instantly. I’ve also noticed that once this happens, the extension stops receiving callbacks like handleNewFlow(), and reinstalling the app or restarting the extension doesn’t help. The only thing that resolves the issue is rebooting the system. After reboot, the extension works fine again — until the problem reoccurs later. I asked AI about this behavior, and it suggested the possibility that the kernel might have marked the extension as untrusted, causing the system to intentionally block all network traffic as a safety mechanism. Has anyone experienced similar behavior with NEFilterDataProvider? Could there be a way to detect or prevent this state without rebooting? Is there any logging or diagnostic data I should collect when it happens again? Any guidance or pointers would be greatly appreciated. Thanks in advance!
Replies
9
Boosts
0
Views
238
Activity
1w
Crash in NetConnection::dequeue When Spawning URLSessionTasks in Loop
I'm encountering a null pointer dereference crash pointing to the internals of CFNetwork library code on iOS. I'm spawning URLSessionTasks at a decently fast rate (~1-5 per second), with the goal being to generate application layer network traffic. I can reliably encounter this crash pointing to NetConnection::dequeue right after a new task has been spawned and had the resume method called. I suspect that this is perhaps a race condition or some delegate/session object lifecycle bug. The crash appears to be more easily reproduced with a higher rate of spawning URLSessionTasks. I've included the JSON crash file, the lldb stack trace, and the source code of my URLSession(Task) usage. urlsession_stuff_stacktrace.txt urlsession_stuff_source.txt urlsession_crash_report.txt
Replies
1
Boosts
0
Views
69
Activity
1w
IPhone fails to connect with Xcode in presence of multiple WebContentFilters
I am facing an intermittent problem where iPhones are failing to pair/connect with Xcode under Xcode -> Windows -> Devices and Simulators. This happens when more than one web content filters are present, for instance, I have my web content filter (FilterSockets true, FilterGrade Firewall) and there is also Sentinel One web content filter with same configuration. Note: We are not blocking any flow from remoted / remotepairingd / core device service / MDRemoteServiceSupport etc processes. But they do get paused and resumed at times for our internal traffic verification logic. So, we are trying to understand what impact our content filter may be having on this iPhone Pairing?? If we stop either one of the filters the problem goes away. I have tracked the network traffic to the phone, and it seems to be using a ethernet interface (en5/en10) over the USB-C cable. I can see endpoints like this: localEndpoint = fe80::7:afff:fea1:edb8%en5.54442 remoteEndpoint = fe80::7:afff:fea1:ed47%en5.49813 I also see remoted process has the below ports open : sudo lsof -nP -iTCP -iUDP | grep remoted remoted 376 root 4u IPv6 0xce4a89bddba37bce 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57395->[fe80:15::7:afff:fea1:ed47]:58783 (ESTABLISHED) remoted 376 root 6u IPv6 0xf20811f6922613c7 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57396 (LISTEN) remoted 376 root 7u IPv6 0x2c393a52251fcc56 0t0 TCP [fe80:15::7:afff:fea1:edb8]:57397 (LISTEN) remoted 376 root 8u IPv6 0xcb9c311b0ec1d6a0 0t0 TCP [fd6e:8a96:a57d::2]:57398 (LISTEN) remoted 376 root 9u IPv6 0xc582859e0623fe4e 0t0 TCP [fd6e:8a96:a57d::2]:57399 (LISTEN) remoted 376 root 10u IPv6 0x2f7d9cee24a44c5b 0t0 TCP [fd6e:8a96:a57d::2]:57400->[fd6e:8a96:a57d::1]:60448 (ESTABLISHED) remoted 376 root 11u IPv6 0xbdb7003643659de 0t0 TCP [fd07:2e7e:2a83::2]:57419 (LISTEN) remoted 376 root 12u IPv6 0x569a5b649ff8f957 0t0 TCP [fd07:2e7e:2a83::2]:57420 (LISTEN) remoted 376 root 13u IPv6 0xa034657978a7da29 0t0 TCP [fd07:2e7e:2a83::2]:57421->[fd07:2e7e:2a83::1]:61729 (ESTABLISHED) But due to the dynamic nature of port and IPs used we are not able to decide on an effective early bypass NEFilterRule. We don't want to use a very broad bypass criteria like all link local IPs etc. Any help will be greatly appreciated.
Replies
1
Boosts
2
Views
70
Activity
1w
Inquiry Regarding USB Network Connectivity Between an iPad (Wi‑Fi Model) and an Embedded Linux Device
Inquiry) Inquiry Regarding USB Network Connectivity Between an iPad (Wi‑Fi Model) and an Embedded Linux Device An embedded device (OS: Linux) is connected to an iPad (Wi‑Fi model) using a USB‑C cable. The ipheth driver is installed on the embedded device, and the iPad is recognized correctly. A web server is running on the embedded device. To launch a browser on the iPad and access the web server running on the embedded device via a USB network connection. Based on our verification, the iPad is not assigned an IP address, and therefore communication with the web server on the embedded device is not possible. We would appreciate it if you could provide guidance on the following questions. We would like to assign an IP address to the iPad (Wi‑Fi Model) so that it can communicate with the embedded device over a USB network connection. Is there a way to achieve this through the standard settings on the iPad? If this cannot be achieved through settings alone, are there any existing applications that provide this functionality? If no such application currently exists, is it technically possible to develop an application that enables this capability on iPadOS? Information) The USB‑C port on the embedded device is fixed in HOST mode. The embedded device operates as the USB host, and the iPad operates as a USB device. When a cellular model iPad is connected and “Personal Hotspot” is enabled, an IP address is assigned via DHCP, and we have confirmed that the web server can be accessed from the iPad’s browser. We are investigating whether a similar solution is possible with a Wi‑Fi model iPad.
Replies
1
Boosts
0
Views
69
Activity
1w
NEURLFilter Not Blocking URLs
I've been able to run this sample project with the PIRServer. But the urls are still not blocked. https://developer.apple.com/documentation/networkextension/filtering-traffic-by-url https://github.com/apple/pir-service-example I got this on the log Received filter status change: <FilterStatus: 'running'>
Replies
1
Boosts
0
Views
103
Activity
1w
Can NWConnection.receive(minimumIncompleteLength:maximumLength:) return nil data for UDP while connection remains .ready?
I’m using Network Framework with UDP and calling: connection.receive(minimumIncompleteLength: 1, maximumLength: 1500) { data, context, isComplete, error in ... // Some Logic } Is it possible for this completion handler to be called with data==nil if I haven't received any kind of error, i.e., error==nil and the connection is still in the .ready state?
Replies
7
Boosts
0
Views
212
Activity
1w
test NEAppProxyProvider without MDM?
This discussion is for iOS/iPadOS. I've written an NEAppProxyProvider network extension. I'd like to test it. I thought that using the "NETestAppMapping" dictionary was a way to get there, but when I try to instantiate an NEAppProxyProviderManager to try to install stuff, the console tells me "must be MDM managed" and I get nowhere. So can someone tell me, can I at least test the idea without needing to first get MDM going? I'd like to know if how I'm approaching the core problem even makes sense. My custom application needs to stream video, via the SRT protocol, to some place like youtube or castr. The problem is that in the environment we are in (big convention centers), our devices are on a LAN, but the connection from the LAN out to the rest of the world just sucks. Surprisingly, cellular has better performance. So I am trying to do the perverse thing of forcing traffix that is NOT local to go out over cellular. And traffic that is completely local (i.e. talking to a purely local server/other devices on the LAN) happens over ethernet. [To simplify things, wifi is not connected.] Is an app proxy the right tool for this? Is there any other tool? Unfortunately, I cannot rewrite the code to force everything through Apple's Network framework, which is the one place I know we can say "use cellular." [E.g. URLSession() has absolutely no way of forcing cellular, and even so, the low level streaming library I use is written with raw sockets, and its not feasible for me to rewrite it.] Any other suggestions of how to accomplish this "send non-local traffic to cellular, all local traffic out over ethernet" gratefully welcomed!
Replies
9
Boosts
0
Views
135
Activity
1w
Understanding '.waiting' state in NWConnection.State for UDP
While going through the documentation for NWConnection, there seems to be state known as .waiting which means that the connection is waiting for a path change. For TCP, the state is understandable and can occur under some scenarios. But for the case of UDP, I have following queries: Why do we need .waiting state for the case of UDP? Even if we do need .waiting state for UDP, when all does this state occurs?
Replies
1
Boosts
0
Views
75
Activity
1w
WiFi WPA3 Cypher Problem
I've submitted a couple of pieces of feedback regarding broken WPA3 support on iOS 26 for the iPhone 17 Pro Max, and I've seen various access point vendors report that the GCMP256 cypher is not working. If you use WPA2, there is no issue. The problem I'm running into comes down to WPA3 being mandatory on 6 GHz. Some vendors have reported that disabling GCMP256 on Cisco Meraki hardware solves the problem. No other major vendor exposes this level of options. Does anyone know if it's possible to get more verbose diagnostic information out of the WiFi stack? I need actual information about why the negotiation fails, the technician-level stuff.
Replies
2
Boosts
0
Views
74
Activity
1w