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
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I’m developing an app designed for hospital environments, where public internet access may not be available. The app includes two components: the main app and a Local Connectivity Extension. Both rely on persistent TCP socket connections to communicate with a local server.
We’re observing a recurring issue where the extension’s socket becomes unresponsive every 1–3 hours, but only when the device is on the lock screen, even if the main app remains in the foreground.
When the screen is not locked, the connection is stable and no disconnections occur.
❗ Issue Details:
• What’s going on: The extension sends a keep-alive ping packet every second, and the server replies with a pong and a system time packet.
• The bug: The server stops receiving keep alive packets from the extension.
• On the server, we detect about 30 second gap on the server, a gap that shows no packets were received by the extension. This was confirmed via server logs and Wireshark).
• On the extension, from our logs there was no gap in sending packets. From it’s perspective, all packets were sent with no error.
• Because no packet are being received by the server, no packets will be sent to the extension. Eventually the server closes the connection due to keep-alive timeout.
• FYI we log when the NEAppPushProvider subclass sleeps and it did NOT go to sleep while we were debugging.
🧾 Example Logs:
Extension log:
2025-03-24 18:34:48.808 sendKeepAliveRequest()
2025-03-24 18:34:49.717 sendKeepAliveRequest()
2025-03-24 18:34:50.692 sendKeepAliveRequest()
... // continuous sending of the ping packet to the server, no problems here
2025-03-24 18:35:55.063 sendKeepAliveRequest()
2025-03-24 18:35:55.063 keepAliveTimer IS TIME OUT... in CoreService. // this is triggered because we did not receive any packets from the server
2025-03-24 18:34:16.298 No keep-alive received for 16 seconds... connection ID=95b3... // this shows that there has been no packets being received by the extension
...
2025-03-24 18:34:30.298 Connection timed out on keep-alive. connection ID=95b3... // eventually closes due to no packets being received
2025-03-24 18:34:30.298 Remote Subsystem Disconnected {name=iPhone|Replica-Ext|...}
✅ Observations:
• The extension process continues running and logging keep-alive attempts.
• However, network traffic stops reaching the server, and no inbound packets are received by the extension.
• It looks like the socket becomes silently suspended or frozen, without being properly closed or throwing an error.
❓Questions:
• Do you know why this might happen within a Local Connectivity Extension, especially under foreground conditions and locked ?
• Is there any known system behavior that might cause the socket to be suspended or blocked in this way after running for a few hours?
Any insights or recommendations would be greatly appreciated.
Thank you!
Hi everyone,
I'm building a health-focused iOS and watchOS app that uses WatchConnectivity to sync real-time heart rate and core body temperature data from iPhone to Apple Watch. While the HealthKit integration works correctly on the iPhone side, I'm facing persistent issues with WatchConnectivity — the data either doesn't arrive on the Watch, or session(_:didReceiveMessage:) never gets triggered.
Here's the setup:
On iPhone: Using WCSession.default.sendMessage(_:replyHandler:errorHandler:) to send real-time values every few seconds.
On Apple Watch: Implemented WCSessionDelegate, and session(_:didReceiveMessage:) is supposed to update the UI.
Both apps have WCSession.isSupported() checks, activate the session, and assign delegates correctly.
The session state shows isPaired = true and isWatchAppInstalled = true.
Bluetooth and Wi-Fi are on, both devices are unlocked and nearby.
Despite all this, the Watch never receives messages in real-time. Sometimes, data comes through in bulk much later or not at all.
I've double-checked Info.plist configurations and made sure background modes include "Uses Bluetooth LE accessories" and "Background fetch" where appropriate.
I would really appreciate guidance on:
Best practices for reliable, low-latency message delivery with WatchConnectivity.
Debugging steps or sample code to validate message transmission and reception.
Any pitfalls related to UI updates from the delegate method.
Happy to share further details. Thanks in advance!
Topic:
App & System Services
SubTopic:
Networking
Tags:
Watch Connectivity
Health and Fitness
watchOS
Apple Watch
Most apps perform ordinary network operations, like fetching an HTTP resource with URLSession and opening a TCP connection to a mail server with Network framework. These operations are not without their challenges, but they’re the well-trodden path.
If your app performs ordinary networking, see TN3151 Choosing the right networking API for recommendations as to where to start.
Some apps have extra-ordinary networking requirements. For example, apps that:
Help the user configure a Wi-Fi accessory
Require a connection to run over a specific interface
Listen for incoming connections
Building such an app is tricky because:
Networking is hard in general.
Apple devices support very dynamic networking, and your app has to work well in whatever environment it’s running in.
Documentation for the APIs you need is tucked away in man pages and doc comments.
In many cases you have to assemble these APIs in creative ways.
If you’re developing an app with extra-ordinary networking requirements, this post is for you.
Note If you have questions or comments about any of the topics discussed here, put them in a new thread here on DevForums. Make sure I see it by putting it in the App & System Services > Networking area. And feel free to add tags appropriate to the specific technology you’re using, like Foundation, CFNetwork, Network, or Network Extension.
Links, Links, and More Links
Each topic is covered in a separate post:
The iOS Wi-Fi Lifecycle describes how iOS joins and leaves Wi-Fi networks. Understanding this is especially important if you’re building an app that works with a Wi-Fi accessory.
Network Interface Concepts explains how Apple platforms manage network interfaces. If you’ve got this far, you definitely want to read this.
Network Interface Techniques offers a high-level overview of some of the more common techniques you need when working with network interfaces.
Network Interface APIs describes APIs and core techniques for working with network interfaces. It’s referenced by many other posts.
Running an HTTP Request over WWAN explains why most apps should not force an HTTP request to run over WWAN, what they should do instead, and what to do if you really need that behaviour.
If you’re building an iOS app with an embedded network server, see Showing Connection Information in an iOS Server for details on how to get the information to show to your user so they can connect to your server.
Many folks run into trouble when they try to find the device’s IP address, or other seemingly simple things, like the name of the Wi-Fi interface. Don’t Try to Get the Device’s IP Address explains why these problems are hard, and offers alternative approaches that function correctly in all network environments.
Similarly, folks also run into trouble when trying to get the host name. On Host Names explains why that’s more complex than you might think.
If you’re working with broadcasts or multicasts, see Broadcasts and Multicasts, Hints and Tips.
If you’re building an app that works with a Wi-Fi accessory, see Working with a Wi-Fi Accessory.
If you’re trying to gather network interface statistics, see Network Interface Statistics.
There are also some posts that are not part of this series but likely to be of interest if you’re working in this space:
TN3179 Understanding local network privacy discusses the local network privacy feature.
Calling BSD Sockets from Swift does what it says on the tin, that is, explains how to call BSD Sockets from Swift. When doing weird things with the network, you often find yourself having to use BSD Sockets, and that API is not easy to call from Swift. The code therein is primarily for the benefit of test projects, oh, and DevForums posts like these.
TN3111 iOS Wi-Fi API overview is a critical resource if you’re doing Wi-Fi specific stuff on iOS.
TLS For Accessory Developers tackles the tricky topic of how to communicate securely with a network-based accessory.
A Peek Behind the NECP Curtain discusses NECP, a subsystem that control which programs have access to which network interfaces.
Networking Resources has links to many other useful resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision History
2025-07-31 Added a link to A Peek Behind the NECP Curtain.
2025-03-28 Added a link to On Host Names.
2025-01-16 Added a link to Broadcasts and Multicasts, Hints and Tips. Updated the local network privacy link to point to TN3179. Made other minor editorial changes.
2024-04-30 Added a link to Network Interface Statistics.
2023-09-14 Added a link to TLS For Accessory Developers.
2023-07-23 First posted.
Hello,
I'm running into an issue while developing an iOS app that requires local network access. I’m using the latest MacBook Air M4 with macOS sequoia 15.5 and Xcode 16.1. In the iOS Simulator, my app fails to discover devices connected to the same local network.
I’ve already added the necessary key to the Info.plist:
NSLocalNetworkUsageDescription
This app needs access to local network devices.
When I run the app on a real device and M2 Chip Macbook's simulators, it works fine for local network permission as expected. However, in the M4 Chip Macbook's Simulator:
The app can’t find any devices on the local network
Bonjour/mDNS seems not to be working as well
I’ve tried the following without success:
Restarting Simulator and Mac
Resetting network settings in Simulator
Confirming app permissions under System Settings > Privacy & Security
Has anyone else encountered this issue with the new Xcode/macOS combo? Is local network access just broken in the Simulator for now, or is there a workaround?
Thanks in advance!
Continuing with my investigations of several issues that we have been noticing in our testing of the JDK with macosx 15.x, I have now narrowed down at least 2 separate problems for which I need help. For a quick background, starting with macosx 15.x several networking related tests within the JDK have started failing in very odd and hard to debug ways in our internal lab. Reading through the macos docs and with help from others in these forums, I have come to understand that a lot of these failures are to do with the new restrictions that have been placed for "Local Network" operations. I have read through https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy and I think I understand the necessary background about these restrictions.
There's more than one issue in this area that I will need help with, so I'll split them out into separate topics in this forum. That above doc states:
macOS 15.1 fixed a number of local network privacy bugs. If you encounter local network privacy problems on macOS 15.0, retest on macOS 15.1 or later.
We did have (and continue to have) 15.0 and 15.1 macos instances within our lab which are impacted by these changes. They too show several networking related failures. However, I have decided not to look into those systems and instead focus only on 15.3.1.
People might see unexpected behavior in System Settings > Privacy & Security if they have multiple versions of the same app installed (FB15568200).
This feedback assistant issue and several others linked in these documentations are inaccessible (even when I login with my existing account). I think it would be good to have some facility in the feedback assistant tool/site to make such issues visible (even if read-only) to be able to watch for updates to those issues.
So now coming to the issue. Several of the networking tests in the JDK do mulicasting testing (through BSD sockets API) in order to test the Java SE multicasting socket API implementations. One repeated failure we have been seeing in our labs is an exception with the message "No route to host". It shows up as:
Process id: 58700
...
java.net.NoRouteToHostException: No route to host
at java.base/sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at java.base/sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:914)
at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:871)
at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:798)
at java.base/sun.nio.ch.DatagramChannelImpl.blockingSend(DatagramChannelImpl.java:857)
at java.base/sun.nio.ch.DatagramSocketAdaptor.send(DatagramSocketAdaptor.java:178)
at java.base/java.net.DatagramSocket.send(DatagramSocket.java:593)
(this is just one example stacktrace from java program)
That "send0" is implemented by the JDK by invoking the sendto() system call. In this case, the sendto() is returning a EHOSTUNREACH error which is what is then propagated to the application.
The forum text editor doesn't allow me to post long text, so I'm going to post the rest of this investigation and logs as a reply.
hello
I am testing the use of network extension. When we use dnsproxy to proxy DNS requests,
we will send you a message that the udp pcbcount of your system continues to increase.
For example
for ((i=1; i<=99999; i++));do
echo "Attempt $i:"
dig google.com
done
when the dig command is used continuously,
the dig command will show the following errors when pcbcount reaches a certain number.
isc_socket_bind: address not available
Can you help us determine what the problem might be? thank you
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:
Wi-Fi Fundamentals forums post
TN3111 iOS Wi-Fi API overview technote
How to modernize your captive network developer news post
iOS Network Signal Strength forums post
See also Networking Resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
I'm trying to use ThreadNetwork API to manage TheradNetworks on device (following this documentation: https://developer.apple.com/documentation/threadnetwork/), but while some functions on THClient work (such as getPreferedNetwork), most don't (storeCredentials, retrieveAllCredentials). When calling these functions I get the following warning/error:
Client: -[THClient getConnectionEntitlementValidity]_block_invoke - Error:
-[THClient storeCredentialsForBorderAgent:activeOperationalDataSet:completion:]_block_invoke:701: - Error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 414 named com.apple.ThreadNetwork.xpc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service with pid 414 named com.apple.ThreadNetwork.xpc was invalidated from this process.}
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 414 named com.apple.ThreadNetwork.xpc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service with pid 414 named com.apple.ThreadNetwork.xpc was invalidated from this process.}
Failed to store Thread credentials: Couldn’t communicate with a helper application.
STEPS TO REPRODUCE
Create new project
Add Thread Network capability via Xcode UI (com.apple.developer.networking.manage-thread-network-credentials)
Trigger storeCredentials
let extendedMacData = "9483C451DC3E".hexadecimal
let tlvHex = "0e080000000000010000000300001035060004001fffe002083c66f0dc9ef53f1c0708fdb360c72874da9905104094dce45388fd3d3426e992cbf0697b030d474c2d5332302d6e65773030310102250b04106c9f919a4da9b213764fc83f849381080c0402a0f7f8".hexadecimal
// Initialize the THClient
let thClient = THClient()
// Store the credentials
await thClient.storeCredentials(forBorderAgent: extendedMacData!, activeOperationalDataSet: tlvHex!) { error in
if let error = error {
print(error)
print("Failed to store Thread credentials: \(error.localizedDescription)")
} else {
print("Successfully stored Thread credentials")
}
}
NOTES:
I tried with first calling getPreferedNetwork to initiate network permission dialog
Tried adding meshcop to bojur services
Tried with different release and debug build configurations
Greetings,
According to Apple's Wi-Fi Aware documentation (https://developer.apple.com/documentation/wifiaware) the Wi-Fi Aware APIs can be used only with peer devices that have been paired. Pairing can be performed using AccessorySetupKit or DeviceDiscoveryUI.
Unfortunately, the sample code for Wi-Fi Aware doesn't include either of these APIs. (https://developer.apple.com/documentation/wifiaware/building-peer-to-peer-apps)
Looking at the sample code for AccessorySetupKit (https://developer.apple.com/documentation/accessorysetupkit/setting-up-and-authorizing-a-bluetooth-accessory) there is only an example using Bluetooth. And the AccessorySetupKit APIs don't yet document how Wi-Fi Aware is used or how one sets up the Info.plist with the appropriate keys.
Can Apple update its example code to fill in these gaps or point me to documentation that can fill in these gaps? It is hard to develop an understanding of the capabilities of these APIs when they are so poorly documented.
Thanks for any help,
Smith
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.
HI,
I am currently developing an app that utilizes Wi-Fi Aware.
According to the Wi-Fi Aware framework examples and the WWDC25 session on Wi-Fi Aware, discovery is handled using DevicePairingView and DevicePicker from the DeviceDiscoveryUI module.
However, these SwiftUI views present their connection UI modally when tapped. My app's design requires the ability to control the presentation of this UI programmatically, rather than relying on a user tap.
While inspecting the DeviceDiscoveryUI module, I found DDDevicePairingViewController and DDDevicePickerViewController, which appear to be the UIViewController counterparts to the SwiftUI views.
The initializer for DDDevicePairingViewController accepts a ListenerProvider, so it seems I can pass the same ListenerProvider instance that is used with the DevicePairingView.
However, the initializer for DDDevicePickerViewController requires an NWBrowser.Descriptor, which seems incompatible with the parameters used for the SwiftUI DevicePicker.
I have two main questions:
(1) Can DDDevicePairingViewController and DDDevicePickerViewController be officially used for Wi-Fi Aware pairing?
(2) Are there any plans to provide more customization or programmatic control over the DevicePairingView and DevicePicker (for example, allowing us to trigger their modal presentation programmatically)?
Thank you.
Topic:
App & System Services
SubTopic:
Networking
Dear Apple:
We found that after mirroring an iPhone and a Mac, calling the NEHotspotConfigurationManager applyConfiguration interface on the iPhone fails to connect to Wi-Fi. Are there any restrictions on using this interface in mirror mode?
I want to add more cipher suites. I use NWConnection to make a connection.
Before I use sec_protocol_options_append_tls_ciphersuite method to add more cipher suites, I found that Apple provided 20 cipher suites shown in the client hello packet. But after I added three more cipher suites, I found that nothing changed, and still original 20 cipher suites shown in the client hello packet when I made a new connection.
The following is the code about connection. I want to add three more cipher suites: tls_ciphersuite_t.ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
tls_ciphersuite_t.ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
tls_ciphersuite_t.ECDHE_RSA_WITH_AES_256_CBC_SHA384
Can you give me some advice about how to add more cipher suites? Thanks.
By the way, I working on a MacOS app.
Xcode version: 16
MacOS version: 15.6
Hello Apple Support Team,
We are seeing a production crash on iOS 26 devices that appears to originate from Apple system frameworks rather than application code.
Crash Summary
Crash signature: _xzm_xzone_malloc_freelist_outlined
Crashed thread: com.apple.network.connections
Frameworks involved: CFNetwork, Security, libdispatch, libsystem_malloc
Affected OS: iOS 26.x
App built with: Xcode 16
Devices: Multiple models (not device-specific)
Reproducibility: Intermittent, higher frequency during app launch / background networking
Observed Stack Trace (top frames)
_xzm_xzone_malloc_freelist_outlined
dispatch_data_create_alloc
xpc_data_deserialize
SecTrustEvaluateIfNecessary
CFNetwork HTTPProtocol / HTTP3Connection
com.apple.network.connections
App Context
The app uses URLSession for networking.
Multiple third-party SDKs are integrated (Firebase Analytics, Dynatrace, Appsflyer, and similar analytics/monitoring SDKs).
These SDKs perform concurrent background network requests, especially during app launch and foreground transitions.
No unsafe memory operations (manual malloc/free, unsafe pointers, or custom networking stacks) are used in the app code.
Key Observations
The crash is predominantly observed on iOS 26 and not on earlier iOS versions.
Stack traces do not include application symbols.
Disabling or delaying analytics SDK initialization significantly reduces the crash rate.
Reducing concurrent network requests and limiting HTTP/3 usage also mitigates the issue.
This suggests a potential regression in CFNetwork / Network.framework / HTTP/3 handling combined with the new memory allocator (xzone) on iOS 26.
Impact
Random app termination during background networking.
Occurs without a clear deterministic repro path, making it difficult to fully mitigate at the app level.
Request
Could you please help investigate whether this is a known iOS 26 issue related to:
HTTP/3 / QUIC networking
XPC deserialization
Memory allocation in the new xzone allocator
High-concurrency network requests
We would appreciate guidance on:
Recommended mitigations
Whether this issue is already tracked internally
Any best practices for apps integrating multiple analytics SDKs on iOS 26
Crash logs and additional diagnostics can be provided if needed.
Thank you for your support.
Best regards,
Dhananjay
Topic:
App & System Services
SubTopic:
Networking
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?
Please consider this very trivial C code, which was run on 15.3.1 of macos:
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "sys/socket.h"
#include <string.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <net/if.h>
// prints out the sockaddr_in6
void print_addr(const char *msg_prefix, struct sockaddr_in6 sa6) {
char addr_text[INET6_ADDRSTRLEN] = {0};
printf("%s%s:%d, addr family=%u\n",
msg_prefix,
inet_ntop(AF_INET6, &sa6.sin6_addr, (char *) &addr_text, INET6_ADDRSTRLEN),
sa6.sin6_port,
sa6.sin6_family);
}
// creates a datagram socket
int create_dgram_socket() {
const int fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0) {
perror("Socket creation failed");
return -1;
}
return fd;
}
int main() {
printf("current process id:%ld parent process id: %ld\n", (long) getpid(), (long) getppid());
//
// hardcode a link-local IPv6 address of a interface which is down
// ifconfig:
// ,,,
// awdl0: flags=8822<BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
// options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
// ...
// inet6 fe80::34be:50ff:fe14:ecd7%awdl0 prefixlen 64 scopeid 0x10
// nd6 options=201<PERFORMNUD,DAD>
// media: autoselect (<unknown type>)
// status: inactive
//
const char *ip6_addr_str = "fe80::34be:50ff:fe14:ecd7"; // link-local ipv6 address from above ifconfig output
// parse the string literal to in6_addr
struct in6_addr ip6_addr;
int rv = inet_pton(AF_INET6, ip6_addr_str, &ip6_addr);
if (rv != 1) {
fprintf(stderr, "failed to parse ipv6 addr %s\n", ip6_addr_str);
exit(EXIT_FAILURE);
}
// create a AF_INET6 SOCK_DGRAM socket
const int sock_fd = create_dgram_socket();
if (sock_fd < 0) {
exit(EXIT_FAILURE);
}
printf("created a socket, descriptor=%d\n", sock_fd);
// create a destination sockaddr which points to the above
// ipv6 link-local address and an arbitrary port
const int dest_port = 12345;
struct sockaddr_in6 dest_sock_addr;
memset((char *) &dest_sock_addr, 0, sizeof(struct sockaddr_in6));
dest_sock_addr.sin6_addr = ip6_addr;
dest_sock_addr.sin6_port = htons(dest_port);
dest_sock_addr.sin6_family = AF_INET6;
dest_sock_addr.sin6_scope_id = 0x10; // scopeid from the above ifconfig output
// now sendto() to that address, whose network interface is down.
// we expect sendto() to return an error
print_addr("sendto() to ", dest_sock_addr);
const char *msg = "hello";
const size_t msg_len = strlen(msg) + 1;
rv = sendto(sock_fd, msg, msg_len, 0, (struct sockaddr *) &dest_sock_addr, sizeof(dest_sock_addr));
if (rv == -1) {
perror("sendto() expectedly failed");
close(sock_fd);
exit(EXIT_FAILURE);
}
printf("sendto() unexpectedly succeeded\n"); // should not reach here, we expect sendto() to return an error
return 0;
}
It creates a SOCK_DGRAM socket and attempts to sendto() to a link-local IPv6 address of a local network interface which is not UP. The sendto() is expected to fail with a "network is down" (or at least fail with some error). Let's see how it behaves.
Copy that code to a file called netdown.c and compile it as follows:
clang netdown.c
Now run the program:
./a.out
That results in the following output:
current process id:29290 parent process id: 21614
created a socket, descriptor=3
sendto() to fe80::34be:50ff:fe14:ecd7:14640, addr family=30
sendto() unexpectedly succeeded
(To reproduce this locally, replace the IPv6 address in that code with a link-local IPv6 address of an interface that is not UP on your system)
Notice how the sendto() returned successfully without any error giving an impression to the application code that the message has been sent. In reality, the message isn't really sent. Here's the system logs from that run:
PID Type Date & Time Process Message
debug 2025-03-13 23:36:36.830147 +0530 kernel Process (a.out) allowed via dev tool environment (/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal)
debug 2025-03-13 23:36:36.833054 +0530 kernel [SPI][HIDSPI]
TX: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
RX: 20 02 00 00 00 00 38 00 10 02 00 17 00 00 2E 00
26700 error 2025-03-13 23:36:36.838607 +0530 nehelper Failed to get the signing identifier for 29290: No such process
26700 error 2025-03-13 23:36:36.838608 +0530 nehelper Failed to get the code directory hash for 29290: No such process
default 2025-03-13 23:36:36.840070 +0530 kernel cfil_dispatch_attach_event:3507 CFIL: Failed to get effective audit token for <sockID 22289651233205710 <4f3051d7ec2dce>>
26700 error 2025-03-13 23:36:36.840678 +0530 nehelper Failed to get the signing identifier for 29290: No such process
26700 error 2025-03-13 23:36:36.840679 +0530 nehelper Failed to get the code directory hash for 29290: No such process
default 2025-03-13 23:36:36.841742 +0530 kernel cfil_hash_entry_log:6082 <CFIL: Error: sosend_reinject() failed>: [29290 ] <UDP(17) out so 891be95f39bd0385 22289651233205710 22289651233205710 age 0> lport 60244 fport 12345 laddr fe80::34be:50ff:fe14:ecd7 faddr fe80::34be:50ff:fe14:ecd7 hash D7EC2DCE
default 2025-03-13 23:36:36.841756 +0530 kernel cfil_service_inject_queue:4466 CFIL: sosend() failed 50
Notice the last line where it states the sosend() (and internal impl detail of macos) failed with error code 50, which corresponds to ENETDOWN ("Network is down"). However, like I noted, this error was never propagated back to the application from the sendto() system call.
The documentation of sendto() system call states:
man sendto
...
Locally detected errors are indicated by a return value of -1.
...
RETURN VALUES
Upon successful completion, the number of bytes which were sent is returned. Otherwise, -1 is returned and the global variable errno is set to indicate the error.
So I would expect sendto() to return -1, which it isn't.
The 15.3.1 source of xnu hasn't yet been published but there is the 15.3 version here https://github.com/apple-oss-distributions/xnu/tree/xnu-11215.81.4 and looking at the corresponding function cfil_service_inject_queue, line 4466 (the one which is reported in the logs) https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/bsd/net/content_filter.c#L4466, the code there logs this error and the cfil_service_inject_queue function then returns back the error. However, looking at the call sites of the call to cfil_service_inject_queue(...), there are several places within that file which don't track the return value (representing an error value) and just ignore it. Is that intentional and does that explain this issue?
Does this deserve to be reported as a bug through feedback assistant?
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?
Topic:
App & System Services
SubTopic:
Networking
Hello,
How long does it usually take for a URL Filter request to be reviewed?
It's been 2.5 weeks since we submitted the request form but we haven't received any feedback yet.
Just in case, the request ID is D3633USVZZ
Questions about FTP crop up from time-to-time here on DevForums. In most cases I write a general “don’t use FTP” response, but I don’t have time to go into all the details. I’ve created this post as a place to collect all of those details, so I can reference them in other threads.
IMPORTANT Apple’s official position on FTP is:
All our FTP APIs have been deprecated, and you should avoid using deprecated APIs.
Apple has been slowly removing FTP support from the user-facing parts of our system. The most recent example of this is that we removed the ftp command-line tool in macOS 10.13.
You should avoid the FTP protocol and look to adopt more modern alternatives.
The rest of this post is an informational explanation of the overall FTP picture.
This post is locked so I can keep it focused. If you have questions or comments, please do create a new thread in the App & System Services > Networking subtopic and I’ll respond there.
Don’t Use FTP
FTP is a very old and very crufty protocol. Certain things that seem obvious to us now — like being able to create a GUI client that reliably shows a directory listing in a platform-independent manner — aren’t possible to do in FTP. However, by far the biggest problem with FTP is that it provides no security [1]. Specifically, the FTP protocol:
Provides no on-the-wire privacy, so anyone can see the data you transfer
Provides no client-authenticates-server authentication, so you have no idea whether you’re talking to the right server
Provides no data integrity, allowing an attacker to munge your data in transit
Transfers user names and passwords in the clear
Using FTP for anonymous downloads may be acceptable (see the explanation below) but most other uses of FTP are completely inappropriate for the modern Internet.
IMPORTANT You should only use FTP for anonymous downloads if you have an independent way to check the integrity of the data you’ve downloaded. For example, if you’re downloading a software update, you could use code signing to check its integrity. If you don’t check the integrity of the data you’ve downloaded, an attacker could substitute a malicious download instead. This would be especially bad in, say, the software update case.
These fundamental problems with the FTP protocol mean that it’s not a priority for Apple. This is reflected in the available APIs, which is the subject of the next section.
FTP APIs
Apple provides two FTP APIs:
All Apple platforms provide FTP downloads via URLSession.
Most Apple platforms (everything except watchOS) support CFFTPStream, which allows for directory listings, downloads, uploads, and directory creation.
All of these FTP APIs are now deprecated:
URLSession was deprecated for the purposes of FTP in the 2022 SDKs (macOS 13, iOS 16, iPadOS 16, tvOS 16, watchOS 9) [2].
CFFTPStream was deprecated in the 2016 SDKs (macOS 10.11, iOS 9, iPadOS 9, tvOS 9).
CFFTPStream still works about as well as it ever did, which is not particularly well. Specifically:
There is at least one known crashing bug (r. 35745763), albeit one that occurs quite infrequently.
There are clear implementation limitations — like the fact that CFFTPCreateParsedResourceListing assumes a MacRoman text encoding (r. 7420589) — that won’t be fixed.
If you’re looking for an example of how to use these APIs, check out SimpleFTPSample.
Note This sample hasn’t been updated since 2013 and is unlikely to ever be updated given Apple’s position on FTP.
The FTP support in URLSession has significant limitations:
It only supports FTP downloads; there’s no support for uploads or any other FTP operations.
It doesn’t support resumable FTP downloads [3].
It doesn’t work in background sessions. That prevents it from running FTP downloads in the background on iOS.
It’s only supported in classic loading mode. See the usesClassicLoadingMode property and the doc comments in <Foundation/NSURLSession.h>.
If Apple’s FTP APIs are insufficient for your needs, you’ll need to write or acquire your own FTP library. Before you do that, however, consider switching to an alternative protocol. After all, if you’re going to go to the trouble of importing a large FTP library into your code base, you might as well import a library for a better protocol. The next section discusses some options in this space.
Alternative Protocols
There are numerous better alternatives to FTP:
HTTPS is by far the best alternative to FTP, offering good security, good APIs on Apple platforms, good server support, and good network compatibility. Implementing traditional FTP operations over HTTPS can be a bit tricky. One possible way forward is to enable DAV extensions on the server.
FTPS is FTP over TLS (aka SSL). While FTPS adds security to the protocol, which is very important, it still inherits many of FTP’s other problems. Personally I try to avoid this protocol.
SFTP is a file transfer protocol that’s completely unrelated to FTP. It runs over SSH, making it a great alternative in many of the ad hoc setups that traditionally use FTP.
Apple doesn’t have an API for either FTPS or SFTP, although on macOS you may be able to make some headway by invoking the sftp command-line tool.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] In another thread someone asked me about FTP’s other problems, those not related to security, so let’s talk about that.
One of FTP’s implicit design goals was to provide cross-platform support that exposes the target platform. You can think of FTP as being kinda like telnet. When you telnet from Unix to VMS, it doesn’t aim to abstract away VMS commands, so that you can type Unix commands at the VMS prompt. Rather, you’re expected to run VMS commands. FTP is (a bit) like that.
This choice made sense back when the FTP protocol was invented. Folks were expecting to use FTP via a command-line client, so there was a human in the loop. If they ran a command and it produced VMS-like output, that was fine because they knew that they were FTPing into a VMS machine.
However, most users today are using GUI clients, and this design choice makes it very hard to create a general GUI client for FTP. Let’s consider the simple problem of getting the contents of a directory. When you send an FTP LIST command, the server would historically run the platform native directory list command and pipe the results back to you. To create a GUI client you have to parse that data to extract the file names. Doing that is a serious challenge. Indeed, just the first step, working out the text encoding, is a challenge. Many FTP servers use UTF-8, but some use ISO-Latin-1, some use other standard encodings, some use Windows code pages, and so on.
I say “historically” above because there have been various efforts to standardise this stuff, both in the RFCs and in individual server implementations. However, if you’re building a general client you can’t rely on these efforts. After all, the reason why folks continue to use FTP is because of it widespread support.
[2] To quote the macOS 13 Ventura Release Notes:
FTP is deprecated for URLSession and related APIs. Please adopt
modern secure networking protocols such as HTTPS. (92623659)
[3] Although you can implement resumable downloads using the lower-level CFFTPStream API, courtesy of the kCFStreamPropertyFTPFileTransferOffset property.
Revision History
2025-10-06 Explained that URLSession only supports FTP in classic loading mode. Made other minor editorial changes.
2024-04-15 Added a footnote about FTP’s other problems. Made other minor editorial changes.
2022-08-09 Noted that the FTP support in URLSession is now deprecated. Made other minor editorial changes.
2021-04-06 Fixed the formatting. Fixed some links.
2018-02-23 First posted.