Hi
I just encountered an reachability detection problem by calling SCNetworkReachabilityGetFlags function in iOS 16.
what did I do:
on device iPhone 12, iOS 16.1.1, turn on Airplane Mode, call SCNetworkReachabilityGetFlags, got flags = kSCNetworkReachabilityFlagsTransientConnection | kSCNetworkReachabilityFlagsReachable
on device iPhone 7, iOS 14.5.1, turn on Airplane Mode, call SCNetworkReachabilityGetFlags, got flags = 0
what I expect:
I'm expecting SCNetworkReachabilityGetFlags on my iOS 16.1 device behave same as my iOS 14.5 device, returning flags = 0. It's inappropriate returning kSCNetworkReachabilityFlagsReachable in this case.
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
Created
It is not possible to establish a point-to-point WiFi connection between iPhone models 15 and 16 (iOS 18) and the HiFlying HF-LPB100-1 module used by our IoT devices to control Yale locks: https://www.yaleconnecthub.com/en/compatible-products/hub
The message displayed on the iPhone WiFi network settings screen when selecting the HF-LPB100-1 module network states 'Unable to connect'.
It is important to highlight that all iPhone models and previous OS versions are compatible with this WiFi module (antenna + chipset).
We already made a post in the Feedback Assistence platform FB15809338 (Provisioning an IoT devise under iOS 18 - Wi-Fi incompatibility )
STEPS TO REPRODUCE
Plug in the Yale Connect Hub model YALE-4971 (with HF-LPB100-1 module) > The device's WiFi module will start reporting its network.
On an iPhone 15 or 16 -using iOS 18 - display the WiFi network configuration screen and select Yale´s device network (it is named Yale-xxxxxx).
Select the Yale network for the iPhone to connect point-to-point.
An error message will appear: Unable to connect.
I’ve encountered an issue with an app that includes a Local Push Connectivity extension. After a fresh install of the app, the Local Network Alert appears when calling NEAppPushManager.save(). The alert message is:
“This app would like to find and connect to devices on your local network. This app will be able to discover and connect to devices on the networks you use.”
Here is the relevant code:
` pushManager.providerConfiguration = NEAppPushManager.providerConfiguration(with: settings, system: system)
if settings.ssids.isEmpty {
fatalError("☠️ The PushManagerSettings.ssids should NEVER be empty!")
}
pushManager.matchSSIDs = !settings.ssids.isEmpty
? Array(settings.ssids)
: []
return pushManager.save()`
Questions:
1. Why does the Local Network Alert appear?
I suspect it is related to pushManager.matchSSIDs, which interacts with the local network to match specific SSIDs.
2. What happens if the user clicks “Don’t Allow”?
Based on my testing, everything seems to work fine even if the user denies the permission.
Would you happen to know why this is happening and if denying the alert could cause any issues down the line?
Topic:
App & System Services
SubTopic:
Networking
I am developing a USB networking accessory using the CDC ECM or NCM protocol and I would like to know what are the MacOS and iPadOS requirements to connect to such a device.
I have a prototype CDC ECM device developed that uses static IPv4 addressing which I can connect to an Arch Linux host and ping, but I am unable to have the same success from my Mac Studio M1 running Sequoia 15.1.1. The device shows up under 'Other Services' with 'Not connected' status, whether I leave it with the default settings or change it to 'Configure IPv4 -> Manually' and then set the appropriate IP address / Subnet mask / Router.
From a discussion on Github, it seems that the ECM device must support NetworkConnection notification in order to work with MacOS. Can you point me to where this is documented and whether there are other expectations/requirements around USB network adapters?
My end goal is to make an embedded device that communicates to MacOS and iPadOS devices/apps over USB CDC NCM with a simple UDP socket listener.
Thank you in advance for any help you can provide.
Hi,
I'm trying to set up automated backups on my machine using a combination of restic, a wrapper script, and a launchd agent, but I think I'm hitting a problem with the local network privacy dialogue.
Basically, the script sets up the environment variables for Restic, which then tries to backup to a local REST server. Problem is, when trying to do that, I get the following error:
Fatal: unable to open config file: Head "https://X:X@X.X.X.network:8000/X/X.X.X.network/config": dial tcp 192.168.50.229:8000: connect: no route to host
So it resolves DNS just fine, but can't connect to the local server. I tried a couple of things, tools such as ping work and can ping the local server, but nothing I do fixes the issue with restic itself. After reading about the network privacy feature, which I loved by the way, I believe it's the culprit here.
This is the .plist file I'm using, which lives in ~/Library/LaunchAgents/com.james.local-backup.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.james.local-backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/james/.local/bin/replicator</string>
<string>--backup</string>
<string>rest:https://X.X.X.network:8000/X/X.X.X.network</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/opt/coreutils/libexec/gnubin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
<key>XDG_CONFIG_HOME</key>
<string>/Users/james/.config</string>
</dict>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>13</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardErrorPath</key>
<string>/tmp/com.user.backup.err</string>
<key>StandardOutPath</key>
<string>/tmp/com.user.backup.out</string>
<key>ProcessType</key>
<string>Background</string>
</dict>
</plist>
The local network dialogue never shows up, so I can't give the wrapper script or restic access to the local network, which I assume is why it can't connect to the local server.
Any way I can solve this? I could build a proper Swift CLI that calls restic, but I assume I'd hit the same issue. Plus, it seems overkill for my needs.
Hi,
I've read a bunch of threads regarding the changes in Sonoma and later requiring Location permission for receiving SSIDs. However, as far as I can see, in Sequoia 15.1 SSIDs and BSSIDs are empty regardless.
In particular, this makes it not possible to use associate(withName:) and associate(withSSID:) because the network object returned by scanForNetwork(withSSID: "...") has its .ssid and .bssid set to nil.
Here is an example:
First we have a wrapper to call the code after the location permission is authorized:
import Foundation
import CoreLocation
class LocationDelegate: NSObject, CLLocationManagerDelegate {
var onAuthorized: (() -> Void)?
var onDenied: (() -> Void)?
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let authStatus = manager.authorizationStatus
print("Location authorization status changed: \(authStatusToString(authStatus))")
if authStatus == .authorizedAlways {
onAuthorized?()
} else if authStatus == .denied || authStatus == .restricted {
onDenied?()
}
}
}
let locationManager = CLLocationManager()
let locationDelegate = LocationDelegate()
func authorizeLocation(onAuthorized: @escaping () -> Void, onDenied: @escaping () -> Void) {
let authStatus = locationManager.authorizationStatus
print("Location authorization status: \(authStatusToString(authStatus))")
if authStatus == .notDetermined {
print("Waiting for location authorization...")
locationDelegate.onAuthorized = onAuthorized
locationDelegate.onDenied = onDenied
locationManager.delegate = locationDelegate
locationManager.requestAlwaysAuthorization()
} else if authStatus == .authorizedAlways {
onAuthorized()
} else if authStatus == .denied || authStatus == .restricted {
onDenied()
}
RunLoop.main.run()
}
func authStatusToString(_ status: CLAuthorizationStatus) -> String {
switch status {
case .notDetermined:
return "Not Determined"
case .restricted:
return "Restricted"
case .denied:
return "Denied"
case .authorizedAlways:
return "Always Authorized"
case .authorizedWhenInUse:
return "Authorized When In Use"
@unknown default:
return "Unknown"
}
}
Then, a demo program itself:
import Foundation
import CoreWLAN
import Network
let client = CWWiFiClient.shared()
guard let interface = client.interface() else {
print("No wifi interface")
exit(1)
}
authorizeLocation(
onAuthorized: {
do {
print("Scanning for wifi networks...")
let scanResults = try interface.scanForNetworks(withSSID: nil)
let networks = scanResults.compactMap { network -> [String: Any]? in
return [
"ssid": network.ssid ?? "unknown",
"bssid": network.bssid ?? "unknown"
]
}
let jsonData = try JSONSerialization.data(withJSONObject: networks, options: .prettyPrinted)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
exit(0)
} catch {
print("Error: \(error)")
exit(1)
}
},
onDenied: {
print("Location access denied")
exit(1)
}
)
When launched, the program asks for permission, and after that, is shown as enabled in Privacy & Security Settings panel.
Here is the output where it can be seen that the scan is performed after location access was authorized, and regardless of that, all ssids are empty:
Location authorization status: Not Determined
Waiting for location authorization...
Location authorization status changed: Always Authorized
Scanning for wifi networks...
[
{
"ssid" : "unknown",
"bssid" : "unknown"
},
{
"ssid" : "unknown",
"bssid" : "unknown"
},
.... further omitted
Calling scanForNetworks() with explicitly specified network name does this as well, returns a CWNetwork object with .ssid / .bssid = nil.
Our company has a VPN client that we develop and it works on 14.x and it was working on 15.x but ever since I have upgraded to 15.1.1, I do not see any traffic being sent to the TUN interface even though I have it configured as the default route. Can anyone provide guidance or insight into what might have changed around the Network Extensions that could have caused this?
Unfortunately I cannot tell if this was happening on 15.0.1. Some things I have tried, to no avail, is disable the firewall and uninstalling/installing of the VPN client. I have no other filters installed that could be interfering. When I try and ping an address I should be able to reach, I get "no route to host"
I have also used Wireshark and have observed zero traffic going to the TUN interface.
NOTE, networking works fine when the VPN client is not connected.
When I was attempting to establish a TCP connection using NWConnection on a physical iPhone, the connection consistently fails with the error:
connection did change state, new: waiting(POSIXErrorCode(rawValue: 50): Network is down)
connection did change state, new: preparing
connection did change state, new: waiting(POSIXErrorCode(rawValue: 50): Network is down)
However, when running the same code in the iOS Simulator, the connection succeeds without issues.
I have already granted the app permission to access the local network by selecting "Allow [App Name] to find devices on the local network" when prompted.
The issue persists even after restarting the app, device, and server.
Additionally, I have configured the Info.plist file with the following keys:
NSAllowsLocalNetworking
NSLocalNetworkUsageDescription
Here is my code:
func start() -> NWConnection {
let myHost: NWEndpoint.Host = "192.168.1.154" // My MacBook
let myPort: NWEndpoint.Port = 1234
let connection = NWConnection(to: .hostPort(host: myHost, port: myPort), using: .tcp)
connection.stateUpdateHandler = { newState in
print("connection did change state, new: \(newState)")
}
connection.start(queue: .main)
return connection
}
Development environment:
Xcode 15.3
MacOS 14.4.1
Device OS: iOS 18.1
I'm attempting to build an app the broadcasts on the local network and awaits responses to those broadcast requests. However, the app does not receive the responses. Essentially, the app broadcasts "DISCOVER:1000" to 10.11.21.255, and expects "ADDRESS:10.11.21.100", but never receives it. I built a test client in python, and it works as expected. Running tcpdump on the server shows the response being sent by the server. It just never reaches the ios app.
In case it matters, I have the multicast entitlement for the app and local network enabled in Info.plist.
import Foundation
import Network
class UDPClient: ObservableObject {
private var connection: NWConnection?
private let networkQueue = DispatchQueue(label: "com.example.udp")
@Published var isReady = false
private var isListening = false
func connect() {
let host = "10.11.21.255"
let port = UInt16(12345)
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(host), port: NWEndpoint.Port(integerLiteral: port))
connection = NWConnection(to: endpoint, using: .udp)
connection?.stateUpdateHandler = { [weak self] state in
switch state {
case .ready:
self?.networkQueue.async {
print("Connection ready")
self?.startReceiving()
DispatchQueue.main.async {
self?.isReady = true
}
}
case .failed(let error):
print("Connection failed: \(error)")
DispatchQueue.main.async {
self?.isReady = false
}
case .waiting(let error):
print("Connection waiting: \(error)")
DispatchQueue.main.async {
self?.isReady = false
}
default:
DispatchQueue.main.async {
self?.isReady = false
}
break
}
}
connection?.start(queue: networkQueue)
}
func send() {
let message = "DISCOVER:1000"
guard let data = message.data(using: .utf8) else {
print("Failed to convert message to data")
return
}
guard let connection = self.connection else {
return
}
networkQueue.async { [weak self] in
print("Attempting to send message...")
guard let self = self else { return }
if self.isReady {
// Ensure we're listening before sending
if !self.isListening {
self.startReceiving()
// Add a small delay to ensure the receiver is ready
self.networkQueue.asyncAfter(deadline: .now() + 0.1) {
self.performSend(data: data, connection: connection)
}
} else {
self.performSend(data: data, connection: connection)
}
} else {
print("Connection is not ready. Retrying in 100ms...")
self.networkQueue.asyncAfter(deadline: .now() + 0.1) {
self.send()
}
}
}
}
private func performSend(data: Data, connection: NWConnection) {
connection.send(content: data, completion: .contentProcessed { error in
if let error = error {
print("Failed to send: \(error)")
} else {
print("Send completed successfully")
}
})
}
private func startReceiving() {
print("Starting to receive messages...")
isListening = true
connection?.receiveMessage { [weak self] content, context, isComplete, error in
guard let self = self else { return }
if let error = error {
print("Receive error: \(error)")
return
}
if let data = content {
print("Received data: \(data)")
if let responseString = String(data: data, encoding: .utf8) {
print("Received response: \(responseString)")
} else {
print("Received data could not be converted to string.")
}
} else {
print("No data received.")
}
// Continue receiving
self.startReceiving()
}
}
func disconnect() {
networkQueue.async { [weak self] in
self?.connection?.cancel()
self?.isListening = false
DispatchQueue.main.async {
self?.isReady = false
}
print("Disconnected")
}
}
}
My main view:
import SwiftUI
struct ContentView: View {
@StateObject private var udpClient = UDPClient()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.onAppear() {
udpClient.connect()
udpClient.send()
}
}
}
#Preview {
ContentView()
}
I am trying to create an app that lets the user send Wake On LAN calls to computers in the local network. I created a small package that uses BSD sockets (https://github.com/pultar/WakeOnLAN/blob/main/Sources/CWakeOnLAN/wol.c) to send the magic packet. For now, I select "en0" manually as the interface.
The app works in the simulator but fails on a real device. I also noticed that I can test the package when I only use the terminal and Swift Package Manager but not from a CLI within XCode. In either case, I observe:
"No route to host"
Following previous post in the forum (see below), I figured I require the multicast entitlement, which I was granted and could add in the Xcode project settings and on Apple Developer together with my App Bundle ID.
However, even after activating the entitlement for my app, I observe the same error.
We have a device which is an appliance and we are developing a control interface app for macOS and iOS/iPadOS.
How can we set up our iOS application to grab information from a local network device while it is in the background in order to show notifications?
Communication between the Apple device and our device is via local networking and the device is designed to be used on networks without internet connections. On networks with internet connections we could forward events from the device, via a server and APNS push notifications, but that isn't valid here.
Events occur on our device and are forwarded to clients, who are subscribed to Server-Sent Events. On macOS this works well and the application can receive updates and show Notification Center notifications fine.
On iOS we are using a BGAppRefreshTaskRequest with time interval set to 1 minute, but it appears that we get scheduled only every few hours. This isn't very useful as notifications just arrive in batches rather than in a timely manner. All normal networking is closed when the app goes into the background, so we cannot keep the SSE request open.
Another idea which we haven't tried yet: Creating a new endpoint on the device which keeps the connection open until a notification arrives, then using background URLSession to poll on that endpoint. Would that work? It seems like a mis-use of the API perhaps?
Topic:
App & System Services
SubTopic:
Networking
Tags:
Notification Center
User Notifications
Background Tasks
Hi
I'm building a React Native app and need to implement the functionality to connect/disconnect to a VPN using WireGuard configuration files (.conf).
I'm using Swift for the native integration on iOS. Does anyone know of any libraries or resources that could help with this?
iOS devices are failing to launch WebSheet (i.e. captive portal mini browser) when auto-join is used to connect to Hotspot 2.0 SSID with a captive portal. Logs captured from the device & RADIUS show that the device associates to the SSID, but does not launch the WebSheet due to the error, "Unable to launch WebSheet because this network has become captive". Afterwards the device may send an EAPOL Logoff request to the Access Point & disconnect from the network.
If manually selecting the SSID from Settings > Wi-Fi, then the same device will log It's a manual join so no further checks required, remain associated to the SSID & launch the captive portal browser which is able to load the captive browser.
info 17:28:35.298531-0500 configd device setup is completed
info 17:28:35.298566-0500 configd Unable to launch WebSheet because this network has become captive, blacklisting network [HS2_Captive_Test]
info 17:28:35.298604-0500 configd Removing FF981347-FDFA-45FD-82D9-88BA0426C0A3
default 17:28:35.298641-0500 configd __BUILTIN__: PresentUI result Temporary Failure (6)
default 17:28:35.298677-0500 configd CNPluginHandler en0: Failure (__BUILTIN__)
default 17:28:35.298716-0500 configd Temporarily disabling (blacklisting) HS2_Captive_Test
Websheet should only be launched when the device is captive. Why wouldWebSheet fail to launch when the device is captive?
Dear Apple Support Team,
I hope this message finds you well.
I am writing to seek clarification on a specific aspect of Wi-Fi connectivity related to the iPhone 16 series running iOS 18.0. We have encountered an issue where the iPhone 16 series devices fail to connect to Wi-Fi networks, and this failure subsequently affects other devices running iOS 18.0.
To better understand the root cause of this issue, I would like to inquire about the differences in the "authentication and encryption" processes between the iPhone 16 series running iOS 18.0 and other devices running iOS 18.0. Specifically, are there any changes or updates in the Wi-Fi authentication and encryption mechanisms that are unique to the iPhone 16 series?
Understanding these differences will greatly assist us in diagnosing and resolving the connectivity issues we are experiencing.
Thank you for your assistance. I look forward to your prompt response.
Best regards,
WJohn
I encountered a problem during the development process. I want to enable the rvi0 capture interface using the rvictl command in the terminal while debugging over Wi-Fi in Xcode, but there is no response.
Then I tried a different method by connecting the iPhone to a hub. At this point, I can see the device normally in both Xcode and the console, but I still cannot use the rvictl command.
How can I capture packets while using Wi-Fi or a hub?
Hi Team,
Looking for an answer, if it's just us or a widespread issue.
Since Sept, our clients Apple devices can't load a Captive Portal on Apple devices. Client wants the CNA to pop up and I can't get it to happen!
Android and Windows devices all work correctly with their respective popups, but CNA will not work.
No changes done on our side and after multiple tshoots and getting vendors to take multiple PCAPs found, Apple devices are not initiating a HTTP GET request as per Meraki >> https://documentation.meraki.com/MR/MR_Splash_Page/Splash_Page_Traffic_Flow_and_Troubleshooting
The work around is to force a HTTP GET request by manually going into the browser and initiate a http site (we tried 1.1.1.1, also tried other public HTTP sites and it works) and that redirects to our Captive Portal page.
We are trying to connect to Webdav.
The file server is in the same network.
So when we try to connect, the local network permission pop-up is displayed.
If the input information is incorrect in the first login attempt when this permission pop-up is displayed,
After that, even after fixing the normal connection, we cannot connect or log in with the message "NSURLErrorDomain Code=-1009", "Internet connection is offline."
This symptom seems to persist even after rebooting or deleting and deleting the app in the actual distributed app.
If you re-debug while debugging Xcode, you can connect normally.
(If you do not re-debug, it fails even if you enter the connection information normally.)
And it affects local connection, so you cannot connect to any local network server such as SMB or FTP.
Also, you cannot browse the server list within the local network. (SMB)
Is there a way to initialize the local network status within the app to improve this phenomenon?
I tried turning Airplane mode ON/OFF, turning Wi-Fi ON/OFF, and turning local network permissions ON/OFF, but it did not work.
Also, this phenomenon seems to be a Sandbox for each app.
When connecting to the same local server from an app installed on the same iPhone/iPad device, the above phenomenon does not occur if the first connection is successful.
** Summary **
If you fail to connect to a server on your local network,
then you will continue to fail to connect to the local server.
This happens even when local network permissions are allowed.
The error message is NSURLErrorDomain Code=-1009
The current device is an iPhone device running iOS 18.1.1.
The content filtering functionality works perfectly when I install the app directly on my mobile device from Xcode. However, when the app is distributed via TestFlight, the app does not prompt users to save configurations, which causes the configuration-saving process to fail.
This app is meant for public use.
As per my understanding from TN3134, content filter apps can be shipped for devices running iOS 16 and later.
iOS app extension 9.0. supervised devices only
iOS app extension 15.0. apps using Screen Time API
iOS app extension 16.0. per app on managed devices
Topic:
App & System Services
SubTopic:
Networking
I am setting up a fake VPN with proxy settings using NEPacketTunnelProvider. When I check proxy check sites, I can see the proxy is detected.
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "10.0.0.1")
let proxySettings = NEProxySettings()
proxySettings.httpEnabled = true
proxySettings.httpsEnabled = true
proxySettings.httpServer = NEProxyServer(address: hostIP, port: portNumber)
proxySettings.httpsServer = NEProxyServer(address: hostIP2, port: portNumber2)
proxySettings.excludeSimpleHostnames = false
proxySettings.matchDomains = [""]
settings.proxySettings = proxySettings
How can I control whether other installed apps on the phone use or bypass this proxy? Can I do this with exceptionList? Since I am routing everything through a VPN, I assumed I could control this. The selection of which apps use the proxy should be up to the user.
Could you provide an explanation of how I can manage this? I am quite new to these types of tasks.
In our setup, our Transparent Proxy (call it TP1) funnels traffic to a helper process running on the same machine (call it Helper), which then actually sends out the traffic to the wider Internet. Now say there's another Transparent Proxy, TP2, on the same machine.
Assuming TP1 gets hold of the traffic first, the sequence would look like so:
Safari --> TP1 --> Helper --> TP2
We want to make it appear to TP2 that the incoming traffic is from Safari, rather than from the Helper process.
We are aware of the Network framework's setMetadata API, but this does not look appropriate for us to use here. The Helper process is pre-existing Golang code, which at best can interface with "pure" (ie BSD) sockets-based C code. In order to use the setMetadata API, looks like we will need to rewrite the entire networking logic to use nw_connection_t (or similar) API, which is too much work, so is infeasible for us to use.
Is there a way to make the setMetadata API work at a socket level? e.g., associate the metadata with a socket so that whatever data is sent out on the socket by the Helper will seem to TP2 to be coming from the desired source process.
Assuming there isn't such a way, please consider this an Enhancement Request to make it so!
Also, this reveals another complication: If and when this Enhancement is implemented, our own TP1 (which interepted the traffic in the first place) would end up thinking that the traffic is from Safari, so ends up re-intercepting it, causing a loop.
Safari --> TP1 --> Helper (invokes setMetadata) --> TP1 --> Helper ...
Which leads to the next Enhancement Request: Please extend the API to allow setting of the "last-hop" source process in addition to the original source application. If the last-hop source process info is set, our TP1 can query this property, see that it's coming from our own Helper process, and skip interception.
In summary, here are the Enhancement Requests:
Allow setMetadata API to work at a socket level
Allow setting of "last-hop" source process in the metadata, in addition to the original source application
More succinctly, please allow setting of metadata to cater to cases where the actual egress happens via a (different) helper process that uses pure C sockets based API.
I have also filed this as a Feedback with Apple, at FB16048393.