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

Networking Resources
General: Forums subtopic: App & System Services > Networking TN3151 Choosing the right networking API Networking Overview document — Despite the fact that this is in the archive, this is still really useful. TLS for App Developers forums post Choosing a Network Debugging Tool documentation WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi? TN3135 Low-level networking on watchOS TN3179 Understanding local network privacy Adapt to changing network conditions tech talk Understanding Also-Ran Connections forums post Extra-ordinary Networking forums post Foundation networking: Forums tags: Foundation, CFNetwork URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms. Moving to Fewer, Larger Transfers forums post Testing Background Session Code forums post Network framework: Forums tag: Network Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms. Building a custom peer-to-peer protocol sample code (aka TicTacToe) Implementing netcat with Network Framework sample code (aka nwcat) Configuring a Wi-Fi accessory to join a network sample code Moving from Multipeer Connectivity to Network Framework forums post NWEndpoint History and Advice forums post Wi-Fi (general): How to modernize your captive network developer news post Wi-Fi Fundamentals forums post Filing a Wi-Fi Bug Report forums post Working with a Wi-Fi Accessory forums post — This is part of the Extra-ordinary Networking series. Wi-Fi (iOS): TN3111 iOS Wi-Fi API overview technote Wi-Fi Aware framework documentation WirelessInsights framework documentation iOS Network Signal Strength forums post Network Extension Resources Wi-Fi on macOS: Forums tag: Core WLAN Core WLAN framework documentation Secure networking: Forums tags: Security Apple Platform Security support document Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS). WWDC 2017 Session 701 Your Apps and Evolving Network Security Standards [1] — This is generally interesting, but the section starting at 17:40 is, AFAIK, the best information from Apple about how certificate revocation works on modern systems. Available trusted root certificates for Apple operating systems support article Requirements for trusted certificates in iOS 13 and macOS 10.15 support article About upcoming limits on trusted certificates support article Apple’s Certificate Transparency policy support article What’s new for enterprise in iOS 18 support article — This discusses new key usage requirements. Technote 2232 HTTPS Server Trust Evaluation Technote 2326 Creating Certificates for TLS Testing QA1948 HTTPS and Test Servers Miscellaneous: More network-related forums tags: 5G, QUIC, Bonjour On FTP forums post Using the Multicast Networking Additional Capability forums post Investigating Network Latency Problems forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] This video is no longer available from Apple, but the URL should help you locate other sources of this info.
0
0
4.2k
Mar ’26
Determine outgoing flow source IPs without allowing data leakage using NEFilterDataProvider
I'm looking for help with a network extension filtering issue. Specifically, we have a subclass of NEFilterDataProvider that is used to filter flows based upon a set of rules, including source IP and destination IP. We've run into an issue where the source IP is frequently 0.0.0.0 (or the IPv6 equivalent) on outgoing flows. This has made it so rules based upon source IP don't work. This is also an issue as we report these connections, but we're lacking critical data. We were able to work around the issue somewhat by keeping a list of flows that we allow that we periodically check to see if the source IP is available, and then report after it becomes available. We also considered doing a "peekBytes" to allow a bit of data to flow and then recheck the flow, but we don't want to allow data leakage on connections that should be blocked because of the source IP. Is there a way to force the operating system or network extension frameworks to determine the source IP for an outbound flow without allowing any bytes to flow to the network? STEPS TO REPRODUCE Create a network filtering extension for filtering flows using NEFilterDataProvider See that when handleNewFlow: is called, the outgoing flow lacks the source IP (is 0.0.0.0) in most cases There is this post that is discussing a similar question, though for a slightly different reason. I imagine the answer to this and the other post will be related, at least as far as NEFilterDataProvider:handleNewFlow not having source IP is considered. Thanks!
1
0
192
Apr ’25
Broadcasts and Multicasts, Hints and Tips
For important background information, read Extra-ordinary Networking before reading this. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Broadcasts and Multicasts, Hints and Tips I regularly see folks struggle with broadcasts and multicasts on Apple platforms. This post is my attempt to clear up some of the confusion. This post covers both IPv4 and IPv6. There is, however, a key difference. In IPv4, broadcasts and multicasts are distinct concepts. In contrast, IPv6 doesn’t support broadcast as such; rather, it treats broadcasts as a special case of multicasts. IPv6 does have an all nodes multicast address, but it’s rarely used. Before reading this post, I suggest you familiarise yourself with IP addresses in general. A good place to start is The Fount of All Knowledge™. Service Discovery A lot of broadcast and multicast questions come from folks implementing their own service discovery protocol. I generally recommend against doing that, for the reasons outlined in the Service Discovery section of Don’t Try to Get the Device’s IP Address. There are, however, some good reasons to implement a custom service discovery protocol. For example, you might be working with an accessory that only supports this custom protocol [1]. If you must implement your own service discovery protocol, read this post and also read the advice in Don’t Try to Get the Device’s IP Address. IMPORTANT Sometimes I see folks implementing their own version of mDNS. This is almost always a mistake: If you’re using third-party tooling that includes its own mDNS implementation, it’s likely that this tooling allows you to disable that implementation and instead rely on the Bonjour support that’s built-in to all Apple platforms. If you’re doing some weird low-level thing with mDNS or DNS-SD, it’s likely that you can do that with the low-level DNS-SD API. [1] And whose firmware you can’t change! I talk more about this in Working with a Wi-Fi Accessory. API Choice Broadcasts and multicasts typically use UDP [1]. TN3151 Choosing the right networking API describes two recommended UDP APIs: Network framework BSD Sockets Our general advice is to prefer Network framework over BSD Sockets, but UDP broadcasts and multicasts are an exception to that rule. Network framework has very limited UDP broadcast support. And while it’s support for UDP multicasts is less limited, it’s still not sufficient for all UDP applications. In cases where Network framework is not sufficient, BSD Sockets is your only option. [1] It is possible to broadcast and multicast at the Ethernet level, but I almost never see questions about that. UDP Broadcasts in Network Framework Historically I’ve claimed that Network framework was useful for UDP broadcasts is very limited circumstances (for example, in the footnote on this post). I’ve since learnt that this isn’t the case. Or, more accurately, this support is so limited (r. 122924701) as to be useless in practice. For the moment, if you want to work with UDP broadcasts, your only option is BSD Sockets. UDP Multicasts in Network Framework Network framework supports UDP multicast using the NWConnectionGroup class with the NWMulticastGroup group descriptor. This support has limits. The most significant limit is that it doesn’t support broadcasts; it’s for multicasts only. Note This only relevant to IPv4. Remember that IPv6 doesn’t support broadcasts as a separate concept. There are other limitations, but I don’t have a good feel for them. I’ll update this post as I encounter issues. Local Network Privacy Some Apple platforms support local network privacy. This impacts broadcasts and multicasts in two ways: Broadcasts and multicasts require local network access, something that’s typically granted by the user. Broadcasts and multicasts are limited by a managed entitlement (except on macOS). TN3179 Understanding local network privacy has lots of additional info on this topic, including the list of platforms to which it applies. Send, Receive, and Interfaces When you broadcast or multicast, there’s a fundamental asymmetry between send and receive: You can reasonable receive datagrams on all broadcast-capable interfaces. But when you send a datagram, it has to target a specific interface. The sending behaviour is the source of many weird problems. Consider the IPv4 case. If you send a directed broadcast, you can reasonably assume it’ll be routed to the correct interface based on the network prefix. But folks commonly send an all-hosts broadcast (255.255.255.255), and it’s not obvious what happens in that case. Note If you’re unfamiliar with the terms directed broadcast and all-hosts broadcast, see IP address. The exact rules for this are complex, vary by platform, and can change over time. For that reason, it’s best to write your broadcast code to be interface specific. That is: Identify the interfaces on which you want to work. Create a socket per interface. Bind that socket to that interface. Note Use the IP_BOUND_IF (IPv4) or IPV6_BOUND_IF (IPv6) socket options rather than binding to the interface address, because the interface address can change over time. Extra-ordinary Networking has links to other posts which discuss these concepts and the specific APIs in more detail. Miscellaneous Gotchas A common cause of mysterious broadcast and multicast problems is folks who hard code BSD interface names, like en0. Doing that might work for the vast majority of users but then fail in some obscure scenarios. BSD interface names are not considered API and you must not hard code them. Extra-ordinary Networking has links to posts that describe how to enumerate the interface list and identify interfaces of a specific type. Don’t assume that there’ll be only one interface of a given type. This might seem obviously true, but it’s not. For example, our platforms support peer-to-peer Wi-Fi, so each device has multiple Wi-Fi interfaces. When sending a broadcast, don’t forget to enable the SO_BROADCAST socket option. If you’re building a sandboxed app on the Mac, working with UDP requires both the com.apple.security.network.client and com.apple.security.network.server entitlements. Some folks reach for broadcasts or multicasts because they’re sending the same content to multiple devices and they believe that it’ll be faster than unicasts. That’s not true in many cases, especially on Wi-Fi. For more on this, see the Broadcasts section of Wi-Fi Fundamentals. Snippets To send a UDP broadcast: func broadcast(message: Data, to interfaceName: String) throws { let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0) defer { try! fd.close() } try fd.setSocketOption(SOL_SOCKET, SO_BROADCAST, 1 as CInt) let interfaceIndex = if_nametoindex(interfaceName) guard interfaceIndex > 0 else { throw … } try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex) try fd.send(data: message, to: ("255.255.255.255", 2222)) } Note These snippet uses the helpers from Calling BSD Sockets from Swift. To receive UDP broadcasts: func receiveBroadcasts(from interfaceName: String) throws { let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0) defer { try! fd.close() } let interfaceIndex = if_nametoindex(interfaceName) guard interfaceIndex > 0 else { fatalError() } try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex) try fd.setSocketOption(SOL_SOCKET, SO_REUSEADDR, 1 as CInt) try fd.setSocketOption(SOL_SOCKET, SO_REUSEPORT, 1 as CInt) try fd.bind("0.0.0.0", 2222) while true { let (data, (sender, port)) = try fd.receiveFrom() … } } IMPORTANT This code runs synchronously, which is less than ideal. In a real app you’d run the receive asynchronously, for example, using a Dispatch read source. For an example of how to do that, see this post. If you need similar snippets for multicast, lemme know. I’ve got them lurking on my hard disk somewhere (-: Other Resources Apple’s official documentation for BSD Sockets is in the man pages. See Reading UNIX Manual Pages. Of particular interest are: setsockopt man page ip man page ip6 man page If you’re not familiar with BSD Sockets, I strongly recommend that you consult third-party documentation for it. BSD Sockets is one of those APIs that looks simple but, in reality, is ridiculously complicated. That’s especially true if you’re trying to write code that works on BSD-based platforms, like all of Apple’s platforms, and non-BSD-based platforms, like Linux. I specifically recommend UNIX Network Programming, by Stevens et al, but there are lots of good alternatives. https://unpbook.com Revision History 2025-09-01 Fixed a broken link. 2025-01-16 First posted.
0
0
694
Sep ’25
Thread topology data: no API path for parent-child relationships
I'm building a HomeKit app that discovers Thread devices and visualizes the mesh topology. I can detect device roles (Router vs End Device via characteristic 0x0703) and identify Border Routers (via _meshcop._udp), but I cannot determine which Router is the parent of a given End Device. Any Thread device can act as a Router (a Nanoleaf bulb, an Eve plug, not just HomePods), and End Devices attach to these Routers as children. That parent-child relationship is what I'm trying to map, but there's no RLOC16, neighbor table, or parent identifier exposed through any available API. I've tested every path I can find. Here's what I've tried on a network with 44 Thread devices and 6 Border Routers: What works (partially) HAP Thread Management Service (0x0701) gives me the device role from characteristic 0x0703, the OpenThread version from 0x0706, and node capabilities from 0x0702. That's the complete set of characteristics on that service. None of them contain RLOC16, parent Router, or neighbor data. This service also only exists on HAP-native Thread devices. My 20 Matter-over-Thread devices (Aqara, Eve Door, SmartWings, Onvis S4) don't have it at all. MeshCoP Bonjour (_meshcop._udp) identifies Border Routers and the network name/Extended PAN ID. No topology data about other mesh nodes. What doesn't work ThreadNetwork framework (THClient) - retrieveAllCredentials() returns error Code 3 because the app can't access credentials stored by Apple Home. Even if it worked, THCredentials only contains network config (name, PAN ID, channel), not topology. Direct CoAP queries - Border Routers don't route traffic from WiFi to Thread management ports. Mesh-local addresses aren't reachable. No Thread NWInterface in Network.framework. Network.framework - No visibility into the Thread mesh from the WiFi side. The only remaining path I can see (but it's not practical) Matter cluster 0x0035 (Thread Network Diagnostics) appears to have exactly what I need: RLOC16, NeighborTable with isChild boolean, RouteTable. I haven't implemented this because it requires commissioning each device individually onto my app's own Matter fabric via Multi-Admin. That's 21 separate user-initiated pairing actions on my network. I can't ask end users to do that. The core issue Every Thread Router (whether it's a HomePod acting as a Border Router or a Nanoleaf bulb acting as a mesh Router) knows its own children and neighbors. The Border Routers also maintain route tables covering the mesh backbone. This data exists on the user's own devices but none of it is exposed to third-party apps. Even something minimal would help. HMAccessory already exposes matterNodeID as a cross-protocol identifier. Exposing RLOC16 the same way would be enough, since parent-child relationships are encoded in the address itself (ParentRLOC = ChildRLOC & 0xFC00). Has anyone found another approach I'm missing? Thanks in advance for any pointers.
1
0
188
Feb ’26
TLS for App Developers
Transport Layer Security (TLS) is the most important security protocol on the Internet today. Most notably, TLS puts the S into HTTPS, adding security to the otherwise insecure HTTP protocol. IMPORTANT TLS is the successor to the Secure Sockets Layer (SSL) protocol. SSL is no longer considered secure and it’s now rarely used in practice, although many folks still say SSL when they mean TLS. TLS is a complex protocol. Much of that complexity is hidden from app developers but there are places where it’s important to understand specific details of the protocol in order to meet your requirements. This post explains the fundamentals of TLS, concentrating on the issues that most often confuse app developers. Note The focus of this is TLS-PKI, where PKI stands for public key infrastructure. This is the standard TLS as deployed on the wider Internet. There’s another flavour of TLS, TLS-PSK, where PSK stands for pre-shared key. This has a variety of uses, but an Apple platforms we most commonly see it with local traffic, for example, to talk to a Wi-Fi based accessory. For more on how to use TLS, both TLS-PKI and TLS-PSK, in a local context, see TLS For Accessory Developers. Server Certificates For standard TLS to work the server must have a digital identity, that is, the combination of a certificate and the private key matching the public key embedded in that certificate. TLS Crypto Magic™ ensures that: The client gets a copy of the server’s certificate. The client knows that the server holds the private key matching the public key in that certificate. In a typical TLS handshake the server passes the client a list of certificates, where item 0 is the server’s certificate (the leaf certificate), item N is (optionally) the certificate of the certificate authority that ultimately issued that certificate (the root certificate), and items 1 through N-1 are any intermediate certificates required to build a cryptographic chain of trust from 0 to N. Note The cryptographic chain of trust is established by means of digital signatures. Certificate X in the chain is issued by certificate X+1. The owner of certificate X+1 uses their private key to digitally sign certificate X. The client verifies this signature using the public key embedded in certificate X+1. Eventually this chain terminates in a trusted anchor, that is, a certificate that the client trusts by default. Typically this anchor is a self-signed root certificate from a certificate authority. Note Item N is optional for reasons I’ll explain below. Also, the list of intermediate certificates may be empty (in the case where the root certificate directly issued the leaf certificate) but that’s uncommon for servers in the real world. Once the client gets the server’s certificate, it evaluates trust on that certificate to confirm that it’s talking to the right server. There are three levels of trust evaluation here: Basic X.509 trust evaluation checks that there’s a cryptographic chain of trust from the leaf through the intermediates to a trusted root certificate. The client has a set of trusted root certificates built in (these are from well-known certificate authorities, or CAs), and a site admin can add more via a configuration profile. This step also checks that none of the certificates have expired, and various other more technical criteria (like the Basic Constraints extension). Note This explains why the server does not have to include the root certificate in the list of certificates it passes to the client; the client has to have the root certificate installed if trust evaluation is to succeed. In addition, TLS trust evaluation (per RFC 2818) checks that the DNS name that you connected to matches the DNS name in the certificate. Specifically, the DNS name must be listed in the Subject Alternative Name extension. Note The Subject Alternative Name extension can also contain IP addresses, although that’s a much less well-trodden path. Also, historically it was common to accept DNS names in the Common Name element of the Subject but that is no longer the case on Apple platforms. App Transport Security (ATS) adds its own security checks. Basic X.509 and TLS trust evaluation are done for all TLS connections. ATS is only done on TLS connections made by URLSession and things layered on top URLSession (like WKWebView). In many situations you can override trust evaluation; for details, see Technote 2232 HTTPS Server Trust Evaluation). Such overrides can either tighten or loosen security. For example: You might tighten security by checking that the server certificate was issued by a specific CA. That way, if someone manages to convince a poorly-managed CA to issue them a certificate for your server, you can detect that and fail. You might loosen security by adding your own CA’s root certificate as a trusted anchor. IMPORTANT If you rely on loosened security you have to disable ATS. If you leave ATS enabled, it requires that the default server trust evaluation succeeds regardless of any customisations you do. Mutual TLS The previous section discusses server trust evaluation, which is required for all standard TLS connections. That process describes how the client decides whether to trust the server. Mutual TLS (mTLS) is the opposite of that, that is, it’s the process by which the server decides whether to trust the client. Note mTLS is commonly called client certificate authentication. I avoid that term because of the ongoing industry-wide confusion between certificates and digital identities. While it’s true that, in mTLS, the server authenticates the client certificate, to set this up on the client you need a digital identity, not a certificate. mTLS authentication is optional. The server must request a certificate from the client and the client may choose to supply one or not (although if the server requests a certificate and the client doesn’t supply one it’s likely that the server will then fail the connection). At the TLS protocol level this works much like it does with the server certificate. For the client to provide this certificate it must apply a digital identity, known as the client identity, to the connection. TLS Crypto Magic™ assures the server that, if it gets a certificate from the client, the client holds the private key associated with that certificate. Where things diverge is in trust evaluation. Trust evaluation of the client certificate is done on the server, and the server uses its own rules to decided whether to trust a specific client certificate. For example: Some servers do basic X.509 trust evaluation and then check that the chain of trust leads to one specific root certificate; that is, a client is trusted if it holds a digital identity whose certificate was issued by a specific CA. Some servers just check the certificate against a list of known trusted client certificates. When the client sends its certificate to the server it actually sends a list of certificates, much as I’ve described above for the server’s certificates. In many cases the client only needs to send item 0, that is, its leaf certificate. That’s because: The server already has the intermediate certificates required to build a chain of trust from that leaf to its root. There’s no point sending the root, as I discussed above in the context of server trust evaluation. However, there are no hard and fast rules here; the server does its client trust evaluation using its own internal logic, and it’s possible that this logic might require the client to present intermediates, or indeed present the root certificate even though it’s typically redundant. If you have problems with this, you’ll have to ask the folks running the server to explain its requirements. Note If you need to send additional certificates to the server, pass them to the certificates parameter of the method you use to create your URLCredential (typically init(identity:certificates:persistence:)). One thing that bears repeating is that trust evaluation of the client certificate is done on the server, not the client. The client doesn’t care whether the client certificate is trusted or not. Rather, it simply passes that certificate the server and it’s up to the server to make that decision. When a server requests a certificate from the client, it may supply a list of acceptable certificate authorities [1]. Safari uses this to filter the list of client identities it presents to the user. If you are building an HTTPS server and find that Safari doesn’t show the expected client identity, make sure you have this configured correctly. If you’re building an iOS app and want to implement a filter like Safari’s, get this list using: The distinguishedNames property, if you’re using URLSession The sec_protocol_metadata_access_distinguished_names routine, if you’re using Network framework [1] See the certificate_authorities field in Section 7.4.4 of RFC 5246, and equivalent features in other TLS versions. Self-Signed Certificates Self-signed certificates are an ongoing source of problems with TLS. There’s only one unequivocally correct place to use a self-signed certificate: the trusted anchor provided by a certificate authority. One place where a self-signed certificate might make sense is in a local environment, that is, securing a connection between peers without any centralised infrastructure. However, depending on the specific circumstances there may be a better option. TLS For Accessory Developers discusses this topic in detail. Finally, it’s common for folks to use self-signed certificates for testing. I’m not a fan of that approach. Rather, I recommend the approach described in QA1948 HTTPS and Test Servers. For advice on how to set that up using just your Mac, see TN2326 Creating Certificates for TLS Testing. TLS Standards RFC 6101 The Secure Sockets Layer (SSL) Protocol Version 3.0 (historic) RFC 2246 The TLS Protocol Version 1.0 RFC 4346 The Transport Layer Security (TLS) Protocol Version 1.1 RFC 5246 The Transport Layer Security (TLS) Protocol Version 1.2 RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3 RFC 4347 Datagram Transport Layer Security RFC 6347 Datagram Transport Layer Security Version 1.2 RFC 9147 The Datagram Transport Layer Security (DTLS) Protocol Version 1.3 Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision History: 2025-11-21 Clearly defined the terms TLS-PKI and TLS-PSK. 2024-03-19 Adopted the term mutual TLS in preference to client certificate authentication throughout, because the latter feeds into the ongoing certificate versus digital identity confusion. Defined the term client identity. Added the Self-Signed Certificates section. Made other minor editorial changes. 2023-02-28 Added an explanation mTLS acceptable certificate authorities. 2022-12-02 Added links to the DTLS RFCs. 2022-08-24 Added links to the TLS RFCs. Made other minor editorial changes. 2022-06-03 Added a link to TLS For Accessory Developers. 2021-02-26 Fixed the formatting. Clarified that ATS only applies to URLSession. Minor editorial changes. 2020-04-17 Updated the discussion of Subject Alternative Name to account for changes in the 2019 OS releases. Minor editorial updates. 2018-10-29 Minor editorial updates. 2016-11-11 First posted.
0
0
8.4k
Nov ’25
XPC Connection with Network Extension fails after upgrade
Hi Team, I have a Network Extension application and UI frontend for it. The UI frontend talks to the Network Extension using XPC, as provided by NEMachServiceName. On M2 machine, The application and XPC connection works fine on clean installation. But, when the application is upgraded, the XPC connection keeps failing. Upgrade steps: PreInstall script kills the running processes, both UI and Network Extension Let installation continue PostInstall script to launch the application after installation complete. Following code is successful to the point of resume from UI application NSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCUIObject)]; newConnection.exportedInterface = exportedInterface; newConnection.exportedObject = delegate; NSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCExtObject)]; newConnection.remoteObjectInterface = remoteObjectInterface; self.currentConnection = newConnection; [newConnection resume]; But it fails to get the object id<IPCExtObject> providerProxy = [self.currentConnection remoteObjectProxyWithErrorHandler:^(NSError *registerError) { }]; Please note, this only fails for M2. For M1, this exact code is running fine. Additionally, if I uninstall the application by dropping it in Trash and then installing the newer version, then too, the application works fine.
4
0
990
Dec ’25
Crash when deallocating NEAppProxyFlow
Hello, I'm working on a Transparent Proxy and when the proxy is being stopped, I'm stopping all the flows by calling flow.closeWriteWithError(POSIXError(.ECANCELED)) flow.closeReadWithError(POSIXError(.ECANCELED)) Then all the flows are deallocated. When deallocating the flow the crash occurs: OS Version: macOS 14.1.2 (23B92) Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000018c2ef704 Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [553] Thread 32 Crashed:: Dispatch queue: <my dispatch queue> 0 CoreFoundation 0x18c2ef704 CF_IS_OBJC + 76 1 CoreFoundation 0x18c23f61c CFErrorGetDomain + 32 2 libnetworkextension.dylib 0x19fe56a00 flow_error_to_errno + 28 3 libnetworkextension.dylib 0x19fe56920 flow_handle_pending_write_requests + 216 4 libnetworkextension.dylib 0x19fe5667c __NEFlowDeallocate + 380 5 CoreFoundation 0x18c2efe28 _CFRelease + 292 6 NetworkExtension 0x19d208390 -[NEAppProxyFlow dealloc] + 36 Is there any way to debug what is happening and if it's related to closing the flow with POSIXError? Thank you
3
0
244
Jul ’25
Matter Generic Switch not resuming subscription on reboot
I'm developing a Matter-over-thread generic switch with 2 generic switch endpoints. This is configured as an Intermittently Connected Device with Long Idle Time. I have an Apple TV serving as the thread border router. I'm able to commission the device successfully in the Home app and assign actions to each of the buttons however when the device is rebooted the subscription doesn't appear to resume successfully and the buttons no longer work. I've tested this on various SOC's with their respective SDKs including ESP32-C6, nrf52840 and EFR32MG24 and the behaviour was consistent across all of them. It was working originally when I first started out on the ESP32-C6, then the issue popped up first when I was testing the nrf52840. In that SDK I set persistent subscriptions explicitly and it seemed to resolve the issue until it popped up again when I found that unplugging and restarting the Apple TV completely which appeared to fix the issue with subscriptions not resuming. Recently I've added a Home Pod Mini Gen 2 to the matter fabric so there are now two TBR on the network and restarting both the Apple TV and the HomePod doesn't appear to resolve the issue anymore and the subscriptions are not resuming across all three SOC's on device reboot I'm wondering if there might be something preventing the subscriptions from resuming?
2
0
211
May ’25
Video AirPlay from iOS to tvOS doesn't work with VPN on when enforceRoutes is enabled
Hey! We discovered an unexpected side-effect of enabling enforceRoutes in our iOS VPN application - video airplay from iOS to tvOS stopped working (Unable to Connect popup appears instead). Our flags combination is: includeAllNetworks = false enforceRoutes = true excludeLocalNetworks = true Interestingly, music content can be AirPlayed with the same conditions. Also, video AirPlay from iOS device to the macOS works flawlessly. Do you know if this is a known issue? Do you have any advice if we can fix this problem on our side, while keeping enforcRoutes flag enabled?
1
0
97
Mar ’26
App occassionally crashing while connecting to public wifi
We are using the [NEHotspotHelper supportedNetworkInterfaces] to get the Wi-Fi interface in our app, but it occasionally crashes on some devices with the following stack trace: 0 CaptiveNetwork 0x0000000221d87a4c ServerConnectionGetHandlerQueue + 0 (ServerConnection.c:509) 1 CaptiveNetwork 0x0000000221d8577c CNPluginCopySupportedInterfaces + 180 (CNPlugin.c:457) 2 NetworkExtension 0x00000001b0446618 +[NEHotspotHelper supportedNetworkInterfaces] + 32 (NEHotspotHelper.m:563) It seems like the crash is happening on apple's api of supportedNetworkInterfaces. We would like to understand the cause of the crash.
2
0
95
May ’25
WiFi aware demo paring issue
I am developing a program on my chip and attempting to establish a connection with the WiFi Aware demo app launched by iOS 26. Currently, I am encountering an issue during the pairing phase. If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I see the PIN code displayed by iOS. Question 1: How should I use this PIN code? Question 2: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process? If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I should display the PIN code. Question 3: How do I generate this PIN code? Question 4: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process?
1
0
613
Nov ’25
NETransparentProxyProvider frequent tunnel churn during Dark Wake cycles on macOS.
Description Our NETransparentProxyProvider system extension maintains a persistent TLS/DTLS control channel to a security gateway. To maintain this stateful connection the extension sends application-level "Keep Alive" packets every few seconds (example : 20 seconds). The Issue: When the macOS device enters a sleep state, the Network Extension process is suspended, causing our application-level heartbeat to cease. Consequently, our backend gateway—detecting no activity—terminates the session via Dead Peer Detection (DPD). The problem is exacerbated by macOS Dark Wake cycles. We observe the extension's wake() callback being triggered periodically (approx. every 15 minutes) while the device remains in a sleep state (lid closed). During these brief windows: The extension attempts to use the existing socket, finds it terminated by the backend, and initiates a full re-handshake. Shortly after the connection is re-established, the OS triggers the sleep() callback and suspends the process again. This creates a "connection churn" cycle that generates excessive telemetry noise and misleading "Session Disconnected" alerts for our enterprise customers. Steps to Reproduce Activate Proxy: Start the NETransparentProxyProvider and establish a TLS session to a gateway. Apply Settings: Configure NETransparentProxyNetworkSettings to intercept outbound TCP/UDP traffic. Initialize Heartbeat: Start a 20-second timer (DispatchSourceTimer) to log and send keep-alive packets. Induce Sleep: Put the Mac to sleep (Apple Menu > Sleep). Observe Logs: Monitor the system via sysdiagnose or the macOS Console. Observation: Logs stop entirely during sleep, indicating process suspension. Observation: wake() and sleep() callbacks are triggered repeatedly during Dark Wake intervals, causing a cycle of re-connections. Expected Behavior We seek to minimize connection turnover during maintenance wakes and maintain session stability while the device is technically in a sleep state. Questions for Apple Is it possible to suppress the sleep and wake callback methods of NETransparentProxyProvider when the device is performing a maintenance/Dark Wake, only triggering them for a full user-initiated wake? Is it possible to prevent the NETransparentProxyProvider process from being suspended during sleep, or at least grant it a high-priority background execution slot to maintain the heartbeat? If suspension is mandatory, is there a recommended way to utilize TCP_KEEPALIVE socket options that the kernel can handle on behalf of the suspended extension? How can the extension programmatically identify if a wake() call is a "Dark Wake" versus a "Full User Wake" to avoid unnecessary re-connection logic?
3
0
171
Feb ’26
Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering traffic by URL sample code Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
3.2k
Mar ’26
A Peek Behind the NECP Curtain
From time to time the subject of NECP grows up, both here on DevForums and in DTS cases. I’ve posted about this before but I wanted to collect those tidbits into single coherent post. If you have questions or comments, start a new thread in the App & System Services > Networking subtopic and tag it with Network Extension. That way I’ll be sure to see it go by. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" A Peek Behind the NECP Curtain NECP stands for Network Extension Control Protocol. It’s a subsystem within the Apple networking stack that controls which programs have access to which network interfaces. It’s vitally important to the Network Extension subsystem, hence the name, but it’s used in many different places. Indeed, a very familiar example of its use is the Settings > Mobile Data [1] user interface on iOS. NECP has no explicit API, although there are APIs that are offer some insight into its state. Continuing the Settings > Mobile Data example above, there is a little-known API, CTCellularData in the Core Telephony framework, that returns whether your app has access to WWAN. Despite having no API, NECP is still relevant to developers. The Settings > Mobile Data example is one place where it affects app developers but it’s most important for Network Extension (NE) developers. A key use case for NECP is to prevent VPN loops. When starting an NE provider, the system configures the NECP policy for the NE provider’s process to prevent it from using a VPN interface. This means that you can safely open a network connection inside your VPN provider without having to worry about its traffic being accidentally routed back to you. This is why, for example, an NE packet tunnel provider can use any networking API it wants, including BSD Sockets, to run its connection without fear of creating a VPN loop [1]. One place that NECP shows up regularly is the system log. Next time you see a system log entry like this: type: debug time: 15:02:54.817903+0000 process: Mail subsystem: com.apple.network category: connection message: nw_protocol_socket_set_necp_attributes [C723.1.1:1] setsockopt 39 SO_NECP_ATTRIBUTES … you’ll at least know what the necp means (-: Finally, a lot of NECP infrastructure is in the Darwin open source. As with all things in Darwin, it’s fine to poke around and see how your favourite feature works, but do not incorporate any information you find into your product. Stuff you uncover by looking in Darwin is not considered API. [1] Settings > Cellular Data if you speak American (-: [2] Network Extension providers can call the createTCPConnection(to:enableTLS:tlsParameters:delegate:) method to create an NWTCPConnection [3] that doesn’t run through the tunnel. You can use that if it’s convenient but you don’t need to use it. [3] NWTCPConnection is now deprecated, but there are non-deprecated equivalents. For the full story, see NWEndpoint History and Advice. Revision History 2025-12-12 Replaced “macOS networking stack” with “Apple networking stack” to avoid giving the impression that this is all about macOS. Added a link to NWEndpoint History and Advice. Made other minor editorial changes. 2023-02-27 First posted.
0
0
2.6k
Dec ’25
Unable to update app with PacketTunnelProvider running
Hi there, I am working on an app that configures a PacketTunnelProvider to establish a VPN connection. Unfortunately, while a VPN connection is established, I am unable to update the app via testflight. Downloading other app updates works fine. I noticed that after I receive the alert that updating failed, the vpn badge appears at the top of my screen (the same ux that occurs when the connection is first established). So it's almost like it tried to close the tunnel, and seeing that the app update failed it restablishes the tunnel. I am unsure of why I would not be able to update my app. Maybe stopTunnel is not being called with NEProviderStopReason.appUpdate?
1
0
69
Jun ’25
Need Help with TUN Writeback
Hi everyone, I'm currently experimenting with building a simple DNS filter using Apple's Packet Tunnel framework. Here's the flow I'm trying to implement: Create a TUN interface Set up a UDP socket Read packets via packetFlow.readPackets Parse the raw IP packet Forward the UDP payload through the socket Receive the response from the server Reconstruct the IP packet with the response Write it back to the TUN interface using packetFlow.writePackets Here’s an example of an intercepted IP packet (DNS request): 45 00 00 3c 15 c4 00 00 40 11 93 d1 c0 a8 00 64 08 08 08 08 ed 6e 00 35 00 28 e5 c9 7f da 01 00 00 01 00 00 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 And here’s the IP packet I tried writing back into the TUN interface (DNS response): 45 00 00 89 5e 37 40 00 40 11 0b 11 08 08 08 08 c0 a8 00 64 00 35 ed 6e 00 75 91 e8 7f da 81 80 00 01 00 04 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 05 00 01 00 00 0c fb 00 11 04 74 69 6d 65 01 67 07 61 61 70 6c 69 6d 67 c0 17 c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 fd c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 7d c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 54 fb Unfortunately, it seems the packet is not being written back correctly to the TUN interface. I'm not seeing any expected DNS response behavior on the device. Also, I noticed that after creating the TUN, the interface address shows up as 0.0.0.0:0 in Xcode. The system log includes this message when connecting the VPN: NWPath does not have valid interface: satisfied (Path is satisfied), interface: utun20[endc_sub6], ipv4, dns, expensive, uses cellular Does anyone know how to properly initialize the TUN so that the system recognizes it with a valid IP configuration? Or why my written-back packet might be getting ignored? Any help would be appreciated!
1
0
93
Jul ’25
Sporadic "no route to host" over ssh
When connecting to my M1 mac mini over ssh, certain programs are often unable to reach network destinations in the corporate LAN, although they can usually reach external addresses like www.apple.com. For example, a java program attempting to download from teamcity.dev.corp.com:8111 often fails like: java.net.NoRouteToHostException: No route to host Running the exact same command from the Apple Terminal program works like normal, simply connecting over ethernet on en0 to a TeamCity server inside the same building. Basic diagnostics from the ssh session do not show anything unusual: > traceroute teamcity.dev.corp.com traceroute to teamcity.dev.corp.com (10.21.4.1), 64 hops max, 40 byte packets 1 teamcity.dev.corp.com (10.21.4.1) 1.702 ms 0.409 ms 0.336 ms > route -n get teamcity.dev.corp.com route to: 10.21.4.1 destination: 10.21.4.1 interface: en0 flags: <UP,HOST,DONE,LLINFO,WASCLONED,IFSCOPE,IFREF> recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire 0 0 0 0 0 0 1500 1194 > uname -a Darwin mac 25.1.0 Darwin Kernel Version 25.1.0: Mon Oct 20 19:32:47 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8103 arm64 Similar problems occur in docker commands to a remote daemon ("no route to host" or "connection refused"): docker -H tcp://<ip>:<port> ... Most other programs are never affected by this problem. Are there other diagnostic steps that might reveal the cause?
3
0
141
Jan ’26
NEHotspotHelper API
For our outdoor power supply company that builds public WiFi networks at camping sites, we want to implement the following features in our app: Scan surrounding WiFi networks When detecting specific public WiFi SSIDs, provide users with corresponding passwords Automatically connect to those WiFi networks Regarding the NEHotspotHelper API permission application, when I clicked on https://developer.apple.com/contact/request/network-extension, it redirected me to https://developer.apple.com/unauthorized/. I'm not sure where to properly apply for this permission now.
1
0
37
May ’25
URL Filter Prefetch Interval guarantee
Hello, I have implemented a URL Filter using the sample provided here: Filtering Traffic by URL. I am also using an App Group to dynamically manage the Bloom filter and block list data. However, when I update my block list URLs and create a new Bloom filter plist in the App Group, the extension does not seem to use the updated Bloom filter even after the prefetch interval expires. Also for testing purpose can I keep this interval to 10 mins or below ?
3
0
283
3w
Network Relay errors out with "Privacy proxy failed with error 53"
I'm using NERelayManager to set Relay configuration which all works perfectly fine. I then do a curl with the included domain and while I see QUIC connection succeeds with relay server and H3 request goes to the server, the connection gets abruptly closed by the client with "Software caused connection abort". Console has this information: default 09:43:04.459517-0700 curl nw_flow_connected [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] Transport protocol connected (quic) default 09:43:04.459901-0700 curl [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:finish_transport @0.131s default 09:43:04.460745-0700 curl nw_flow_connected [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] Joined protocol connected (http3) default 09:43:04.461049-0700 curl [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:finish_transport @0.133s default 09:43:04.465115-0700 curl [C2 E47A3A0C-7275-4F6B-AEDF-59077ABAE34B 192.168.4.197:4433 quic, multipath service: 1, tls, definite, attribution: developer] cancel default 09:43:04.465238-0700 curl [C2 E47A3A0C-7275-4F6B-AEDF-59077ABAE34B 192.168.4.197:4433 quic, multipath service: 1, tls, definite, attribution: developer] cancelled [C2 FCB1CFD1-4BF9-4E37-810E-81265D141087 192.168.4.139:53898<->192.168.4.197:4433] Connected Path: satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi Duration: 0.121s, QUIC @0.000s took 0.000s, TLS 1.3 took 0.111s bytes in/out: 2880/4322, packets in/out: 4/8, rtt: 0.074s, retransmitted bytes: 0, out-of-order bytes: 0 ecn packets sent/acked/marked/lost: 3/1/0/0 default 09:43:04.465975-0700 curl nw_flow_disconnected [C2 192.168.4.197:4433 cancelled multipath-socket-flow ((null))] Output protocol disconnected default 09:43:04.469189-0700 curl nw_endpoint_proxy_receive_report [C1.1 IPv4#124bdc4d:80 in_progress proxy (satisfied (Path is satisfied), interface: en0[802.11], ipv4, ipv6, dns, proxy, uses wifi)] Privacy proxy failed with error 53 ([C1.1.1] masque Proxy: http://192.168.4.197:4433) default 09:43:04.469289-0700 curl [C1.1.1 192.168.4.197:4433 failed socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:failed_connect @0.141s, error Software caused connection abort Relay server otherwise works fine with our QUIC MASQUE clients but not with built-in macOS MASQUE client. Anything I'm missing?
0
0
272
May ’25
Networking Resources
General: Forums subtopic: App & System Services > Networking TN3151 Choosing the right networking API Networking Overview document — Despite the fact that this is in the archive, this is still really useful. TLS for App Developers forums post Choosing a Network Debugging Tool documentation WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi? TN3135 Low-level networking on watchOS TN3179 Understanding local network privacy Adapt to changing network conditions tech talk Understanding Also-Ran Connections forums post Extra-ordinary Networking forums post Foundation networking: Forums tags: Foundation, CFNetwork URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms. Moving to Fewer, Larger Transfers forums post Testing Background Session Code forums post Network framework: Forums tag: Network Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms. Building a custom peer-to-peer protocol sample code (aka TicTacToe) Implementing netcat with Network Framework sample code (aka nwcat) Configuring a Wi-Fi accessory to join a network sample code Moving from Multipeer Connectivity to Network Framework forums post NWEndpoint History and Advice forums post Wi-Fi (general): How to modernize your captive network developer news post Wi-Fi Fundamentals forums post Filing a Wi-Fi Bug Report forums post Working with a Wi-Fi Accessory forums post — This is part of the Extra-ordinary Networking series. Wi-Fi (iOS): TN3111 iOS Wi-Fi API overview technote Wi-Fi Aware framework documentation WirelessInsights framework documentation iOS Network Signal Strength forums post Network Extension Resources Wi-Fi on macOS: Forums tag: Core WLAN Core WLAN framework documentation Secure networking: Forums tags: Security Apple Platform Security support document Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS). WWDC 2017 Session 701 Your Apps and Evolving Network Security Standards [1] — This is generally interesting, but the section starting at 17:40 is, AFAIK, the best information from Apple about how certificate revocation works on modern systems. Available trusted root certificates for Apple operating systems support article Requirements for trusted certificates in iOS 13 and macOS 10.15 support article About upcoming limits on trusted certificates support article Apple’s Certificate Transparency policy support article What’s new for enterprise in iOS 18 support article — This discusses new key usage requirements. Technote 2232 HTTPS Server Trust Evaluation Technote 2326 Creating Certificates for TLS Testing QA1948 HTTPS and Test Servers Miscellaneous: More network-related forums tags: 5G, QUIC, Bonjour On FTP forums post Using the Multicast Networking Additional Capability forums post Investigating Network Latency Problems forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] This video is no longer available from Apple, but the URL should help you locate other sources of this info.
Replies
0
Boosts
0
Views
4.2k
Activity
Mar ’26
Determine outgoing flow source IPs without allowing data leakage using NEFilterDataProvider
I'm looking for help with a network extension filtering issue. Specifically, we have a subclass of NEFilterDataProvider that is used to filter flows based upon a set of rules, including source IP and destination IP. We've run into an issue where the source IP is frequently 0.0.0.0 (or the IPv6 equivalent) on outgoing flows. This has made it so rules based upon source IP don't work. This is also an issue as we report these connections, but we're lacking critical data. We were able to work around the issue somewhat by keeping a list of flows that we allow that we periodically check to see if the source IP is available, and then report after it becomes available. We also considered doing a "peekBytes" to allow a bit of data to flow and then recheck the flow, but we don't want to allow data leakage on connections that should be blocked because of the source IP. Is there a way to force the operating system or network extension frameworks to determine the source IP for an outbound flow without allowing any bytes to flow to the network? STEPS TO REPRODUCE Create a network filtering extension for filtering flows using NEFilterDataProvider See that when handleNewFlow: is called, the outgoing flow lacks the source IP (is 0.0.0.0) in most cases There is this post that is discussing a similar question, though for a slightly different reason. I imagine the answer to this and the other post will be related, at least as far as NEFilterDataProvider:handleNewFlow not having source IP is considered. Thanks!
Replies
1
Boosts
0
Views
192
Activity
Apr ’25
Broadcasts and Multicasts, Hints and Tips
For important background information, read Extra-ordinary Networking before reading this. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Broadcasts and Multicasts, Hints and Tips I regularly see folks struggle with broadcasts and multicasts on Apple platforms. This post is my attempt to clear up some of the confusion. This post covers both IPv4 and IPv6. There is, however, a key difference. In IPv4, broadcasts and multicasts are distinct concepts. In contrast, IPv6 doesn’t support broadcast as such; rather, it treats broadcasts as a special case of multicasts. IPv6 does have an all nodes multicast address, but it’s rarely used. Before reading this post, I suggest you familiarise yourself with IP addresses in general. A good place to start is The Fount of All Knowledge™. Service Discovery A lot of broadcast and multicast questions come from folks implementing their own service discovery protocol. I generally recommend against doing that, for the reasons outlined in the Service Discovery section of Don’t Try to Get the Device’s IP Address. There are, however, some good reasons to implement a custom service discovery protocol. For example, you might be working with an accessory that only supports this custom protocol [1]. If you must implement your own service discovery protocol, read this post and also read the advice in Don’t Try to Get the Device’s IP Address. IMPORTANT Sometimes I see folks implementing their own version of mDNS. This is almost always a mistake: If you’re using third-party tooling that includes its own mDNS implementation, it’s likely that this tooling allows you to disable that implementation and instead rely on the Bonjour support that’s built-in to all Apple platforms. If you’re doing some weird low-level thing with mDNS or DNS-SD, it’s likely that you can do that with the low-level DNS-SD API. [1] And whose firmware you can’t change! I talk more about this in Working with a Wi-Fi Accessory. API Choice Broadcasts and multicasts typically use UDP [1]. TN3151 Choosing the right networking API describes two recommended UDP APIs: Network framework BSD Sockets Our general advice is to prefer Network framework over BSD Sockets, but UDP broadcasts and multicasts are an exception to that rule. Network framework has very limited UDP broadcast support. And while it’s support for UDP multicasts is less limited, it’s still not sufficient for all UDP applications. In cases where Network framework is not sufficient, BSD Sockets is your only option. [1] It is possible to broadcast and multicast at the Ethernet level, but I almost never see questions about that. UDP Broadcasts in Network Framework Historically I’ve claimed that Network framework was useful for UDP broadcasts is very limited circumstances (for example, in the footnote on this post). I’ve since learnt that this isn’t the case. Or, more accurately, this support is so limited (r. 122924701) as to be useless in practice. For the moment, if you want to work with UDP broadcasts, your only option is BSD Sockets. UDP Multicasts in Network Framework Network framework supports UDP multicast using the NWConnectionGroup class with the NWMulticastGroup group descriptor. This support has limits. The most significant limit is that it doesn’t support broadcasts; it’s for multicasts only. Note This only relevant to IPv4. Remember that IPv6 doesn’t support broadcasts as a separate concept. There are other limitations, but I don’t have a good feel for them. I’ll update this post as I encounter issues. Local Network Privacy Some Apple platforms support local network privacy. This impacts broadcasts and multicasts in two ways: Broadcasts and multicasts require local network access, something that’s typically granted by the user. Broadcasts and multicasts are limited by a managed entitlement (except on macOS). TN3179 Understanding local network privacy has lots of additional info on this topic, including the list of platforms to which it applies. Send, Receive, and Interfaces When you broadcast or multicast, there’s a fundamental asymmetry between send and receive: You can reasonable receive datagrams on all broadcast-capable interfaces. But when you send a datagram, it has to target a specific interface. The sending behaviour is the source of many weird problems. Consider the IPv4 case. If you send a directed broadcast, you can reasonably assume it’ll be routed to the correct interface based on the network prefix. But folks commonly send an all-hosts broadcast (255.255.255.255), and it’s not obvious what happens in that case. Note If you’re unfamiliar with the terms directed broadcast and all-hosts broadcast, see IP address. The exact rules for this are complex, vary by platform, and can change over time. For that reason, it’s best to write your broadcast code to be interface specific. That is: Identify the interfaces on which you want to work. Create a socket per interface. Bind that socket to that interface. Note Use the IP_BOUND_IF (IPv4) or IPV6_BOUND_IF (IPv6) socket options rather than binding to the interface address, because the interface address can change over time. Extra-ordinary Networking has links to other posts which discuss these concepts and the specific APIs in more detail. Miscellaneous Gotchas A common cause of mysterious broadcast and multicast problems is folks who hard code BSD interface names, like en0. Doing that might work for the vast majority of users but then fail in some obscure scenarios. BSD interface names are not considered API and you must not hard code them. Extra-ordinary Networking has links to posts that describe how to enumerate the interface list and identify interfaces of a specific type. Don’t assume that there’ll be only one interface of a given type. This might seem obviously true, but it’s not. For example, our platforms support peer-to-peer Wi-Fi, so each device has multiple Wi-Fi interfaces. When sending a broadcast, don’t forget to enable the SO_BROADCAST socket option. If you’re building a sandboxed app on the Mac, working with UDP requires both the com.apple.security.network.client and com.apple.security.network.server entitlements. Some folks reach for broadcasts or multicasts because they’re sending the same content to multiple devices and they believe that it’ll be faster than unicasts. That’s not true in many cases, especially on Wi-Fi. For more on this, see the Broadcasts section of Wi-Fi Fundamentals. Snippets To send a UDP broadcast: func broadcast(message: Data, to interfaceName: String) throws { let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0) defer { try! fd.close() } try fd.setSocketOption(SOL_SOCKET, SO_BROADCAST, 1 as CInt) let interfaceIndex = if_nametoindex(interfaceName) guard interfaceIndex > 0 else { throw … } try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex) try fd.send(data: message, to: ("255.255.255.255", 2222)) } Note These snippet uses the helpers from Calling BSD Sockets from Swift. To receive UDP broadcasts: func receiveBroadcasts(from interfaceName: String) throws { let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0) defer { try! fd.close() } let interfaceIndex = if_nametoindex(interfaceName) guard interfaceIndex > 0 else { fatalError() } try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex) try fd.setSocketOption(SOL_SOCKET, SO_REUSEADDR, 1 as CInt) try fd.setSocketOption(SOL_SOCKET, SO_REUSEPORT, 1 as CInt) try fd.bind("0.0.0.0", 2222) while true { let (data, (sender, port)) = try fd.receiveFrom() … } } IMPORTANT This code runs synchronously, which is less than ideal. In a real app you’d run the receive asynchronously, for example, using a Dispatch read source. For an example of how to do that, see this post. If you need similar snippets for multicast, lemme know. I’ve got them lurking on my hard disk somewhere (-: Other Resources Apple’s official documentation for BSD Sockets is in the man pages. See Reading UNIX Manual Pages. Of particular interest are: setsockopt man page ip man page ip6 man page If you’re not familiar with BSD Sockets, I strongly recommend that you consult third-party documentation for it. BSD Sockets is one of those APIs that looks simple but, in reality, is ridiculously complicated. That’s especially true if you’re trying to write code that works on BSD-based platforms, like all of Apple’s platforms, and non-BSD-based platforms, like Linux. I specifically recommend UNIX Network Programming, by Stevens et al, but there are lots of good alternatives. https://unpbook.com Revision History 2025-09-01 Fixed a broken link. 2025-01-16 First posted.
Replies
0
Boosts
0
Views
694
Activity
Sep ’25
Thread topology data: no API path for parent-child relationships
I'm building a HomeKit app that discovers Thread devices and visualizes the mesh topology. I can detect device roles (Router vs End Device via characteristic 0x0703) and identify Border Routers (via _meshcop._udp), but I cannot determine which Router is the parent of a given End Device. Any Thread device can act as a Router (a Nanoleaf bulb, an Eve plug, not just HomePods), and End Devices attach to these Routers as children. That parent-child relationship is what I'm trying to map, but there's no RLOC16, neighbor table, or parent identifier exposed through any available API. I've tested every path I can find. Here's what I've tried on a network with 44 Thread devices and 6 Border Routers: What works (partially) HAP Thread Management Service (0x0701) gives me the device role from characteristic 0x0703, the OpenThread version from 0x0706, and node capabilities from 0x0702. That's the complete set of characteristics on that service. None of them contain RLOC16, parent Router, or neighbor data. This service also only exists on HAP-native Thread devices. My 20 Matter-over-Thread devices (Aqara, Eve Door, SmartWings, Onvis S4) don't have it at all. MeshCoP Bonjour (_meshcop._udp) identifies Border Routers and the network name/Extended PAN ID. No topology data about other mesh nodes. What doesn't work ThreadNetwork framework (THClient) - retrieveAllCredentials() returns error Code 3 because the app can't access credentials stored by Apple Home. Even if it worked, THCredentials only contains network config (name, PAN ID, channel), not topology. Direct CoAP queries - Border Routers don't route traffic from WiFi to Thread management ports. Mesh-local addresses aren't reachable. No Thread NWInterface in Network.framework. Network.framework - No visibility into the Thread mesh from the WiFi side. The only remaining path I can see (but it's not practical) Matter cluster 0x0035 (Thread Network Diagnostics) appears to have exactly what I need: RLOC16, NeighborTable with isChild boolean, RouteTable. I haven't implemented this because it requires commissioning each device individually onto my app's own Matter fabric via Multi-Admin. That's 21 separate user-initiated pairing actions on my network. I can't ask end users to do that. The core issue Every Thread Router (whether it's a HomePod acting as a Border Router or a Nanoleaf bulb acting as a mesh Router) knows its own children and neighbors. The Border Routers also maintain route tables covering the mesh backbone. This data exists on the user's own devices but none of it is exposed to third-party apps. Even something minimal would help. HMAccessory already exposes matterNodeID as a cross-protocol identifier. Exposing RLOC16 the same way would be enough, since parent-child relationships are encoded in the address itself (ParentRLOC = ChildRLOC & 0xFC00). Has anyone found another approach I'm missing? Thanks in advance for any pointers.
Replies
1
Boosts
0
Views
188
Activity
Feb ’26
TLS for App Developers
Transport Layer Security (TLS) is the most important security protocol on the Internet today. Most notably, TLS puts the S into HTTPS, adding security to the otherwise insecure HTTP protocol. IMPORTANT TLS is the successor to the Secure Sockets Layer (SSL) protocol. SSL is no longer considered secure and it’s now rarely used in practice, although many folks still say SSL when they mean TLS. TLS is a complex protocol. Much of that complexity is hidden from app developers but there are places where it’s important to understand specific details of the protocol in order to meet your requirements. This post explains the fundamentals of TLS, concentrating on the issues that most often confuse app developers. Note The focus of this is TLS-PKI, where PKI stands for public key infrastructure. This is the standard TLS as deployed on the wider Internet. There’s another flavour of TLS, TLS-PSK, where PSK stands for pre-shared key. This has a variety of uses, but an Apple platforms we most commonly see it with local traffic, for example, to talk to a Wi-Fi based accessory. For more on how to use TLS, both TLS-PKI and TLS-PSK, in a local context, see TLS For Accessory Developers. Server Certificates For standard TLS to work the server must have a digital identity, that is, the combination of a certificate and the private key matching the public key embedded in that certificate. TLS Crypto Magic™ ensures that: The client gets a copy of the server’s certificate. The client knows that the server holds the private key matching the public key in that certificate. In a typical TLS handshake the server passes the client a list of certificates, where item 0 is the server’s certificate (the leaf certificate), item N is (optionally) the certificate of the certificate authority that ultimately issued that certificate (the root certificate), and items 1 through N-1 are any intermediate certificates required to build a cryptographic chain of trust from 0 to N. Note The cryptographic chain of trust is established by means of digital signatures. Certificate X in the chain is issued by certificate X+1. The owner of certificate X+1 uses their private key to digitally sign certificate X. The client verifies this signature using the public key embedded in certificate X+1. Eventually this chain terminates in a trusted anchor, that is, a certificate that the client trusts by default. Typically this anchor is a self-signed root certificate from a certificate authority. Note Item N is optional for reasons I’ll explain below. Also, the list of intermediate certificates may be empty (in the case where the root certificate directly issued the leaf certificate) but that’s uncommon for servers in the real world. Once the client gets the server’s certificate, it evaluates trust on that certificate to confirm that it’s talking to the right server. There are three levels of trust evaluation here: Basic X.509 trust evaluation checks that there’s a cryptographic chain of trust from the leaf through the intermediates to a trusted root certificate. The client has a set of trusted root certificates built in (these are from well-known certificate authorities, or CAs), and a site admin can add more via a configuration profile. This step also checks that none of the certificates have expired, and various other more technical criteria (like the Basic Constraints extension). Note This explains why the server does not have to include the root certificate in the list of certificates it passes to the client; the client has to have the root certificate installed if trust evaluation is to succeed. In addition, TLS trust evaluation (per RFC 2818) checks that the DNS name that you connected to matches the DNS name in the certificate. Specifically, the DNS name must be listed in the Subject Alternative Name extension. Note The Subject Alternative Name extension can also contain IP addresses, although that’s a much less well-trodden path. Also, historically it was common to accept DNS names in the Common Name element of the Subject but that is no longer the case on Apple platforms. App Transport Security (ATS) adds its own security checks. Basic X.509 and TLS trust evaluation are done for all TLS connections. ATS is only done on TLS connections made by URLSession and things layered on top URLSession (like WKWebView). In many situations you can override trust evaluation; for details, see Technote 2232 HTTPS Server Trust Evaluation). Such overrides can either tighten or loosen security. For example: You might tighten security by checking that the server certificate was issued by a specific CA. That way, if someone manages to convince a poorly-managed CA to issue them a certificate for your server, you can detect that and fail. You might loosen security by adding your own CA’s root certificate as a trusted anchor. IMPORTANT If you rely on loosened security you have to disable ATS. If you leave ATS enabled, it requires that the default server trust evaluation succeeds regardless of any customisations you do. Mutual TLS The previous section discusses server trust evaluation, which is required for all standard TLS connections. That process describes how the client decides whether to trust the server. Mutual TLS (mTLS) is the opposite of that, that is, it’s the process by which the server decides whether to trust the client. Note mTLS is commonly called client certificate authentication. I avoid that term because of the ongoing industry-wide confusion between certificates and digital identities. While it’s true that, in mTLS, the server authenticates the client certificate, to set this up on the client you need a digital identity, not a certificate. mTLS authentication is optional. The server must request a certificate from the client and the client may choose to supply one or not (although if the server requests a certificate and the client doesn’t supply one it’s likely that the server will then fail the connection). At the TLS protocol level this works much like it does with the server certificate. For the client to provide this certificate it must apply a digital identity, known as the client identity, to the connection. TLS Crypto Magic™ assures the server that, if it gets a certificate from the client, the client holds the private key associated with that certificate. Where things diverge is in trust evaluation. Trust evaluation of the client certificate is done on the server, and the server uses its own rules to decided whether to trust a specific client certificate. For example: Some servers do basic X.509 trust evaluation and then check that the chain of trust leads to one specific root certificate; that is, a client is trusted if it holds a digital identity whose certificate was issued by a specific CA. Some servers just check the certificate against a list of known trusted client certificates. When the client sends its certificate to the server it actually sends a list of certificates, much as I’ve described above for the server’s certificates. In many cases the client only needs to send item 0, that is, its leaf certificate. That’s because: The server already has the intermediate certificates required to build a chain of trust from that leaf to its root. There’s no point sending the root, as I discussed above in the context of server trust evaluation. However, there are no hard and fast rules here; the server does its client trust evaluation using its own internal logic, and it’s possible that this logic might require the client to present intermediates, or indeed present the root certificate even though it’s typically redundant. If you have problems with this, you’ll have to ask the folks running the server to explain its requirements. Note If you need to send additional certificates to the server, pass them to the certificates parameter of the method you use to create your URLCredential (typically init(identity:certificates:persistence:)). One thing that bears repeating is that trust evaluation of the client certificate is done on the server, not the client. The client doesn’t care whether the client certificate is trusted or not. Rather, it simply passes that certificate the server and it’s up to the server to make that decision. When a server requests a certificate from the client, it may supply a list of acceptable certificate authorities [1]. Safari uses this to filter the list of client identities it presents to the user. If you are building an HTTPS server and find that Safari doesn’t show the expected client identity, make sure you have this configured correctly. If you’re building an iOS app and want to implement a filter like Safari’s, get this list using: The distinguishedNames property, if you’re using URLSession The sec_protocol_metadata_access_distinguished_names routine, if you’re using Network framework [1] See the certificate_authorities field in Section 7.4.4 of RFC 5246, and equivalent features in other TLS versions. Self-Signed Certificates Self-signed certificates are an ongoing source of problems with TLS. There’s only one unequivocally correct place to use a self-signed certificate: the trusted anchor provided by a certificate authority. One place where a self-signed certificate might make sense is in a local environment, that is, securing a connection between peers without any centralised infrastructure. However, depending on the specific circumstances there may be a better option. TLS For Accessory Developers discusses this topic in detail. Finally, it’s common for folks to use self-signed certificates for testing. I’m not a fan of that approach. Rather, I recommend the approach described in QA1948 HTTPS and Test Servers. For advice on how to set that up using just your Mac, see TN2326 Creating Certificates for TLS Testing. TLS Standards RFC 6101 The Secure Sockets Layer (SSL) Protocol Version 3.0 (historic) RFC 2246 The TLS Protocol Version 1.0 RFC 4346 The Transport Layer Security (TLS) Protocol Version 1.1 RFC 5246 The Transport Layer Security (TLS) Protocol Version 1.2 RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3 RFC 4347 Datagram Transport Layer Security RFC 6347 Datagram Transport Layer Security Version 1.2 RFC 9147 The Datagram Transport Layer Security (DTLS) Protocol Version 1.3 Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision History: 2025-11-21 Clearly defined the terms TLS-PKI and TLS-PSK. 2024-03-19 Adopted the term mutual TLS in preference to client certificate authentication throughout, because the latter feeds into the ongoing certificate versus digital identity confusion. Defined the term client identity. Added the Self-Signed Certificates section. Made other minor editorial changes. 2023-02-28 Added an explanation mTLS acceptable certificate authorities. 2022-12-02 Added links to the DTLS RFCs. 2022-08-24 Added links to the TLS RFCs. Made other minor editorial changes. 2022-06-03 Added a link to TLS For Accessory Developers. 2021-02-26 Fixed the formatting. Clarified that ATS only applies to URLSession. Minor editorial changes. 2020-04-17 Updated the discussion of Subject Alternative Name to account for changes in the 2019 OS releases. Minor editorial updates. 2018-10-29 Minor editorial updates. 2016-11-11 First posted.
Replies
0
Boosts
0
Views
8.4k
Activity
Nov ’25
XPC Connection with Network Extension fails after upgrade
Hi Team, I have a Network Extension application and UI frontend for it. The UI frontend talks to the Network Extension using XPC, as provided by NEMachServiceName. On M2 machine, The application and XPC connection works fine on clean installation. But, when the application is upgraded, the XPC connection keeps failing. Upgrade steps: PreInstall script kills the running processes, both UI and Network Extension Let installation continue PostInstall script to launch the application after installation complete. Following code is successful to the point of resume from UI application NSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCUIObject)]; newConnection.exportedInterface = exportedInterface; newConnection.exportedObject = delegate; NSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCExtObject)]; newConnection.remoteObjectInterface = remoteObjectInterface; self.currentConnection = newConnection; [newConnection resume]; But it fails to get the object id<IPCExtObject> providerProxy = [self.currentConnection remoteObjectProxyWithErrorHandler:^(NSError *registerError) { }]; Please note, this only fails for M2. For M1, this exact code is running fine. Additionally, if I uninstall the application by dropping it in Trash and then installing the newer version, then too, the application works fine.
Replies
4
Boosts
0
Views
990
Activity
Dec ’25
Crash when deallocating NEAppProxyFlow
Hello, I'm working on a Transparent Proxy and when the proxy is being stopped, I'm stopping all the flows by calling flow.closeWriteWithError(POSIXError(.ECANCELED)) flow.closeReadWithError(POSIXError(.ECANCELED)) Then all the flows are deallocated. When deallocating the flow the crash occurs: OS Version: macOS 14.1.2 (23B92) Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000018c2ef704 Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [553] Thread 32 Crashed:: Dispatch queue: <my dispatch queue> 0 CoreFoundation 0x18c2ef704 CF_IS_OBJC + 76 1 CoreFoundation 0x18c23f61c CFErrorGetDomain + 32 2 libnetworkextension.dylib 0x19fe56a00 flow_error_to_errno + 28 3 libnetworkextension.dylib 0x19fe56920 flow_handle_pending_write_requests + 216 4 libnetworkextension.dylib 0x19fe5667c __NEFlowDeallocate + 380 5 CoreFoundation 0x18c2efe28 _CFRelease + 292 6 NetworkExtension 0x19d208390 -[NEAppProxyFlow dealloc] + 36 Is there any way to debug what is happening and if it's related to closing the flow with POSIXError? Thank you
Replies
3
Boosts
0
Views
244
Activity
Jul ’25
Matter Generic Switch not resuming subscription on reboot
I'm developing a Matter-over-thread generic switch with 2 generic switch endpoints. This is configured as an Intermittently Connected Device with Long Idle Time. I have an Apple TV serving as the thread border router. I'm able to commission the device successfully in the Home app and assign actions to each of the buttons however when the device is rebooted the subscription doesn't appear to resume successfully and the buttons no longer work. I've tested this on various SOC's with their respective SDKs including ESP32-C6, nrf52840 and EFR32MG24 and the behaviour was consistent across all of them. It was working originally when I first started out on the ESP32-C6, then the issue popped up first when I was testing the nrf52840. In that SDK I set persistent subscriptions explicitly and it seemed to resolve the issue until it popped up again when I found that unplugging and restarting the Apple TV completely which appeared to fix the issue with subscriptions not resuming. Recently I've added a Home Pod Mini Gen 2 to the matter fabric so there are now two TBR on the network and restarting both the Apple TV and the HomePod doesn't appear to resolve the issue anymore and the subscriptions are not resuming across all three SOC's on device reboot I'm wondering if there might be something preventing the subscriptions from resuming?
Replies
2
Boosts
0
Views
211
Activity
May ’25
Video AirPlay from iOS to tvOS doesn't work with VPN on when enforceRoutes is enabled
Hey! We discovered an unexpected side-effect of enabling enforceRoutes in our iOS VPN application - video airplay from iOS to tvOS stopped working (Unable to Connect popup appears instead). Our flags combination is: includeAllNetworks = false enforceRoutes = true excludeLocalNetworks = true Interestingly, music content can be AirPlayed with the same conditions. Also, video AirPlay from iOS device to the macOS works flawlessly. Do you know if this is a known issue? Do you have any advice if we can fix this problem on our side, while keeping enforcRoutes flag enabled?
Replies
1
Boosts
0
Views
97
Activity
Mar ’26
App occassionally crashing while connecting to public wifi
We are using the [NEHotspotHelper supportedNetworkInterfaces] to get the Wi-Fi interface in our app, but it occasionally crashes on some devices with the following stack trace: 0 CaptiveNetwork 0x0000000221d87a4c ServerConnectionGetHandlerQueue + 0 (ServerConnection.c:509) 1 CaptiveNetwork 0x0000000221d8577c CNPluginCopySupportedInterfaces + 180 (CNPlugin.c:457) 2 NetworkExtension 0x00000001b0446618 +[NEHotspotHelper supportedNetworkInterfaces] + 32 (NEHotspotHelper.m:563) It seems like the crash is happening on apple's api of supportedNetworkInterfaces. We would like to understand the cause of the crash.
Replies
2
Boosts
0
Views
95
Activity
May ’25
WiFi aware demo paring issue
I am developing a program on my chip and attempting to establish a connection with the WiFi Aware demo app launched by iOS 26. Currently, I am encountering an issue during the pairing phase. If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I see the PIN code displayed by iOS. Question 1: How should I use this PIN code? Question 2: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process? If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I should display the PIN code. Question 3: How do I generate this PIN code? Question 4: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process?
Replies
1
Boosts
0
Views
613
Activity
Nov ’25
NETransparentProxyProvider frequent tunnel churn during Dark Wake cycles on macOS.
Description Our NETransparentProxyProvider system extension maintains a persistent TLS/DTLS control channel to a security gateway. To maintain this stateful connection the extension sends application-level "Keep Alive" packets every few seconds (example : 20 seconds). The Issue: When the macOS device enters a sleep state, the Network Extension process is suspended, causing our application-level heartbeat to cease. Consequently, our backend gateway—detecting no activity—terminates the session via Dead Peer Detection (DPD). The problem is exacerbated by macOS Dark Wake cycles. We observe the extension's wake() callback being triggered periodically (approx. every 15 minutes) while the device remains in a sleep state (lid closed). During these brief windows: The extension attempts to use the existing socket, finds it terminated by the backend, and initiates a full re-handshake. Shortly after the connection is re-established, the OS triggers the sleep() callback and suspends the process again. This creates a "connection churn" cycle that generates excessive telemetry noise and misleading "Session Disconnected" alerts for our enterprise customers. Steps to Reproduce Activate Proxy: Start the NETransparentProxyProvider and establish a TLS session to a gateway. Apply Settings: Configure NETransparentProxyNetworkSettings to intercept outbound TCP/UDP traffic. Initialize Heartbeat: Start a 20-second timer (DispatchSourceTimer) to log and send keep-alive packets. Induce Sleep: Put the Mac to sleep (Apple Menu > Sleep). Observe Logs: Monitor the system via sysdiagnose or the macOS Console. Observation: Logs stop entirely during sleep, indicating process suspension. Observation: wake() and sleep() callbacks are triggered repeatedly during Dark Wake intervals, causing a cycle of re-connections. Expected Behavior We seek to minimize connection turnover during maintenance wakes and maintain session stability while the device is technically in a sleep state. Questions for Apple Is it possible to suppress the sleep and wake callback methods of NETransparentProxyProvider when the device is performing a maintenance/Dark Wake, only triggering them for a full user-initiated wake? Is it possible to prevent the NETransparentProxyProvider process from being suspended during sleep, or at least grant it a high-priority background execution slot to maintain the heartbeat? If suspension is mandatory, is there a recommended way to utilize TCP_KEEPALIVE socket options that the kernel can handle on behalf of the suspended extension? How can the extension programmatically identify if a wake() call is a "Dark Wake" versus a "Full User Wake" to avoid unnecessary re-connection logic?
Replies
3
Boosts
0
Views
171
Activity
Feb ’26
Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering traffic by URL sample code Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
3.2k
Activity
Mar ’26
A Peek Behind the NECP Curtain
From time to time the subject of NECP grows up, both here on DevForums and in DTS cases. I’ve posted about this before but I wanted to collect those tidbits into single coherent post. If you have questions or comments, start a new thread in the App & System Services > Networking subtopic and tag it with Network Extension. That way I’ll be sure to see it go by. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" A Peek Behind the NECP Curtain NECP stands for Network Extension Control Protocol. It’s a subsystem within the Apple networking stack that controls which programs have access to which network interfaces. It’s vitally important to the Network Extension subsystem, hence the name, but it’s used in many different places. Indeed, a very familiar example of its use is the Settings > Mobile Data [1] user interface on iOS. NECP has no explicit API, although there are APIs that are offer some insight into its state. Continuing the Settings > Mobile Data example above, there is a little-known API, CTCellularData in the Core Telephony framework, that returns whether your app has access to WWAN. Despite having no API, NECP is still relevant to developers. The Settings > Mobile Data example is one place where it affects app developers but it’s most important for Network Extension (NE) developers. A key use case for NECP is to prevent VPN loops. When starting an NE provider, the system configures the NECP policy for the NE provider’s process to prevent it from using a VPN interface. This means that you can safely open a network connection inside your VPN provider without having to worry about its traffic being accidentally routed back to you. This is why, for example, an NE packet tunnel provider can use any networking API it wants, including BSD Sockets, to run its connection without fear of creating a VPN loop [1]. One place that NECP shows up regularly is the system log. Next time you see a system log entry like this: type: debug time: 15:02:54.817903+0000 process: Mail subsystem: com.apple.network category: connection message: nw_protocol_socket_set_necp_attributes [C723.1.1:1] setsockopt 39 SO_NECP_ATTRIBUTES … you’ll at least know what the necp means (-: Finally, a lot of NECP infrastructure is in the Darwin open source. As with all things in Darwin, it’s fine to poke around and see how your favourite feature works, but do not incorporate any information you find into your product. Stuff you uncover by looking in Darwin is not considered API. [1] Settings > Cellular Data if you speak American (-: [2] Network Extension providers can call the createTCPConnection(to:enableTLS:tlsParameters:delegate:) method to create an NWTCPConnection [3] that doesn’t run through the tunnel. You can use that if it’s convenient but you don’t need to use it. [3] NWTCPConnection is now deprecated, but there are non-deprecated equivalents. For the full story, see NWEndpoint History and Advice. Revision History 2025-12-12 Replaced “macOS networking stack” with “Apple networking stack” to avoid giving the impression that this is all about macOS. Added a link to NWEndpoint History and Advice. Made other minor editorial changes. 2023-02-27 First posted.
Replies
0
Boosts
0
Views
2.6k
Activity
Dec ’25
Unable to update app with PacketTunnelProvider running
Hi there, I am working on an app that configures a PacketTunnelProvider to establish a VPN connection. Unfortunately, while a VPN connection is established, I am unable to update the app via testflight. Downloading other app updates works fine. I noticed that after I receive the alert that updating failed, the vpn badge appears at the top of my screen (the same ux that occurs when the connection is first established). So it's almost like it tried to close the tunnel, and seeing that the app update failed it restablishes the tunnel. I am unsure of why I would not be able to update my app. Maybe stopTunnel is not being called with NEProviderStopReason.appUpdate?
Replies
1
Boosts
0
Views
69
Activity
Jun ’25
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
124
Activity
2w
Need Help with TUN Writeback
Hi everyone, I'm currently experimenting with building a simple DNS filter using Apple's Packet Tunnel framework. Here's the flow I'm trying to implement: Create a TUN interface Set up a UDP socket Read packets via packetFlow.readPackets Parse the raw IP packet Forward the UDP payload through the socket Receive the response from the server Reconstruct the IP packet with the response Write it back to the TUN interface using packetFlow.writePackets Here’s an example of an intercepted IP packet (DNS request): 45 00 00 3c 15 c4 00 00 40 11 93 d1 c0 a8 00 64 08 08 08 08 ed 6e 00 35 00 28 e5 c9 7f da 01 00 00 01 00 00 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 And here’s the IP packet I tried writing back into the TUN interface (DNS response): 45 00 00 89 5e 37 40 00 40 11 0b 11 08 08 08 08 c0 a8 00 64 00 35 ed 6e 00 75 91 e8 7f da 81 80 00 01 00 04 00 00 00 00 04 74 69 6d 65 05 61 70 70 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 05 00 01 00 00 0c fb 00 11 04 74 69 6d 65 01 67 07 61 61 70 6c 69 6d 67 c0 17 c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 fd c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 74 7d c0 2c 00 01 00 01 00 00 03 04 00 04 11 fd 54 fb Unfortunately, it seems the packet is not being written back correctly to the TUN interface. I'm not seeing any expected DNS response behavior on the device. Also, I noticed that after creating the TUN, the interface address shows up as 0.0.0.0:0 in Xcode. The system log includes this message when connecting the VPN: NWPath does not have valid interface: satisfied (Path is satisfied), interface: utun20[endc_sub6], ipv4, dns, expensive, uses cellular Does anyone know how to properly initialize the TUN so that the system recognizes it with a valid IP configuration? Or why my written-back packet might be getting ignored? Any help would be appreciated!
Replies
1
Boosts
0
Views
93
Activity
Jul ’25
Sporadic "no route to host" over ssh
When connecting to my M1 mac mini over ssh, certain programs are often unable to reach network destinations in the corporate LAN, although they can usually reach external addresses like www.apple.com. For example, a java program attempting to download from teamcity.dev.corp.com:8111 often fails like: java.net.NoRouteToHostException: No route to host Running the exact same command from the Apple Terminal program works like normal, simply connecting over ethernet on en0 to a TeamCity server inside the same building. Basic diagnostics from the ssh session do not show anything unusual: > traceroute teamcity.dev.corp.com traceroute to teamcity.dev.corp.com (10.21.4.1), 64 hops max, 40 byte packets 1 teamcity.dev.corp.com (10.21.4.1) 1.702 ms 0.409 ms 0.336 ms > route -n get teamcity.dev.corp.com route to: 10.21.4.1 destination: 10.21.4.1 interface: en0 flags: <UP,HOST,DONE,LLINFO,WASCLONED,IFSCOPE,IFREF> recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire 0 0 0 0 0 0 1500 1194 > uname -a Darwin mac 25.1.0 Darwin Kernel Version 25.1.0: Mon Oct 20 19:32:47 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8103 arm64 Similar problems occur in docker commands to a remote daemon ("no route to host" or "connection refused"): docker -H tcp://<ip>:<port> ... Most other programs are never affected by this problem. Are there other diagnostic steps that might reveal the cause?
Replies
3
Boosts
0
Views
141
Activity
Jan ’26
NEHotspotHelper API
For our outdoor power supply company that builds public WiFi networks at camping sites, we want to implement the following features in our app: Scan surrounding WiFi networks When detecting specific public WiFi SSIDs, provide users with corresponding passwords Automatically connect to those WiFi networks Regarding the NEHotspotHelper API permission application, when I clicked on https://developer.apple.com/contact/request/network-extension, it redirected me to https://developer.apple.com/unauthorized/. I'm not sure where to properly apply for this permission now.
Replies
1
Boosts
0
Views
37
Activity
May ’25
URL Filter Prefetch Interval guarantee
Hello, I have implemented a URL Filter using the sample provided here: Filtering Traffic by URL. I am also using an App Group to dynamically manage the Bloom filter and block list data. However, when I update my block list URLs and create a new Bloom filter plist in the App Group, the extension does not seem to use the updated Bloom filter even after the prefetch interval expires. Also for testing purpose can I keep this interval to 10 mins or below ?
Replies
3
Boosts
0
Views
283
Activity
3w
Network Relay errors out with "Privacy proxy failed with error 53"
I'm using NERelayManager to set Relay configuration which all works perfectly fine. I then do a curl with the included domain and while I see QUIC connection succeeds with relay server and H3 request goes to the server, the connection gets abruptly closed by the client with "Software caused connection abort". Console has this information: default 09:43:04.459517-0700 curl nw_flow_connected [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] Transport protocol connected (quic) default 09:43:04.459901-0700 curl [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:finish_transport @0.131s default 09:43:04.460745-0700 curl nw_flow_connected [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] Joined protocol connected (http3) default 09:43:04.461049-0700 curl [C1.1.1 192.168.4.197:4433 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:finish_transport @0.133s default 09:43:04.465115-0700 curl [C2 E47A3A0C-7275-4F6B-AEDF-59077ABAE34B 192.168.4.197:4433 quic, multipath service: 1, tls, definite, attribution: developer] cancel default 09:43:04.465238-0700 curl [C2 E47A3A0C-7275-4F6B-AEDF-59077ABAE34B 192.168.4.197:4433 quic, multipath service: 1, tls, definite, attribution: developer] cancelled [C2 FCB1CFD1-4BF9-4E37-810E-81265D141087 192.168.4.139:53898<->192.168.4.197:4433] Connected Path: satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi Duration: 0.121s, QUIC @0.000s took 0.000s, TLS 1.3 took 0.111s bytes in/out: 2880/4322, packets in/out: 4/8, rtt: 0.074s, retransmitted bytes: 0, out-of-order bytes: 0 ecn packets sent/acked/marked/lost: 3/1/0/0 default 09:43:04.465975-0700 curl nw_flow_disconnected [C2 192.168.4.197:4433 cancelled multipath-socket-flow ((null))] Output protocol disconnected default 09:43:04.469189-0700 curl nw_endpoint_proxy_receive_report [C1.1 IPv4#124bdc4d:80 in_progress proxy (satisfied (Path is satisfied), interface: en0[802.11], ipv4, ipv6, dns, proxy, uses wifi)] Privacy proxy failed with error 53 ([C1.1.1] masque Proxy: http://192.168.4.197:4433) default 09:43:04.469289-0700 curl [C1.1.1 192.168.4.197:4433 failed socket-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] event: flow:failed_connect @0.141s, error Software caused connection abort Relay server otherwise works fine with our QUIC MASQUE clients but not with built-in macOS MASQUE client. Anything I'm missing?
Replies
0
Boosts
0
Views
272
Activity
May ’25