Our app receives real-time GPS and aircraft data from devices via UDP broadcast and/or multicast on a WiFi network created by the device.
We have identified that the iPhone or iPad will just stop receiving UDP broadcast/multicast data for an interval of time. In general, it appears after roughly every 128KB of data is received.
In the attached screenshot from Xcode instruments, you can see the data reception alternating on/off.
We have verified with Wireshark that the data is still flowing during that entire time period. And by tracking bytes received the app ultimately receives about 55% of the bytes, which tracks with the Network graph.
We have used different approaches to the network code, including GCDAsyncUdpSocket, BSD Sockets, and the Network framework. We've tried it on background threads and the main thread. Tested it on iPads and iPhones. All produce the same result. The data is just never reaching the app code.
Any insight on what may be temporarily disabling data reception?
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
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
I use eapolcfg in Apple's open source eap8021x repository to connect to the enterprise network.
1.https://github.com/gfleury/eap8021x-debug
https://opensource.apple.com/source/eap8021x/eap8021x-304.100.1/
Our enterprise network authentication is PEAP. So far, I have created a profile using the following commands and have done the access.
./eapolcfg createProfile --authType PEAP --SSID myssid --securityType WPA2 --userDefinedName MyProfile
./eapolcfg setPasswordItem --password mypassword --name myname --SSID myssid
./eapolcfg startAuthentication --interface en0 --SSID myssid
After I performed this series of operations, I passed
BOOL success = [self.interface associateToEnterpriseNetwork:network identity:nil username:username password:password error:&error];
Connection will pop up the following pop-up window, sometimes associateToEnterpriseNetwork will fail. I don't know what went wrong, is it that I missed some steps through the eapolcfg [tool?]
This function also reports the following error:Error Domain=com.apple.coreWLAN.EAPOL.error Code=1
"(null)"
Please answer my questions. Thank you very much
Hi!
I wrote an internal used backup command line tool which is in use since several years.
Today I got an error while sending an email: “Failed: ioOnClosedChannel”.
I assume that the latest macOS updates did break my app. On the server I use macOS 15.7 and on my development machine macOS 26.
Here is the related code:
private func sendMail() {
var a : [Email.Attachment] = []
if self.imageData != nil {
switch self.imageType {
case .tiff:
a.append(Email.Attachment(name: "Statistics.tif", contentType: #"image/tiff"#, contents: ByteBuffer(bytes: self.imageData!)))
case .pdf:
a.append(Email.Attachment(name: "Statistics.pdf", contentType: #"application/pdf"#, contents: ByteBuffer(bytes: self.imageData!)))
case .unknown:
fatalError("Unimplemented attachment type!")
}
}
mailHtml = mailHtml.replacingOccurrences(of: "<br>", with: "<br>\n")
let email = Email(sender: .init(name: "Backup", emailAddress: "SENDER@MYDOMAIN"),
replyTo: nil,
recipients: recipients,
cc: [],
bcc: [],
subject: self.subject,
body: .universal(plain: self.mailText, html: mailHtml),
attachments: a)
let evg = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let mailer = Mailer(group: evg,
configuration: smtpConfig,
transmissionLogger: nil)
do {
print("Sending mail... ", terminator: "")
try mailer.send(email: email).wait() // <-- ERROR HERE Failed: ioOnClosedChannel
print("done.")
} catch {
print("Failed: \(error)")
}
do {
try evg.syncShutdownGracefully()
} catch {
print("Failed shutdown: \(error)")
}
}
I use https://github.com/sersoft-gmbh/swift-smtp.
Any clue about the reason of this error?
TIA,
GreatOm
Topic:
App & System Services
SubTopic:
Networking
Starting in iOS 26, two notable changes have been made to CallKit, LiveCommunicationKit, and the PushToTalk framework:
As a diagnostic aid, we're introducing new dialogs to warn apps of voip push related issue, for example when they fail to report a call or when when voip push delivery stops. The specific details of that behavior are still being determined and are likely to change over time, however, the critical point here is that these alerts are only intended to help developers debug and improve their app. Because of that, they're specifically tied to development and TestFlight signed builds, so the alert dialogs will not appear for customers running app store builds. The existing termination/crashes will still occur, but the new warning alerts will not appear.
As PushToTalk developers have previously been warned, the last unrestricted PushKit entitlement ("com.apple.developer.pushkit.unrestricted-voip.ptt") has been disabled in the iOS 26 SDK. ALL apps that link against the iOS 26 SDK which receive a voip push through PushKit and which fail to report a call to CallKit will be now be terminated by the system, as the API contract has long specified.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware
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?
Hi folks, I'm building an iOS companion app to a local hosted server app (hosted on 0.0.0.0). The MacOS app locally connects to this server hosted, and I took the approach of advertising the server using a Daemon and BonjourwithTXT(for port) and then net service to resolve a local name. Unfortunately if there's not enough time given after the iPhone/iPad is plugged in (usb or ethernet), the app will cycle through attempts and disconnects many times before connecting and I'm trying to find a way to only connect when a viable en interface is available.
I've run into a weird thing in which the en interface only becomes seen on the NWMonitor after multiple connection attempts have been made and failed. If I screen for en before connecting it simply never appears. Is there any way to handle this such that my app can intelligently wait for an en connection before trying to connect? Attaching my code although I have tried a few other setups but none has been perfect.
func startMonitoringAndBrowse() {
DebugLogger.shared.append("Starting Bonjour + Ethernet monitoring")
if !browserStarted {
let params = NWParameters.tcp
params.includePeerToPeer = false
params.requiredInterfaceType = .wiredEthernet
browser = NWBrowser(for: .bonjourWithTXTRecord(type: "_mytcpapp._tcp", domain: nil), using: params)
browser?.stateUpdateHandler = { state in
if case .ready = state {
DebugLogger.shared.append("Bonjour browser ready.")
}
}
browser?.browseResultsChangedHandler = { results, _ in
self.handleBrowseResults(results)
}
browser?.start(queue: .main)
browserStarted = true
}
// Start monitoring for wired ethernet
monitor = NWPathMonitor()
monitor?.pathUpdateHandler = { path in
let hasEthernet = path.availableInterfaces.contains { $0.type == .wiredEthernet }
let ethernetInUse = path.usesInterfaceType(.wiredEthernet)
DebugLogger.shared.append("""
NWPathMonitor:
- Status: \(path.status)
- Interfaces: \(path.availableInterfaces.map { "\($0.name)[\($0.type)]" }.joined(separator: ", "))
- Wired Ethernet: \(hasEthernet), In Use: \(ethernetInUse)
""")
self.tryToConnectIfReady()
self.stopMonitoring()
}
monitor?.start(queue: monitorQueue)
}
// MARK: - Internal Logic
private func handleBrowseResults(_ results: Set<NWBrowser.Result>) {
guard !self.isResolving, !self.hasResolvedService else { return }
for result in results {
guard case let .bonjour(txtRecord) = result.metadata,
let portString = txtRecord["actual_port"],
let actualPort = Int(portString),
case let .service(name, type, domain, _) = result.endpoint else {
continue
}
DebugLogger.shared.append("Bonjour result — port: \(actualPort)")
self.resolvedPort = actualPort
self.isResolving = true
self.resolveWithNetService(name: name, type: type, domain: domain)
break
}
}
private func resolveWithNetService(name: String, type: String, domain: String) {
let netService = NetService(domain: domain, type: type, name: name)
netService.delegate = self
netService.includesPeerToPeer = false
netService.resolve(withTimeout: 5.0)
resolvingNetService = netService
DebugLogger.shared.append("Resolving NetService: \(name).\(type)\(domain)")
}
private func tryToConnectIfReady() {
guard hasResolvedService,
let host = resolvedHost, let port = resolvedPort else { return }
DebugLogger.shared.append("Attempting to connect: \(host):\(port)")
discoveredIP = host
discoveredPort = port
connectionPublisher.send(.connecting(ip: host, port: port))
stopBrowsing()
socketManager.connectToServer(ip: host, port: port)
hasResolvedService = false
}
}
// MARK: - NetServiceDelegate
extension BonjourManager: NetServiceDelegate {
func netServiceDidResolveAddress(_ sender: NetService) {
guard let hostname = sender.hostName else {
DebugLogger.shared.append("Resolved service with no hostname")
return
}
DebugLogger.shared.append("Resolved NetService hostname: \(hostname)")
resolvedHost = hostname
isResolving = false
hasResolvedService = true
tryToConnectIfReady()
}
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
DebugLogger.shared.append("NetService failed to resolve: \(errorDict)")
}
}
We are currently working on a zero-configuration networking compliant device thru avahi-daemon.
Our Device want to have multiple Instance name for different services.
Example
InstanceA._ipps._tcp.local.
InstanceA._ipp._tcp.local.
InstanceB._ipps._tcp.local.
InstanceB._ipp._tcp.local.
Will BCT confuse this as multiple device connected in the network and cause it to fail? Does Bonjour only allows only a Single Instance name with multiple services?
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.
Firstly, I'm completely new to native Swift/iOS Development so apologies if this is a simple question that I'm seemingly misunderstanding.
I have an app which has the Multicast Networking entitlement and works fine on my own iPhone, however it only has one interface when I list them (en0)
The multicast networking, however, fails entirely on another test iPhone but this also appears to have one or more 'ipsecX' interfaces both with the IP 192.0.0.6 - I'm guessing but I wonder if this is related to a connection to Apple Watch as I've noticed two devices that have these additional interfaces, and both of them are connected to Apple Watch (with no VPNs configured) and that's the only thing that differentiates them from my own iPhone.
I can reproduce the symptoms on my own iPhone by connecting to a VPN which creates a utunX interface (but in my case disconnecting from the VPN removes this interface and it works as expected)
I expect a solution would be to bind my Multicast Group to the WiFi IP but I've tried a few things without success;
Setting params.requiredInterfaceType = .wifi
Looping through each interface to try and 'find' en0 and bind this way;
let queue = DispatchQueue(label: "En0MonitorQueue")
monitor.pathUpdateHandler = { [weak self] path in
// Find the en0 interface
if let en0 = path.availableInterfaces.first(where: { $0.name == "en0" }) {
monitor.cancel() // Stop monitoring once found
let params = NWParameters.udp
params.allowLocalEndpointReuse = true
params.requiredInterface = en0
guard let multicast = try? NWMulticastGroup(for: [
.hostPort(
host: NWEndpoint.Host(self?.settings.multicastIP ?? "224.224.0.77"),
port: NWEndpoint.Port(rawValue: UInt16(self?.settings.multicastPort ?? 23019))
)
]) else {
print("Failed to Start Multicast Group")
return
}
let group = NWConnectionGroup(with: multicast, using: params)
// previous multicast stuff is here
} else {
print("en0 interface not found, waiting...")
}
}
monitor.start(queue: queue)
Neither seems to work.
I feel I must be missing something simple, because it should not be the case that simply enabling a VPN (or having another interface created by something else) breaks Multicast on en0/WiFi.
That said, I also don't want to limit the user to en0 as they may wish to use Ethernet interfaces, but for now it would be good to make it work to confirm this is the problem.
Topic:
App & System Services
SubTopic:
Networking
I have currently created an app which contains an upload button which when clicked upload health data using HealthKit to an AWS S3 bucket.
Now I want to implement an automatic file upload mechanism which would mean that the app is installed and opened just once - and then the upload must happen on a schedule (once daily) from the background without ever having to open the app again.
I've tried frameworks like NSURLSession and BackgroundTasks but nothing seems to work. Is this use case even possible to implement? Does iOS allow this?
The file is just a few KBs in size.
For reference, here is the Background Tasks code:
import UIKit
import BackgroundTasks
import HealthKit
class AppDelegate: NSObject, UIApplicationDelegate {
let backgroundTaskIdentifier = "com.yourapp.healthdata.upload"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Register the background task
BGTaskScheduler.shared.register(forTaskWithIdentifier: backgroundTaskIdentifier, using: nil) { task in
self.handleHealthDataUpload(task: task as! BGAppRefreshTask)
}
// Schedule the first upload task
scheduleDailyUpload()
return true
}
// Schedule the background task for daily execution
func scheduleDailyUpload() {
print("[AppDelegate] Scheduling daily background task.")
let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)
request.earliestBeginDate = Date(timeIntervalSinceNow: 24*60*60)
do {
try BGTaskScheduler.shared.submit(request)
print("[AppDelegate] Daily background task scheduled.")
} catch {
print("[AppDelegate] Could not schedule daily background task: \(error.localizedDescription)")
}
}
// Handle the background task when it's triggered by the system
func handleHealthDataUpload(task: BGAppRefreshTask) {
print("[AppDelegate] Background task triggered.")
// Call your upload function with completion handler
HealthStoreManager.shared.fetchAndUploadHealthData { success in
if success {
print("[AppDelegate] Upload completed successfully.")
task.setTaskCompleted(success: true)
// Schedule the next day's upload after a successful upload
self.scheduleDailyUpload()
} else {
print("[AppDelegate] Upload failed.")
task.setTaskCompleted(success: false)
}
}
// Handle task expiration (e.g., if upload takes too long)
task.expirationHandler = {
print("[AppDelegate] Background task expired.")
task.setTaskCompleted(success: false)
}
}
}
When handleNewUDPFlow in NETransparentProxyProvider is used to handle UDP data from port 53,
at the same time, run the script continuously to execute nslookup or dig, about tens of thousands of times later,
the nslookup shows the error "isc_socket_bind: address not available".
So I check the system port status, and find all of the ports from 49152 to 65535 are occupied. The number of net.inet.udp.pcbcount is also very high.
net.inet.udp.pcbcount: 91433
Then I made the following attempts:
handleNewUDPFlow function return false directly, the nslookup script runs with no problems.
I write a simple network extension that use handleNewUDPFlow to reply the mock data directly, and only hijack the UDP data from my test program (HelloWorld-5555).
My network exntension code:
override func handleNewUDPFlow(_ flow: NEAppProxyUDPFlow, initialRemoteEndpoint remoteEndpoint: NWEndpoint) -> Bool {
guard let tokenData = flow.metaData.sourceAppAuditToken, tokenData.count == MemoryLayout<audit_token_t>.size else { return false }
let audit_token = tokenData.withUnsafeBytes { buf in
buf.baseAddress?.assumingMemoryBound(to: audit_token_t.self).pointee
}
let pid = audit_token_to_pid(audit_token ?? audit_token_t())
if (!flow.metaData.sourceAppSigningIdentifier.starts(with: "HelloWorld-5555")) {
return false
}
Logger.statistics.log("handleNewUDPFlow \(remoteEndpoint.debugDescription, privacy: .public) \(flow.hash), pid:\(pid), \(flow.metaData.sourceAppSigningIdentifier, privacy: .public)")
flow.open(withLocalEndpoint: nil) { error in
if let error {
os_log("flow open error: %@", error.localizedDescription)
return
}
flow.readDatagrams { data_grams, remote_endpoints, read_err in
guard let read_data_grams = data_grams,
let read_endpoints = remote_endpoints,
read_err == nil else {
os_log("readDatagrams failed")
flow.closeReadWithError(nil)
flow.closeWriteWithError(nil)
return
}
let mockData = Data([0x01,0x02,0x03])
let datagrams = [ mockData ]
guard let remoteEnd = remoteEndpoint as? NWHostEndpoint else {
os_log("Not the NWHostENdpoint")
flow.closeReadWithError(nil)
flow.closeWriteWithError(nil)
return
}
let endpoints = [ NWHostEndpoint(hostname: remoteEnd.hostname, port: remoteEnd.port) ]
flow.writeDatagrams(datagrams, sentBy: endpoints) { error in
if let error {
os_log("writeDatagrams error: %@", error.localizedDescription)
}
os_log("writeDatagrams close")
flow.closeReadWithError(nil)
flow.closeWriteWithError(nil)
}
}
}
return true
}
My test program code:
void send_udp() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
int bytes_sent;
// create socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket create failed");
exit(EXIT_FAILURE);
}
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htonl(0);
// bind
if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) {
printf("IPV4 bind errno:%d\n", errno);
close(sockfd);
return;
}
// server addr
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// send & recv
strcpy(buffer, "Hello, UDP server!");
bytes_sent = sendto(sockfd, buffer, strlen(buffer), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr));
if (bytes_sent < 0) {
perror("sendto failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("sendto ok\n");
char recvbuf[128] = {0};
socklen_t len = sizeof(server_addr);
int sz = recvfrom(sockfd, recvbuf, sizeof(recvbuf), MSG_WAITALL, (struct sockaddr *) &server_addr, &len);
printf("recv sz: %d\n", sz);
close(sockfd);
return;
}
int main() {
send_udp();
return 0;
}
2.1 When I use bind in my program, after the program running tens of thousands of times, the ports are exhausted, and nslookup return the error "isc_socket_bind: address not available". The case looks like running the nslookup script, because the nslookup will call the bind.
2.2 When I remove the bind from my program, all the tests are go.
I have made the above experiments on different systems: 13.x, 14.x, 15.x, and read the kernel source code about bind and port assignment,
bsd/netinet/in_pcb.c
bsd/netinet/udp_usrreq.c
and find kernel will do different action for network extension by call necp_socket_should_use_flow_divert
I have checked my network extension process by lsof and netstat, its sockets or flows are all closed properly.
I don't know how I can avoid this problem to ensure my network extension to work long time properly. Apparently, the port exhaustion is related to the use of bind function and network extension. I doubt there is a port leak problem in system when use network extension.
Hope for your help.
My personal project is a bit further along however after not being able to get this to work in my app I fell back to a much simpler/proven implementation out there. There is this project on GitHub with a guide that implements a barebones app extension with packet tunneling. I figure this can give us common ground.
After changing the bundle and group identifiers to all end with -Caleb and or match up I tried running the app. The app extension does not work whatsoever and seemingly for reasons that are similar to my personal project.
If I pull up the console and filter for the subsystem (com.github.kean.vpn-client-caleb.vpn-tunnel) I see the following.
First you see installd installing it
0x16ba5f000 -[MIUninstaller _uninstallBundleWithIdentity:linkedToChildren:waitForDeletion:uninstallReason:temporaryReference:deleteDataContainers:wasLastReference:error:]: Destroying container com.github.kean.vpn-client-caleb.vpn-tunnel with persona 54D15361-A614-4E0D-931A-0953CDB50CE8 at /private/var/mobile/Containers/Data/PluginKitPlugin/2D0AE485-BB56-4E3E-B59E-48424CD4FD65
And then installd says this (No idea what it means)
0x16b9d3000 -[MIInstallationJournalEntry _refreshUUIDForContainer:withError:]: Data container for com.github.kean.vpn-client-caleb.vpn-tunnel is now at /private/var/mobile/Containers/Data/PluginKitPlugin/2D0AE485-BB56-4E3E-B59E-48424CD4FD65
Concerningly runningboardd seems to immediately try and stop it?
Executing termination request for: <RBSProcessPredicate <RBSProcessBundleIdentifiersPredicate| {(
"com.github.kean.vpn-client-caleb",
"com.github.kean.vpn-client-caleb.vpn-tunnel"
)}>>
[app<com.github.kean.vpn-client-caleb(54D15361-A614-4E0D-931A-0953CDB50CE8)>:1054] Terminating with context: <RBSTerminateContext| explanation:installcoordinationd app:[com.github.kean.vpn-client-caleb/54D15361-A614-4E0D-931A-0953CDB50CE8] uuid:963149FA-F712-460B-9B5C-5CE1C309B2FC isPlaceholder:Y reportType:None maxTerminationResistance:Absolute attrs:[
<RBSPreventLaunchLimitation| <RBSProcessPredicate <RBSProcessBundleIdentifiersPredicate| {(
"com.github.kean.vpn-client-caleb",
"com.github.kean.vpn-client-caleb.vpn-tunnel"
)}>> allow:(null)>
]>
Then runningboardd leaves a cryptic message
Acquiring assertion targeting system from originator [osservice<com.apple.installcoordinationd>:244] with description <RBSAssertionDescriptor| "installcoordinationd app:[com.github.kean.vpn-client-caleb/54D15361-A614-4E0D-931A-0953CDB50CE8] uuid:963149FA-F712-460B-9B5C-5CE1C309B2FC isPlaceholder:Y" ID:33-244-5222 target:system attributes:[
<RBSPreventLaunchLimitation| <RBSProcessPredicate <RBSProcessBundleIdentifiersPredicate| {(
"com.github.kean.vpn-client-caleb",
"com.github.kean.vpn-client-caleb.vpn-tunnel"
)}>> allow:(null)>
]>
And that seems to be all I have to go off of.... If I widen my search a bit I can see backboardd saying things like
Connection removed: IOHIDEventSystemConnection uuid:57E97E5D-8CDE-467B-81CA-36A93C7684AD pid:1054 process:vpn-client type:Passive entitlements:0x0 caller:BackBoardServices: <redacted> + 280 attributes:{
HighFrequency = 1;
bundleID = "com.github.kean.vpn-client-caleb";
pid = 1054;
} state:0x1 events:119 mask:0x800 dropped:0 dropStatus:0 droppedMask:0x0 lastDroppedTime:NONE
Or
Removing client connection <BKHIDClientConnection: 0xbf9828cd0; IOHIDEventSystemConnectionRef: 0xbf96d9600; vpid: 1054(vAF7); taskPort: 0x5D777; bundleID: com.github.kean.vpn-client-caleb> for client: IOHIDEventSystemConnection uuid:57E97E5D-8CDE-467B-81CA-36A93C7684AD pid:1054 process:vpn-client type:Passive entitlements:0x0 caller:BackBoardServices: <redacted> + 280 attributes:{
HighFrequency = 1;
bundleID = "com.github.kean.vpn-client-caleb";
pid = 1054;
} state:0x1 events:119 mask:0x800 dropped:0 dropStatus:0 droppedMask:0x0 lastDroppedTime:NONE source:HID
There's really nothing in the sysdiagnose either. No crash no nothing.
I am stumped. Any idea what might be going wrong for me here? Has something about the way app extensions or sandbox rules work changed in later OSes?
I’m working with the NEHotspotHelper API in my iOS app, and I noticed the following log message in Console:
"(BUNDLE ID ) is using NEHotspotHelper API and it's unresponsive to API's evaluate command. The API gives 45 seconds to 3rd party apps to respond, and then it launches WebSheet to allow user to interact with the portal."
I have two different apps that both register a NEHotspotHelper handler:
App A checks for .evaluate and calls createResponse(.unsupportedNetwork) if we don’t manage that particular network.
App B registers for hotspot events but does not handle .evaluate at all.
In App A, whenever I see that “unresponsive” or “45 seconds” log, the system eventually launches the standard captive portal WebSheet. In App B, I never see those logs.
I have a few questions:
Are these “unresponsive” logs indeed triggered by the .evaluate command specifically?
In other words, do we only see that 45-second timeout and the subsequent WebSheet message if our app is registered to handle Evaluate but doesn’t respond quickly (or responds with .unsupportedNetwork)?
Is it best practice (or required) to always respond to .evaluate—for example, sending .unsupportedNetwork if we don’t plan on managing the user’s login or captive portal? Does ignoring .evaluate lead to other unexpected behavior or logs?
Should we still explicitly respond to Evaluate with .unsupportedNetwork? Or is it okay to skip Evaluate handling entirely on every app or invocation?
I’d love to confirm whether .evaluate handling is the direct cause of these logs, and how best to avoid the “unresponsive”/“45 seconds” fallback if our app isn’t intended to manage the portal.
Thanks in advance for any insights!
Topic:
App & System Services
SubTopic:
Networking
PLATFORM AND VERSION: iOS
Development environment: Xcode 15.3, macOS 14.7.1 (23H222)
Run-time configuration: iOS 18.3.1
DESCRIPTION OF PROBLEM:
Our app uses NEHotspotConfigurationManager with joinOnce set to false to connect to an IoT device's Wi-Fi hotspot. Later, we programmatically disconnect from this hotspot. We are wondering if, after this programmatic disconnection, there is a possibility that the iPhone will automatically reconnect to the hotspot (even when our app is not running). Does it matter if the hotspot's SSID is hidden or not? This concern arises because the iPhone is already familiar with the hotspot's network configuration. Our testing indicates that this does not happen, but we want to be certain. This is a behavior we do NOT want to occur.
We set joinOnce to false because we experience connectivity issues with the IoT device when joinOnce is true (there are several discussions in forums regarding issues with setting it to true).
Thank you.
Thanks.
Hi,
DNS resolution using libresolv (res_nquery) fails in 15.4 when connected to VPN. The same is working fine for 15.3 and lower and this happens for all the domains. The method returns -1 and res->res_h_errno is set to 2.
In wireshark we can see that the DNS request is sent and server also returns the response successfully.
The same works fine if we use TCP instead of UDP by setting the following option
res->options |= RES_USEVC;
I've implemented a custom system extension VPN for macOS using Packet Tunnel Provider.
The VPN is configured with on-demand, and a rule to always connect whenever there's traffic:
onDemandRules = [NEOnDemandRuleConnect()]
As for the tunnel's settings (at the Packet Tunnel Provider), I've configured a split tunnel, so some routes are excluded from the tunnel.
Now I have the following scenario:
The VPN is connected
The Mac enters sleep
The sleep() function is called (at my Packet Tunnel Provider)
The Mac briefly awakes to check emails/push notifications/etc. This traffic is excluded from the tunnel.
What is the expected behavior here? Should the wake function be called because of the on-demand rule? Or should the VPN remain asleep because this traffic is excluded from the tunnel?
Context: We are using NWConnection for UDP and TCP Connections, and wanted to know the best way to keep the number of pending send completions in control to limit resource usage
Questions:
Is there a way to control the send rate, such that too many 'send pending completion' does not get queued. Say if I do a ‘extremely dense flurry of 10 million NWConnection.send’ will all go asynchronous without any complications? Or I would be informed once it reaches some threshold.
Or no? And is it the responsibility of the application using NWConnection.send to limit the outstanding completion , as if they were beyond a certain limit, it would have an impact on outstanding and subsequent requests?
If so – how would one know ‘what is supposed to be the limit’ at runtime? Is this a process level or system level limit.
Will errors like EAGAIN and ETIMEOUT ever will be reported. In the test I simulated, where the TCP Server was made to not do receive, causing the 'socket send buffer' to become full on the sender side. On the sender side my send stopped getting complete, and became pending. Millions of sends were pending for long duration, hence wanted to know if we will ever get EAGAIN or ETIMEOUT.
I am looking for inputs to better understand MacOS entitlements. I ask this in context of OpenJDK project, which builds and ships the JDK. The build process makes uses of make tool and thus doesn't involving building through the XCode product. The JDK itself is a Java language platform providing applications a set of standard APIs. The implementation of these standard APIs internally involves calling platform specific native library functions. In this discussion, I would like to focus on the networking functions that the implementation uses. Almost all of these networking functions and syscalls that the internal implementation uses are BSD socket related. Imagine calls to socket(), connect(), getsockopt(), setsockopt(), getaddrinfo(), sendto(), listen(), accept() and several such.
The JDK that's built through make is then packaged and made available for installation. The packaging itself varies, but for this discussion, I'll focus on the .tar.gz archived packaging. Within this archive there are several executables (for example: java, javac and others) and several libraries. My understanding, based on what I have read of MacOS entitlements is that, the entitlements are set on the executable and any libraries that would be loaded and used by that executable will be evaluated against the entitlements of the executable (please correct me if I misunderstand).
Reading through the list of entitlements noted here https://developer.apple.com/documentation/bundleresources/entitlements, the relevant entitlements that an executable (like "java") which internally invokes BSD socket related syscalls and library functions, appear to be:
com.apple.security.network.client - https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.network.client
com.apple.security.network.server - https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.network.server
com.apple.developer.networking.multicast - https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.networking.multicast
Is my understanding correct that these are the relevant ones for MacOS? Are there any more entitlements that are of interest? Would it then mean that the executables (java for example) would have to enroll for these entitlements to be allowed to invoke those functions at runtime?
Reading through https://developer.apple.com/documentation/bundleresources/entitlements, I believe that even when an executable is configured with these entitlements, when the application is running if that executable makes use of any operations for which it has an entitlement, the user is still prompted (through a UI notification) whether or not to allow the operation. Did I understand it right?
The part that isn't clear from that documentation is, if the executable hasn't been configured with a relevant entitlement, what happens when the executable invokes on such operation. Will the user see a UI notification asking permission to allow the operation (just like if an entitlement was configured)? Or does that operation just fail in some behind the scenes way?
Coming back to the networking specific entitlements, I found a couple of places in the MacOS documentation where it is claimed that the com.apple.developer.networking.multicast entitlement is only applicable on iOS. In fact, the entitlement definition page for it https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.networking.multicast says:
"Your app must have this entitlement to send or receive IP multicast or broadcast on iOS. It also allows your app to browse and advertise arbitrary Bonjour service types."
Yet, that same page, a few lines above, shows "macOS 10.0+". So, is com.apple.developer.networking.multicast entitlement necessary for an executable running on MacOS which deals with multicasting using BSD sockets?
As a more general comment about the documentation, I see that the main entitlements page here https://developer.apple.com/documentation/bundleresources/entitlements categorizes some of these entitlements under specific categories, for example, notice how some entitlements are categorized under "App Clips". I think it would be useful if there was a category for "BSD sockets" and under that it would list all relevant entitlements that are applicable, even if it means repeating the entitlement names across different categories. I think that will make it easier to identify the relevant entitlements.
Finally, more as a long term question, how does one watch or keep track of these required entitlements for these operations. What I mean is, is it expected that application developers keep visiting the macos documentation, like these pages, to know that a new entitlement is now required in a new macos (update) release? Or are there other ways to keep track of it? For example, if a newer macos requires a new entitlement, then when (an already built) executable is run on that version of macos, perhaps generate a notification or some kind of explicit error which makes it clear what entitlement is missing? I have read through https://developer.apple.com/documentation/bundleresources/diagnosing-issues-with-entitlements but that page focuses on identifying such issues when a executable is being built and doesn't explain the case where an executable has already been shipped with X entitlements and a new Y entitlement is now required to run on a newer version of macos.
Hello. I'm developing on a cross-platform app to help user connect enterprise network and found it difficult in macOS.
The issue is, I guided user to install profile, but the authentication won't start immediately even the cable is plugged in or the WLAN is connected. There is still some manual operation to be done:
Ethernet: Select the correct profile, and click the Connect button.
Wlan: Click the Connect button. (The profile contains SSID so need't select the correct profile)
Obviously, the operation is still not easy for users to understand and follow. So, is there any method to auto connect 802.1x network using the selected profile in terminal or by code? I mean, the manual operation is not necessary, maybe you can tell me a better solution.
BTW, I found it possible to connect WLAN and auto select the correct profile by using this command
networksetup -setairportnetwork en1 MY_SSID, but it could be very slow since the authentication seemed start 30 sec after connecting the SSID. So I believe it not the best solution.