Hi,
We have an issue (https://github.com/actions/runner-images/issues/10924) raised by a user requesting to add 'local network access' permission for macOS 15 and macOS 15-arm64 image runners. Apple introduced a new LNP policy with macOS Sequoia that is not controlled by TCC or MDM. Could you please guide us on how to add 'local network access' permission for macOS 15 and macOS 15-arm64 image runners?
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
When I used the iPhone 11 to scan the wifi connection, the system reported an error,
‘’’
let config = NEHotspotConfiguration(ssid: name, passphrase: passwd, isWEP: false)
let manager = NEHotspotConfigurationManager()
manager.apply(config) { error in
}
’’’
NEHotspotConfigurationErrorDomain Code=8 “internal error.” , the only thins that fixes this issue it restarting the iPhone.
What is the reason for this and how to solve it?
Reference link:
https://developer.apple.com/forums/thread/111638
https://cloud.tencent.com/developer/ask/sof/114654981
Hello. I would like to develop an application that sends SSH commands via my phone to the server. I know that applications of this type exist, but they are not suitable for my use as a blind person who uses a screen reader. I hope you can help me find libraries that will assist me in development, or ready-made, open-source projects that I can develop and modify if necessary. Thank you in advance.
Topic:
App & System Services
SubTopic:
Networking
I would like to develop a macOS app that would automatically switch Network Locations based on certain criteria. I want to publish this on the Mac App Store, but I'm unsure if this functionality is permitted.
I've searched through the App Store Review Guidelines and documentation on NetworkExtension and SystemConfiguration frameworks, but I haven't found clear information on whether:
Programmatically changing Network Locations is allowed in sandboxed App Store apps
What specific entitlements would be required
If there are any API-approved ways to do this without shell commands
I'd like to avoid investing significant development time if this type of functionality would ultimately be rejected. As a relatively new Apple platform developer, any guidance on:
The appropriate frameworks/APIs to use
Required entitlements
Whether this functionality is even permitted for App Store distribution
would be incredibly helpful.
Thank you in advance for any insights!
Topic:
App & System Services
SubTopic:
Networking
Tags:
Network Extension
System Configuration
CFNetwork
When setting up a packet tunnel with a profile that has includeAllNetworks set to true, we seemingly cannot send any traffic inside the tunnel using any kind of an API. We've tried using BSD sockets, as we ping a host only reachable within the tunnel to establish whether we have connectivity - this does not work. When using NWConnection from the Network framework and specifying the required interface via virtualInterface from the packet tunnel, the connection state never reaches ready. Our interim solution is to, as ridiculous as it sounds, include a whole userspace networking stack so we can produce valid TCP packets just to send into our own tunnel. We require a TCP connection within our own tunnel to do some configuration during tunnel setup. Is there no better solution?
Topic:
App & System Services
SubTopic:
Networking
Tags:
Network Extension
Network
System Configuration
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.
Dear Apple Team,
I am facing an issue with UDP networking in my watchOS app for duplex audio streaming using NWConnection. I have already added the necessary capabilities, including background mode for audio, to ensure smooth operation.
Issue Details:
The UDP connection works fine on the simulator since it uses macOS networking and allows low-level access.
However, on a real Apple Watch (running watchOS 10), the connection remains in a "waiting" state and fails with Error 50.
I am aware of Technical Note TN3135 regarding low-level networking on watchOS, but even after following these guidelines, the issue persists.
Questions:
Does watchOS impose additional restrictions on UDP networking compared to iOS/macOS?
Are there any specific entitlements or configurations required to allow UDP connections on a real Apple Watch?
Is there a workaround or debugging method to get more insights into why the connection fails?
I would appreciate any guidance or recommendations on resolving this issue.
I'm developing a per-app VPN iOS app with Wireguard. For that, I created a configuration file with payload type "com.apple.vpn.managed.applayer". Using the MDM server I installed some apps which need to use the VPN connection. But when I open these apps, I could see the VPN getting enabled in the device. The VPN icon appears on the notification bar but no internet connection. The VPN and internet is working correctly if I change the payload type to "com.apple.vpn.managed" in configuration file.
We have a NEFilterDataProvider extension that intercepts all TCP and UDP IPv4/6 traffic. At times just after wakeup from sleep, it causes internet access issues, such as showing "This site can't be reached" when opening websites.
The traffic is not being dropped by the extension.
According to the logs, the connection is being closed after approximately 4 minutes.
During the issue, the flow logs are as follows:
Flow 515129771 is connecting
New flow: NEFlow type = stream, app = com.google.Chrome.helper...
Detaching, ref count = 2 (logged after ~4 minutes)
Sending close, how = 2
Removing from group 2, ref count = 2
Destroying, app tx 0, tunnel tx 0, tunnel rx 0
Closing reads, not closed by plugin
Closing writes, not sending close
Any suggestions on the possible cause and how to further debug it?
Please consider this trivial C code which deals with BSD sockets. This will illustrate an issue with sendto() which seems to be impacted by the recent "Local Network" restrictions on 15.3.1 macos.
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "sys/socket.h"
#include <string.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <net/if.h>
// prints out the sockaddr_in6
void print_addr(const char *msg_prefix, struct sockaddr_in6 sa6) {
char addr_text[INET6_ADDRSTRLEN] = {0};
printf("%s%s:%d, addr family=%u\n",
msg_prefix,
inet_ntop(AF_INET6, &sa6.sin6_addr, (char *) &addr_text, INET6_ADDRSTRLEN),
sa6.sin6_port,
sa6.sin6_family);
}
// creates a datagram socket
int create_dgram_socket() {
const int fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0) {
perror("Socket creation failed");
return -1;
}
return fd;
}
// returns a string representing the current local time
char *current_time() {
time_t seconds_since_epoch;
time(&seconds_since_epoch);
char *res = ctime(&seconds_since_epoch);
const size_t len = strlen(res);
// strip off the newline character that's at the end of the ctime() output
res[len - 1] = '\0';
return res;
}
// Creates a datagram socket and then sends a messages (through sendto()) to a valid
// multicast address. This it does two times, to the exact same destination address from
// the exact same socket.
//
// Between the first and the second attempt to sendto(), there is
// a sleep of 1 second.
//
// The first time, the sendto() succeeds and claims to have sent the expected number of bytes.
// However system logs (generated through "log collect") seem to indicate that the message isn't
// actually sent (there's a "cfil_service_inject_queue:4466 CFIL: sosend() failed 65" in the logs).
//
// The second time the sendto() returns a EHOSTUNREACH ("No route to host") error.
//
// If the sleep between these two sendto() attempts is removed then both the attempts "succeed".
// However, the system logs still suggest that the message isn't actually sent.
int main() {
printf("current process id:%ld parent process id: %ld\n", (long) getpid(), (long) getppid());
// valid multicast address as specified in
// https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
const char *ip6_addr_str = "ff01::1";
struct in6_addr ip6_addr;
int rv = inet_pton(AF_INET6, ip6_addr_str, &ip6_addr);
if (rv != 1) {
fprintf(stderr, "failed to parse ipv6 addr %s\n", ip6_addr_str);
exit(EXIT_FAILURE);
}
// create a AF_INET6 SOCK_DGRAM socket
const int sock_fd = create_dgram_socket();
if (sock_fd < 0) {
exit(EXIT_FAILURE);
}
printf("created a socket, descriptor=%d\n", sock_fd);
const int dest_port = 12345; // arbitrary port
struct sockaddr_in6 dest_sock_addr;
memset((char *) &dest_sock_addr, 0, sizeof(struct sockaddr_in6));
dest_sock_addr.sin6_addr = ip6_addr; // the target multicast address
dest_sock_addr.sin6_port = htons(dest_port);
dest_sock_addr.sin6_family = AF_INET6;
print_addr("test will attempt to sendto() to destination host:port -> ", dest_sock_addr);
const char *msg = "hello";
const size_t msg_len = strlen(msg) + 1;
for (int i = 1; i <= 2; i++) {
if (i != 1) {
// if not the first attempt, then sleep a while before attempting to sendto() again
int num_sleep_seconds = 1;
printf("sleeping for %d second(s) before calling sendto()\n", num_sleep_seconds);
sleep(num_sleep_seconds);
}
printf("%s attempt %d to sendto() %lu bytes\n", current_time(), i, msg_len);
const size_t num_sent = sendto(sock_fd, msg, msg_len, 0, (struct sockaddr *) &dest_sock_addr,
sizeof(dest_sock_addr));
if (num_sent == -1) {
fprintf(stderr, "%s ", current_time());
perror("sendto() failed");
close(sock_fd);
exit(EXIT_FAILURE);
}
printf("%s attempt %d of sendto() succeeded, sent %lu bytes\n", current_time(), i, num_sent);
}
return 0;
}
What this program does is, it uses the sendto() system call to send a message over a datagram socket to a (valid) multicast address. It does this twice, from the same socket to the same target address. There is a sleep() of 1 second between these two sendto() attempts.
Copy that code into noroutetohost.c and compile:
clang noroutetohost.c
Then run:
./a.out
This generates the following output:
current process id:58597 parent process id: 21614
created a socket, descriptor=3
test will attempt to sendto() to destination host:port ->ff01::1:14640, addr family=30
Fri Mar 14 20:34:09 2025 attempt 1 to sendto() 6 bytes
Fri Mar 14 20:34:09 2025 attempt 1 of sendto() succeeded, sent 6 bytes
sleeping for 1 second(s) before calling sendto()
Fri Mar 14 20:34:10 2025 attempt 2 to sendto() 6 bytes
Fri Mar 14 20:34:10 2025 sendto() failed: No route to host
Notice how the first call to sendto() "succeeds", even the return value (that represents the number of bytes sent) matches the number of bytes that were supposed to be sent. Then notice how the second attempt fails with a EHOSTUNREACH ("No route to host") error. Looking through the system logs, it appears that the first attempt itself has failed:
2025-03-14 20:34:09.474797 default kernel cfil_hash_entry_log:6082 <CFIL: Error: sosend_reinject() failed>: [58597 a.out] <UDP(17) out so 891be95f3a70c605 22558774573152560 22558774573152560 age 0> lport 0 fport 12345 laddr :: faddr ff01::1 hash 1003930
2025-03-14 20:34:09.474806 default kernel cfil_service_inject_queue:4466 CFIL: sosend() failed 65
(notice the time on that log messages, they match the first attempt from the program's output log)
So even though the first attempt failed, it never got reported back to the application. Then after sleeping for (an arbitrary amount of) 1 second, the second call fails with the EHOSTUNREACH. The system logs don't show any error (at least not the one similar to that previous one) for the second call.
If I remove that sleep() between those two attempts, then both the sendto() calls "succeed" (and return the expected value for the number of bytes sent). However, the system logs show that the first call (and very likely even the second) has failed with the exact same log message from the kernel like before.
If I'm not wrong then this appears to be some kind of a bug in the "local network" restrictions. Should this be reported? I can share the captured logs but I would prefer to do it privately for this one.
Another interesting thing in all this is that there's absolutely no notification to the end user (I ran this program from the Terminal) about any of the "Local Network" restrictions.
Continuing with my investigations of several issues that we have been noticing in our testing of the JDK with macosx 15.x, I have now narrowed down at least 2 separate problems for which I need help. For a quick background, starting with macosx 15.x several networking related tests within the JDK have started failing in very odd and hard to debug ways in our internal lab. Reading through the macos docs and with help from others in these forums, I have come to understand that a lot of these failures are to do with the new restrictions that have been placed for "Local Network" operations. I have read through https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy and I think I understand the necessary background about these restrictions.
There's more than one issue in this area that I will need help with, so I'll split them out into separate topics in this forum. That above doc states:
macOS 15.1 fixed a number of local network privacy bugs. If you encounter local network privacy problems on macOS 15.0, retest on macOS 15.1 or later.
We did have (and continue to have) 15.0 and 15.1 macos instances within our lab which are impacted by these changes. They too show several networking related failures. However, I have decided not to look into those systems and instead focus only on 15.3.1.
People might see unexpected behavior in System Settings > Privacy & Security if they have multiple versions of the same app installed (FB15568200).
This feedback assistant issue and several others linked in these documentations are inaccessible (even when I login with my existing account). I think it would be good to have some facility in the feedback assistant tool/site to make such issues visible (even if read-only) to be able to watch for updates to those issues.
So now coming to the issue. Several of the networking tests in the JDK do mulicasting testing (through BSD sockets API) in order to test the Java SE multicasting socket API implementations. One repeated failure we have been seeing in our labs is an exception with the message "No route to host". It shows up as:
Process id: 58700
...
java.net.NoRouteToHostException: No route to host
at java.base/sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at java.base/sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:914)
at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:871)
at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:798)
at java.base/sun.nio.ch.DatagramChannelImpl.blockingSend(DatagramChannelImpl.java:857)
at java.base/sun.nio.ch.DatagramSocketAdaptor.send(DatagramSocketAdaptor.java:178)
at java.base/java.net.DatagramSocket.send(DatagramSocket.java:593)
(this is just one example stacktrace from java program)
That "send0" is implemented by the JDK by invoking the sendto() system call. In this case, the sendto() is returning a EHOSTUNREACH error which is what is then propagated to the application.
The forum text editor doesn't allow me to post long text, so I'm going to post the rest of this investigation and logs as a reply.
Just bought a macbook pro m4, im trying to run an api on port 5000, disabled airplay receiver, checked processes, ghost ones, hidden ones, and stuck ones. I didn't find a thing using the port, but i still get port in use.
Topic:
App & System Services
SubTopic:
Networking
Could anyone tell me how to detect status of Local Network for iOS 18+ systems ?
Hi everyone, I developed an Android version of a VPN app built with Flutter using OpenVPN, and it works perfectly on Android. However, when porting it to iOS, I’ve encountered an issue: the app connects successfully but then automatically disconnects when tested via TestFlight. We’ve already added all the necessary network extensions. Despite this, we decided to submit the app to the App Store. It’s been five days now, and the app is still 'Waiting for Review.' Could anyone share their experience deploying and working on an iOS version of a VPN app? I’d really appreciate your insights!
My app sent a network request to the backend. The backend returns a 200, but the front end received a -1001 or -1005 NSURLError. Any clue why this could be happening?
Could anyone teach me how to ask iOS 18 to have a prompt during set-up process of a new APP if user accidentally turns off Local Network ?
Is it possible using the network framework to retrieve the list of certificates presented by the host alone, and not the reconstructed chain assembled by the system?
For example, in OpenSSL one can call SSL_get_peer_cert_chain which will return exactly this - a list of the certificates presented by the server. This is useful for when you may want to manually reconstruct the chain, or if the server is misconfigured (for example, is missing an intermediate cert).
Is something like this possible with the network framework?
If I connect to a host that I know only returns 1 certificate, the trust ref already has the reconstructed chain by the time my code is called:
sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { metadata, trustRef, verifyComplete in
let trust = sec_trust_copy_ref(trustRef).takeRetainedValue()
let numberOfCertificates = SecTrustGetCertificateCount(trust) // Returns 3 even though the server only sent 1
When I use NSURLSessionTaskTransactionMetrics property domainLookupStartDate and domainLookupEndDate to calculate the duration of DNS, sometimes I get 4294893875545978 or -4294893875545978 return
method like this
[NSNumber numberWithLongLong:[taskMetrics.domainLookupEndDate timeIntervalSinceDate:taskMetrics.domainLookupStartDate?]*1000000000]
The hexadecimal value of 4294893875545978 is 0xF3F3F3F3F3F3A.
Is 4294893875545978 a special value?
Topic:
App & System Services
SubTopic:
Networking
Hello,
Title states it basically. I have a java program (launched via shell script) running as a service using launchd which is running as a user (not root) and it does not request Local Network permissions ever.
I feel like i'm missing something here. I combed through all of the Local Network FAQs and don't really see this use case addressed.
I do see that there is an open ticket for an API to trigger the request, but no update on that and the ticket is not visible publicly.
Is there is a way to accomplish this for java or other programs running via launchd with a user other than root? something like an entitlement or an API to seed the permission of Local Network when installing the service via launchctl etc?
We have developed a DNS filter based on NEDNSProxyProvider. It works great for a minute, then it stops responding. Our logs indicate that during the outage our extension gets DNS requests and formulates DNS responses that it hands back to the OS, but from outside of our code it is as though our extension is not responding.