Hi, we have an iOS application that runs a NEAppProxyProvider network extension. The configuration for the extension is delivered by MDM and we've noticed that some MDMs are beginning to force end users to select certificate based authentication as the auth type for the per-app VPN payload. This itself causes no problems, but when a certificate to use for the authentication is also provided in the profile, our extension fails to start. Our application does not use the credentials from the profile, certificate based or otherwise, so we aren't doing anything unusual with them either.
We thought the problem might be caused because we lacked the com.apple.managed.vpn.shared entitlement that would be needed to access the certificate once it was on device (even though we never actually try to access it), but that did not fix the issue.
We have also confirmed that this happens regardless of MDM used to configure the profile.
Here are the relevant logs we are seeing that show the extension never starts:
neagent: NEAgentSession: failed to create the delegate
nesessionmanager:[313]: Tearing down XPC connection due to setup error: Error Domain=NEAgentErrorDomain Code=2 "(null)"
: Last disconnect error for changed from "none" to "The VPN app used by the VPN configuration is not installed"
STEPS TO REPRODUCE
Create an application that establishes a basic per-app VPN (just a loopback works) using the network extension
Using an MDM, create and deploy a per-app VPN profile with certificate based authentication (include a certificate as well) that uses the test application as a plugin.
Using the MDM, assign another application to the per-app VPN.
Try to connect to the internet using the assigned application, it should fail to connect because the system can't start the extension.
For reference it appears that this issue is similar to ours: https://forums.developer.apple.com/forums/thread/746879
I've tried all the suggestions on that page, including adding a 'first-light' log and that is never seen. There are also no additional clues when adding the VPN debug profile to the device.
Thanks!
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.
Post
Replies
Boosts
Views
Activity
Hello there,
I'm trying to consume graph.microsoft.com API by using URLSession. But I'm getting Error 400 from the server every time when I send a request with URLSession, but not if I use Postman for the same request. And when I examined the requests with Fiddler, I noticed that URLSession use HTTP/2, and Postman use HTTP/1.1. According to the Microsoft's documentation graph.microsoft.com supports only HTTP/1.1. As I understand URLSession decides to which version of HTTP to use during ALPN and will use HTTP/2 only if the server support it. My question is it possible the graph server to advertise itself as its support HTTP/2 and how to determinate this? Or maybe, which is more likely URLSession has bug that make it to do the wrong assumption about the HTTP/2. And most important there is there a mechanism to make URLSession to use a certain version of HTTP?
Thank you in advance,
Emil
iOS18 UDP fails to send data, iOS other systems fine
Device discovery by broadcasting over UDP
Failed to send data to the discovered device using UDP communication
This problem only occurs on iOS18, other iOS versions work fine
I read the official forum of Apple, it is recommended to use BSD socket to send data, and it cannot be sent on iOS18. I suspect that the device privacy permission is found locally, which is invalid on iOS18
On Sequoia it became impossible to properly debug programs using third party mDNS, multicast or broadcast, thanks to a bug? in I guess the new local network privacy feature, every send call returns no route to host.
If I run the CI job, which properly packages, signs, notarizes said program, the resulting .app works fine and also requests permission to access the local network - which is impossible through lldb as it doesn't have an Info.plist, just the ***** binary itself. However this may not be the issue, see the repro method below.
A fast and easy method to reproduce is using an example from this repo: https://github.com/keepsimple1/mdns-sd/
Running the query example in a good old shell without lldb (cargo run --example query _smb._tcp) starts outputting results.
Then running the same binary through lldb (lldb -o run target/debug/examples/query _smb._tcp) would result in no route to host errors. I can't provide an output anymore as I was forced to downgrade. It works fine again on 14.6.1. I'm a bit reluctant to even try 14.7.
Also reported in feedback assistant: FB15185667
Hi there, I have some thread related questions regards to network framework completion callbacks. In short, how should I process cross thread data in the completion callbacks?
Here are more details. I have a background serial dispatch queue (call it dispatch queue A) to sequentially process the nw_connection and any network io events. Meanwhile, user inputs are handled by serial dispatch queue ( dispatch queue B). How should I handle the cross thread user data in this case?
(I write some simplified sample code below)
struct {
int client_status;
char* message_to_sent;
}user_data;
nw_connection_t nw_connection;
dispatch_queue_t dispatch_queue_A
static void send_message(){
dispatch_data_t data = dispatch_data_create(message, len(message), dispath_event_loop->dispatch_queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
nw_connection_send(
nw_connection, data, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, false, ^(nw_error_t error) {
user_data.client_status = SENT;
mem_release(user_data.message_to_sent); });
});
}
static void setup_connection(){
dispatch_queue_A=
dispatch_queue_create("unique_id_a", DISPATCH_QUEUE_SERIAL);
nw_connection = nw_connection_create(endpoint, params);
nw_connection_set_state_changed_handler(){
if (state == nw_connection_state_ready) {
user_data.client_status = CONNECTED
}
// ... other operations ...
}
nw_connection_start(nw_connection);
nw_retain(nw_connection);
}
static void user_main(){
setup_connection()
user_data.client_status = INIT;
dispatch_queue_t dispatch_queue_B = dispatch_queue_create("unique_id_b", DISPATCH_QUEUE_SERIAL);
// write socket
dispatch_async(dispatch_queue_B, ^(){
if (user_data.client_status != CONNECTED ) return;
user_data.message_to_sent = malloc(XX,***)
// I would like to have all io events processed on dispatch queue A so that the io events would not interacted with the user events
dispatch_async_f(dispatch_queue_A, send_message);
// Disconnect block
dispatch_async(dispatch_queue_B, ^(){
dispatch_async_f(dispatch_queue_A, ^(){
nw_connection_cancel(nw_connection)
});
user_data.client_status = DISCONNECTING;
});
// clean up connection and so on...
}
To be more specific, my questions would be:
As I was using serial dispatch queue, I didn't protect the user_data here. However, which thread would the send_completion_handler get called? Would it be a data race condition where the Disconnect block and send_completion_handler both access user_data?
If I protect the user_data with lock, it might block the thread. How does the dispatch queue make sure it would NOT put a related execution block onto the "blocked thread"?
Hi all,
I am overhauling code of an iPadOS app that discovers devices on a network using a custom UDP broadcast based discovery protocol.
This is how the discovery mechanism should work: The iPad sends an IPv4 broadcast message to the network's broadcast address using a fixed destination port, but a random source port (determined at bind time). The device responds with a unicast message to the source IP address and port of the discovery message.
Until now the code is based on BSD sockets using GCDAsyncUdpSocket and has been working well for around ten years with a single socket that was used to both send and receive the discovery messages and replies.
We would like to make the move to the Network Framework now and I tried to recreate this discovery mechanism with the Network Framework in Objective-C.
I am able to create an nw_connection_t with the broadcast address as hostname and the specific destination port as port. I am able to send discovery messages to the device and the device sends a reply (verified with Wireshark). But calling nw_connection_receive_message(...) never fires. Also in Wireshark the iPad replies with Destination unreachable (Port unreachable).
When I create the connection with the unicast address of the device, the reply is received.
It seems to me, that the connection doesn't accept replies from addresses / ports that don't match, what was set when the connection was created. Is there a way to also accept messages from other sources? E.g. there is nw_multicast_group_descriptor_set_disable_unicast_traffic when doing multicast. This seems to solve this problems when doing mutlicast.
This is a code excerpt of what I tried:
// Create default UDP parameters without DTLS
nw_parameters_t params = nw_parameters_create_secure_udp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION);
// Enable P2P (should enable broadcast and multicast)
nw_parameters_set_include_peer_to_peer(params, true);
// Require the active interface
// The active interface comes from a path monitor callback
nw_parameters_require_interface(params, self.networkUtils.activeInterface.interface);
// Setup the remote endpoint with the "ping" (discovery) broadcast IP address and port
const char *endpointAddress = [pingAddress.ipAddress cStringUsingEncoding:NSUTF8StringEncoding];
NSString *portString = @(pingAddress.port).stringValue;
const char *endpointPort = [portString cStringUsingEncoding:NSUTF8StringEncoding];
nw_endpoint_t broadcastEndpoint = nw_endpoint_create_host(endpointAddress, endpointPort);
nw_connection_t tmpConnection = nw_connection_create(broadcastEndpoint, params);
__weak __typeof(self) weakSelf = self;
nw_connection_set_state_changed_handler(tmpConnection, ^(nw_connection_state_t state, nw_error_t _Nullable error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
MSLogVerbose("State changed: %d; error: %@", state, error);
strongSelf.connectionState = state;
if (state == nw_connection_state_ready) {
[strongSelf receiveMessageForConnection:tmpConnection];
}
});
nw_connection_set_queue(tmpConnection, AGGalileoBrowser.browserQueue);
nw_connection_start(tmpConnection);
Thanks for your help!
Arno
I am getting an error when trying to call an api being hosted on my local development machine from an XCode project running on my iPhone:
Task <xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>.<2> finished with error [-1202] Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “10.0.0.5” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
"<cert(0x106046600) s: XXXXXXXXXX-Dev i: XXXXXXXXXX Dev CA>",
"<cert(0x106047000) s: XXXXXXXXXX Dev CA i: XXXXXXXXXX Dev CA>"
), NSErrorClientCertificateStateKey=0
I have followed the instructions for creating a certificate authority and certificate and installing it on my phone as outlined in Creating Certificates for TLS Testing and Installing a CA’s Root Certificate on Your Test Device. I have read posts in this forum without resolution and seen them on stack overflow like this one and this one which have not been answered or the solutions do not work in more current environments (example response: "This doesn't work in XCode 14.2").
I did have this running in earlier versions and with Android Studio. It would be ideal to have the current state answer to how to develop api's on your local machine and call them from your iPhone or simulator.
please help, upgrade to Sequoia 15, system default open it, how to close?
how to turn off private WiFi address using code, swift or objective-c language
Code I have used for years on Macs now crashes after updating OS:
SSL_CTX *sslctx = SSL_CTX_new(SSLv23_client_method());
Reading the posts about TLS changes, I change it to this:
SSL_CTX *sslctx = SSL_CTX_new(TLS_client_method());
In fact any method I give results in crash.. Is this a known issue?
Is there something I now need to call before calling SSL_CTX_new()?
Hi everybody!
With latest updates on Ventura around 13.9.X, Sonoma 14.5 and upper, and most probably Sequoia, we notice a change on how to retrieve BSSID. We know Airport is discontinue, but also other commands are impacted by new security policies.
Now, to make any command work in the proper way we need to ask for Location Permission. But here is where we are finding some issues to make it compatible with the new requirements.
We have a web desktop app (Built with Electronjs) that use an mach-o executable (built on C++). This executable runs IOREG to retrieve the BSSID. One of the tries we did is to request the Location Permission on the parent/GUI app, but by doing this, IOREG was not able to retrieve the BSSID.
Then, we try to look for a way to make a little test only with our executable. But in the attempt to, we do not found a way to trigger the location permission request, either manually or by a command.
Is there a way to prompt the user from a terminal executable or the right way is to prompt from the GUI?
Do we need to stop using Mach-o executable in c++ and move to a native mach-o executable in swift to be able to prompt from it (This executable runs in the machine frequently, several times per minute)?
We are open to change the command if need it.
Requirements: Suppose a carrier provides multiple networks and an iPhone can switch to the best network based on signal strength.
Questions: In iOS, suppose we need to switch IMSI based on the best network available then is it possible to achieve that.
We do have apple carrier entitlements as well.
Can we achieve with Applet? if Yes so please describe it like how can we create applet and how applet works to switch IMSI profile.
Hi all,
I would like to know if it is possible to activate a content filter through the command line interface (CLI). Based on my research, it seems that Apple does not allow this for security design reasons. If it’s indeed not permitted, is there a way to use a GUI-based app as a workaround, where the GUI would only serve the purpose of activating the content filter? After the filter is activated, I’d like to hide the GUI app and run the content filter in the background. Is this approach feasible, and what would be the best way to achieve it?
Thanks in advance for your help!
Starting from macOS 15 (macOS Sequoia), a new pop-up is triggered: “Local Network Privacy.” We have some questions regarding this new pop-up on MacOS:
Running the following simple code:
cups_dest_t *dests;
int num_dests = cupsGetDests(&dests);
triggers the “Local Network Privacy” pop-up.
Question: Is this intended behavior? Even if the user presses the “Deny” button, printers can still be iterated, and it is possible to set options for the printer. Is this intended behavior?
If so, which actions related to the CUPS library will be denied when the user presses the “Deny” button?
Question: Should this pop-up appear for daemons/launchd processes?
We found similar questions on some forums, but the answers are unclear. It seems that the pop-up should not appear for launch daemons. We tested the mentioned code with CUPS, and the pop-up was triggered.
Is this a bug? If so, will it be resolved before the new macOS version is released?
Question: There is somewhere documented all the scenarios in which this pop-up may appear is challenging?
Regarding automatically allowing or disallowing the pop-up:
We found the following response:
“There is no way to automatically allow or disallow the local network privacy prompt. If it shows up in your app, you will need to analyze your code to better understand how the prompt is being triggered. If the prompt is triggered by a library you do not control, you will need to either remove the library or inquire further with the library vendor.”
Question: How can we ensure that a launchd daemon will work as expected if the user presses the “Deny” button?
Is there any way to detect if the user pressed “Deny”?
Hello,
I have a Qt c++ executable that accesses a server backend on my local network.
After building the executable, I can run it either from within the Qt Creator IDE, OR I can run it from the command line.
When I launch from within the Qt Creator IDE, the same executable cannot talk to the backend server on my local network. However, the same executable when launched from the command line works fine.
This started only with macOS Sequoia and the new "Local Network" permission. How can I get my IDE launched executable to work? Otherwise I cannot continue my app development.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
diskCapacity:100 * 1024 * 1024
diskPath:@"myCache"];
if (!configuration) {
NSLog(@"Failed to create session configuration.");
return;
}
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
if (!session) {
NSLog(@"Failed to create session.");
return;
}
NSURL *url = [NSURL URLWithString:@"https://example.com"];
if (!url) {
NSLog(@"Invalid URL.");
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:url];
if (!request) {
NSLog(@"Failed to create request.");
return;
}
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"Error: %@", error.localizedDescription);
} else {
NSLog(@"Data received: %@", data);
}
}];
if (!dataTask) {
NSLog(@"Failed to create data task.");
return;
}
dataTask.priority = NSURLSessionTaskPriorityDefault;
[dataTask resume];
error message
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSFileManager createDirectoryAtURL:withIntermediateDirectories:attributes:error:]: URL is nil'
*** First throw call stack:
(0x1848bd08c 0x181bbf2e4 0x183585f48 0x185d2f2bc 0x185d2ec7c 0x10709271c 0x1070a3f04 0x185d2ea88 0x185d2db20 0x185d2d5f4 0x185d2d07c 0x185d274b0 0x185dd82c4 0x185dd8214 0x185dd730c 0x107090a30 0x10709271c 0x10709a5e8 0x10709b394 0x10709cb20 0x1070a85f0 0x1070a7c00 0x20bc27c7c 0x20bc24488)
libc++abi: terminating due to uncaught exception of type NSException
Hi!
I am new to Apple app development so please bear with me.
I am trying to design an app that can mimic some of the functionality of iptables routing. The crux of it is I would like to redirect local traffic bound for a specific port to a different port and then redirect any outgoing traffic on that port back to the original port:
outgoing packet bound for IP:1234 -> 127.0.0.1:2345
outgoing packet bound for IP:2345 -> IP:1234
I tried to implement this behavior with a packet tunnel but have not made any substantial progress. Is this the right approach?
Here is my implementation:
private func handleConnection(_ connection: NWConnection) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] data, context, isComplete, error in
if let data = data, !data.isEmpty {
self?.processData(data, from: connection)
}
if let error = error {
print("Connection error: \(error)")
}
if isComplete {
connection.cancel()
} else {
self?.handleConnection(connection) // Continue to receive data
}
}
connection.start(queue: .main)
}
private func processData(_ data: Data, from connection: NWConnection) {
switch connection.endpoint {
case .hostPort(let host, let port):
let portNumber = port.rawValue
let hostDescription = host.debugDescription
print("Received data from host: \(hostDescription) on port: \(portNumber)")
if portNumber == 1234 {
// Rule 1: Redirect traffic from port 1234 to 127.0.0.1:2345
redirectTraffic(data, to: "127.0.0.1", port: 2345)
print("Redirecting traffic from 1234 to 2345")
} else if portNumber == 2345 {
// Rule 2: Redirect traffic from port 2345 to the original IP address but port 1234
redirectTraffic(data, to: hostDescription, port: 1234)
print("Redirecting traffic from 2345 back to 1234")
}
case .service(name: _, type: _, domain: _, interface: _):
print("Received bonjour service")
case .unix(path: _):
print("Received unix domain path")
case .url(_):
print("Received url")
case .opaque(_):
print("Opaque?")
@unknown default:
fatalError("Unknown endpoint type")
}
}
How can I resolve the error(Code=65 "No route to host).
Xcode 16(SDK ios18): We invoke GCDAsyncUdpSocket to send UDP data to the broadcast address,then get Error Domain=NSPOSIXErrorDomain Code=65 "No route to host"
Xcode 16.1 beta 2(SDK ios18.1): We invoke GCDAsyncUdpSocket to send UDP data to the broadcast address,then it work fine.
Xcode 15.4(SDK ios17.5): We invoke GCDAsyncUdpSocket to send UDP data to the broadcast address,then it work fine.
Notes:
Privacy - Local Network Usage Description and the multicast entitlement has been added.
Bonjour services has been added _http._tcp、_http._udp
Code:
GCDAsyncUdpSocket *gcdUdpSearchSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![gcdUdpSearchSocket enableBroadcast:YES error:&error]){
NSLog(@"gcdUdpSearchSocket enableBroadcast Error binding: %@", error);
return;
}
if (![gcdUdpSearchSocket bindToPort:UDP_PORT error:&error])
{
NSLog(@"GCDUdp Error binding: %@", error);
return;
}
if (![gcdUdpSearchSocket beginReceiving:&error])
{
NSLog(@"GCDUdp Error receiving: %@", error);
return;
}
In macOS Sequoia, there are up to 3 locations where an end user can enable or disable a Network Extension.
In order of appearance in the System Settings.app application:
Network > Filters
General > Login Items & Extensions (1)
General > Login Items & Extensions > Network Extensions
a) it's quite difficult for an end user (and even a developer) to understand why there are 3 different locations and whether we are dealing with the same unique item or not. e.g. why would an end user have a clue about the difference between a Network Extension and a (Packet | Content) Filter?
b) it's not possible for an end user to figure out what the consequences of disabling an item in one of these 3 locations is going to be, because, in each case, the consequences appear to be different, undocumented or not detailed clearly in the UI. (2)
[Q] Is there a clear, complete and detailed documentation for Network Extensions UX controls in macOS Sequoia? For either end users or developers?
I could't find one when searching inside www.apple.com or developer.apple.com.
(1) not sure why a Network Extension also appears here as it's not a launchd daemon controlled by a 3rd party launchd plist. And not sure to understand why it's there since there's now the Network Extensions panel.
(2) it does not help that the output of the systemextensionsctl command line tool, in most cases, reports that the extension is still activated and enabled.
I tried building some app logic around NetworkMonitor.isConnected in my watch app (I want to trigger an update when the user opens the app and isConnected == true, otherwise observe NetworkMonitor.isConnected until it changes to true), and I found out that on a real device, NetworkMonitor.isConnected is always false.
This does not seem to be documented anywhere. Am I right in assuming NetworkMonitor is not to be trusted on the watch? watchOS version is 18.
I found an old post where eskimo argues that NWPathMonitor is not useful on the watch (which is also not documented), is it the same for NetworkMonitor?
https://forums.developer.apple.com/forums/thread/127080
My App is a rather small menu-bar status-item app with 2 informational windows. It does NOT make use of ANY of the APIs mentioned here: https://developer.apple.com/forums/thread/663874 that are bound to need "Local Network" hence trigger TCC dialog.
Yet - on first run of the app, the dialog pops.
App is Obj-C, and the only APIs used are Notification-Center (for scheduling local notifications to the user), XPC connections and calls to other (our) apps for gathering that information, plus normal AppKit windowing (Controls, Text-fields, etc.) nothing else.
Obviously SOMETHING I do causes the thing - and I know for sure this app DOES NOT NEED access to the local network - only I do not know how to identify the specific API I need to avoid using (or change the way I'm using)
Are there any specific system logs to watch for?
Is there any official set of APIs that will trigger the dialog?
Provided that I cannot avoid this - could this permission be granted via MDM profile payload? Our product comes with