Network connections send and receive data using transport and security protocols.

Posts under Network tag

200 Posts

Post

Replies

Boosts

Views

Activity

Networking Resources
General: Forums subtopic: App & System Services > Networking TN3151 Choosing the right networking API Networking Overview document — Despite the fact that this is in the archive, this is still really useful. TLS for App Developers forums post Choosing a Network Debugging Tool documentation WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi? TN3135 Low-level networking on watchOS TN3179 Understanding local network privacy Adapt to changing network conditions tech talk TCP and UDP ports used by Apple software products support article Understanding Also-Ran Connections forums post Extra-ordinary Networking forums post Foundation networking: Forums tags: Foundation, CFNetwork URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms. Moving to Fewer, Larger Transfers forums post Testing Background Session Code forums post Network framework: Forums tag: Network Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms. WWDC 2025 Session 250 Use structured concurrency with Network framework — This is a great introduction to the new Network framework API introduced in appleOS 2026. Building a custom peer-to-peer protocol sample code (aka TicTacToe) Implementing netcat with Network Framework sample code (aka nwcat) Configuring a Wi-Fi accessory to join a network sample code Moving from Multipeer Connectivity to Network Framework forums post NWEndpoint History and Advice forums post Wi-Fi (general): How to modernize your captive network developer news post Wi-Fi Fundamentals forums post Filing a Wi-Fi Bug Report forums post Working with a Wi-Fi Accessory forums post — This is part of the Extra-ordinary Networking series. Wi-Fi (iOS): TN3111 iOS Wi-Fi API overview technote Wi-Fi Aware framework documentation Building peer-to-peer apps sample code WirelessInsights framework documentation iOS Network Signal Strength forums post Network Extension Resources Wi-Fi on macOS: Forums tag: Core WLAN Core WLAN framework documentation Secure networking: Forums tags: Security Apple Platform Security support document Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS). WWDC 2017 Session 701 Your Apps and Evolving Network Security Standards [1] — This is generally interesting, but the section starting at 17:40 is, AFAIK, the best information from Apple about how certificate revocation works on modern systems. WWDC 2025 Session 314 Get ahead with quantum-secure cryptography Available trusted root certificates for Apple operating systems support article Requirements for trusted certificates in iOS 13 and macOS 10.15 support article About upcoming limits on trusted certificates support article Apple’s Certificate Transparency policy support article What’s new for enterprise in iOS 18 support article — This discusses new key usage requirements. Prepare your network environment for stricter security requirements support article — This is primarily of interest to folks developing management software, for example, an MDM server. Technote 2232 HTTPS Server Trust Evaluation Technote 2326 Creating Certificates for TLS Testing QA1948 HTTPS and Test Servers Miscellaneous: More network-related forums tags: 5G, QUIC, Bonjour On FTP forums post Using the Multicast Networking Additional Capability forums post Investigating Network Latency Problems forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] This video is no longer available from Apple, but the URL should help you locate other sources of this info.
0
0
6.5k
Sep ’26
libquic.dylib crash during QUIC path migration on iOS 26 (quic_migration_probe_path / nw_protocol_data_access_buffer)
libquic.dylib crashes with a null/invalid buffer access in nw_protocol_data_access_buffer during QUIC connection path migration on iOS 26. App code is not in the stack — this is entirely within Apple system libraries. We are seeing a consistent crash on iOS 26 that does not reproduce on iOS 17 or iOS 18. The crash occurs on a background thread ("com.apple.network.connections") with no application code in the crashed thread's stack. The crash trace begins in quic_migration_probe_path and terminates in nw_protocol_data_access_buffer + 180, suggesting a use-after-free or buffer lifetime violation during QUIC connection path migration (e.g., Wi-Fi ↔ Cellular handoff). This crash does not appear to be reproducible on demand — it correlates with network path transitions while QUIC connections are active. Our app uses standard URLSession with default/ephemeral session configurations and does not explicitly enable HTTP/3; iOS 26 is automatically upgrading eligible connections. Crash thread (abbreviated): 0 libquic.dylib quic_conn_send_packet + 144 1 libquic.dylib quic_conn_continue_sending + 424 2 libquic.dylib __quic_conn_send_frames_for_key_state_block_invoke_2 + 1244 3 Network nw_protocol_data_access_buffer + 180 ← crash 4 Network nw_protocol_data_copy_buffer 5 Network nw_endpoint_flow_output_frames 6 libquic.dylib quic_conn_send_frames_for_key_state 7 libquic.dylib quic_conn_send_frames 8 libquic.dylib quic_migration_probe_path + 1464 9 libquic.dylib quic_migration_path_established + 2608 10 libquic.dylib __quic_migration_path_event_block_invoke.21 11 libquic.dylib quic_migration_path_event 12 Network nw_protocol_implementation_connected There is no app code in the crashed thread. This is a regression introduced in iOS 26, where libquic.dylib was separated into its own dynamic library and new path migration probe logic was introduced.
5
0
1.1k
10h
Can't the input loop of a NWProtocolFramerImplementation be like...
Recently, I've been asking here about creating a NWProtocolFramerImplementation that splits across line breaks. Examples and questions usually involve some glob in a "while true" loop. From reading around, couldn't that function be implemented as: func handleInput(framer: NWProtocolFramer.Instance) -> Int { // Pull out objects until an incomplete object is discovered. var domainData: Data? while framer.parseInput( minimumIncompleteLength: 1, maximumLength: .max, parse: { buffer, isComplete in guard let buffer else { return 0 } // Why is `buffer` an Optional? // Other checks and computations // Mutate domainData with the result of this iteration. // Return how many bytes from the buffer are an irrevocable part of domainData. } ) { defer { domainData = nil } guard let domainData else { break } let domainMessage = //... let framerMessage = NWProtocolFramer.Message(myMessage: domainMessage) // The return value is whether or not the delivery was immediate. _ = framer.deliverInputNoCopy(length: domainData.count, message: framerMessage, isComplete: true) } return 0 } A clear separation of concerns, and makes figuring out what's going on easier.
1
0
247
11h
SOCKS5 proxies (from PAC or ProxyConfiguration) are never applied to QUIC, and NWConnection silently connects directly
On macOS 27.0.1 (26A434), a SOCKS5 proxy is applied to TCP connections but never to QUIC. This happens whether the proxy comes from a PAC file in the system proxy settings or from an explicit ProxyConfiguration. The system SOCKS5 client only ever sends CONNECT; it never sends UDP ASSOCIATE (RFC 1928, CMD 0x03), so it has no way to carry UDP. URLSession handles this by staying on TCP through the proxy. A QUIC NWConnection instead connects directly to the origin, as if no proxy were configured. Setup. The system proxy settings use a PAC URL (ProxyAutoConfigURLString in scutil --proxy; in my test it was installed through NEProxySettings.proxyAutoConfigurationURL). For the test host, a public site that serves HTTP/3, the PAC returns SOCKS5 127.0.0.1:<port>. For the explicit cases I used a local SOCKS5 server that logs every command it receives. With the system PAC, default parameters, no explicit proxy: URLSession, assumesHTTP3Capable = true: goes through the proxy over TCP (transaction metrics: h2, isProxyConnection == true, remote address 127.0.0.1:<port>). HTTP/3 isn't used, which is consistent: the proxy can't carry it. NWConnection, TLS: currentPath.remoteEndpoint is 127.0.0.1:<port>. The PAC is honored. NWConnection, QUIC (ALPN h3): .ready in about 170 ms, and currentPath.remoteEndpoint is the origin's own address. The PAC is ignored. With an explicit proxy, set via NWParameters.PrivacyContext.proxyConfigurations: QUIC with a working SOCKS5 server: .ready, and the server receives nothing — no CONNECT, no UDP ASSOCIATE. QUIC with the proxy pointing at a port nothing listens on: still .ready, still connected to the origin's own address. TLS with that same dead proxy: stays in .waiting with ECONNREFUSED. The proxy is honored for TCP. At no point did the SOCKS5 server receive a UDP ASSOCIATE request. Cases 3–5 are the concerning part. An app that configures a proxy, or a user or administrator who installs a PAC, reasonably expects traffic to go through the proxy or fail. Instead, QUIC traffic goes straight to the origin, which then sees the device's own address, and nothing in the API signals that the proxy was skipped. Minimal snippet: import Network let host: NWEndpoint.Host = "YOUR_HTTP3_HOST" // any public host that serves HTTP/3 let parameters = NWParameters(quic: NWProtocolQUIC.Options(alpn: ["h3"])) // Remove these four lines to test with the system PAC instead. let privacy = NWParameters.PrivacyContext(description: "socks5-quic") privacy.proxyConfigurations = [ ProxyConfiguration(socksv5Proxy: .hostPort(host: "127.0.0.1", port: 1099)) // nothing listens on 1099 ] parameters.setPrivacyContext(privacy) let connection = NWConnection(host: host, port: 443, using: parameters) connection.stateUpdateHandler = { state in if case .ready = state { // Prints the origin's own address. With NWParameters.tls instead of QUIC, // the same proxy configuration leaves the connection in .waiting (ECONNREFUSED). print(connection.currentPath?.remoteEndpoint as Any) } } connection.start(queue: .main) I filed this as FB24760235 on 09/13/2026 and haven't had a response, so I'd like to ask here: Is it intended that a QUIC NWConnection ignores both the system PAC and proxyConfigurations? If so, how can an app find out that a connection went direct? And shouldn't a connection that can't honor the configured proxy fail rather than bypass it? Is UDP ASSOCIATE support planned for the system SOCKS5 client, so that QUIC and other UDP traffic can follow a SOCKS5 proxy the way TCP does? Thanks!
1
0
281
11h
Unexplained behavioural changes in BSD sockets on macos 26.6.x and 27
We have started seeing some unexplained behavioural differences in the BSD socket APIs on macos 26.6.x and macos 27. On a different front, there also seems to be some changes in the ptrace area for PT_DETACH. Historically, the release notes of macos don't include any mention of such changes. And unfortunately, prior experience of filing feedback assistant issues too hasn't been very motivating due to lack of any response on those tickets. These forums have been very helpful in trying to understand some of these changes, and I plan to raise separate topics for the issues shortly. In the past, the other useful option I have used is reading up the kernel sources published at https://opensource.apple.com/releases/. But there hasn't been any updates for macos 26.6 or macos 27. It will be very useful if macos 26.6 and 27 releases are published there. That will help expedite investigating some of these failures. BSD socket APIs in the recent releases of macos have seen several issues (feedback assistant issues have been filed). The implications of these failures is that we (in OpenJDK) have had to disable several tests on recent versions of macos which has reduced the test coverage and reliability of these very primitive networking APIs on this platform.
5
0
225
2d
Dual-stack UDP socket bound to port 0 can get a port already in use on 127.0.0.1 (FB25058707)
I filed FB25058707 and wanted to make sure it reaches the right people, because it causes silent datagram loss that's hard to trace. On macOS, when a dual-stack UDP socket (AF_INET6 with IPV6_V6ONLY=0) binds [::]:0, the kernel sometimes gives it a port that an AF_INET socket already has bound to 127.0.0.1. Datagrams sent to 127.0.0.1 on that port then go to the AF_INET socket, so the dual-stack socket never receives them. An explicit bind of the same socket to that port fails with EADDRINUSE; only port-0 assignment hands it out. This program binds 1000 AF_INET sockets to 127.0.0.1:0, then binds dual-stack sockets to [::]:0 and checks where a datagram to 127.0.0.1:port lands whenever the port is already held. It's loopback only and runs in a few seconds: /* * A dual-stack UDP socket (AF_INET6, IPV6_V6ONLY=0) bound to [::]:0 can be * assigned a port already bound by an AF_INET socket on 127.0.0.1. Datagrams * to 127.0.0.1:port then reach the AF_INET socket, not the dual-stack one. * Loopback only. Build: cc -O2 -o dualstack_port0 dualstack_port0.c */ #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #define HELD 1000 #define TRIALS 2000 static int held[65536]; static void die(const char *what) { perror(what); exit(1); } static int port_of(int s) { struct sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &len) != 0) die("getsockname"); if (ss.ss_family == AF_INET) return ntohs(((struct sockaddr_in *)&ss)->sin_port); return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); } static int bind_v4(in_addr_t addr) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket AF_INET"); struct sockaddr_in sin = { .sin_len = sizeof(sin), .sin_family = AF_INET, .sin_addr.s_addr = addr }; if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) die("bind AF_INET"); return s; } static int bind_dual(void) { int s = socket(AF_INET6, SOCK_DGRAM, 0), off = 0; if (s < 0) die("socket AF_INET6"); if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) != 0) die("IPV6_V6ONLY"); struct sockaddr_in6 sin6 = { .sin6_len = sizeof(sin6), .sin6_family = AF_INET6, .sin6_addr = in6addr_any }; if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) die("bind AF_INET6"); return s; } /* Returns 1 if s receives token within 100ms, skipping other datagrams. */ static int got(int s, const char *token) { struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 }; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) die("SO_RCVTIMEO"); char buf[64]; for (;;) { ssize_t n = recv(s, buf, sizeof(buf) - 1, 0); if (n < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; die("recv"); } buf[n] = 0; if (strcmp(buf, token) == 0) return 1; } } int main(void) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) die("getrlimit"); rl.rlim_cur = rl.rlim_max < 4096 ? rl.rlim_max : 4096; if (setrlimit(RLIMIT_NOFILE, &rl) != 0) die("setrlimit"); memset(held, -1, sizeof(held)); for (int i = 0; i < HELD;) { int s = bind_v4(htonl(INADDR_LOOPBACK)), p = port_of(s); if (held[p] >= 0) { close(s); continue; } held[p] = s; i++; } int sender = bind_v4(htonl(INADDR_LOOPBACK)); for (int dual = 1; dual >= 0; dual--) { int collisions = 0, to_held = 0, to_wild = 0; for (int i = 0; i < TRIALS; i++) { int w = dual ? bind_dual() : bind_v4(htonl(INADDR_ANY)), p = port_of(w); if (held[p] >= 0) { collisions++; char token[32]; snprintf(token, sizeof(token), "%d-%d", dual, i); struct sockaddr_in to = { .sin_len = sizeof(to), .sin_family = AF_INET, .sin_port = htons(p), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) }; if (sendto(sender, token, strlen(token), 0, (struct sockaddr *)&to, sizeof(to)) < 0) die("sendto"); to_held += got(held[p], token); to_wild += got(w, token); } close(w); } printf("%s: %d/%d wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket %d times, the wildcard socket %d times\n", dual ? "AF_INET6 V6ONLY=0 [::]:0" : "AF_INET 0.0.0.0:0 ", collisions, TRIALS, to_held, to_wild); } return 0; } On macOS 27.0 (26A428): AF_INET6 V6ONLY=0 [::]:0: 122/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 122 times, the wildcard socket 0 times AF_INET 0.0.0.0:0 : 0/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 0 times, the wildcard socket 0 times macOS 15.8.1 x86_64 gives the same pattern, and a Go version of the test reproduces on 15.7.9 and 26.6.2 as well. FreeBSD 15.1 gives 0/2000 with a dual-stack socket. From the public XNU source (xnu-12377.121.6), in6_pcbsetport checks candidate ports with in6_pcblookup_local, which skips PCBs without INP_IPV6, while in6_pcbbind does an IPv4 PCB lookup for dual-stack wildcard binds. That would explain why an explicit bind is refused but port 0 isn't. This is the cause of the long-standing Go issue golang/go#67226, since Go's net.ListenUDP("udp", 0.0.0.0:0) creates exactly this socket, and of intermittent failures in QUIC client tests. Using an AF_INET socket for IPv4-only traffic avoids it, but there's no workaround for a socket that needs both families on one port.
2
0
156
3d
macos 27 - EDOM error from setsockopt() for SO_LINGER socket option for values greater than 32767
On macos 27, there appears to be a change in the setsockopt() implementation for the SO_LINGER option. It looks like the implementation now imposes a different maximum limit on the value that is accepted for linger. Consider the trivial attached C program. Rename it from main.c.txt to main.c. Compiling it (using clang main.c) and running it (using ./a.out), on older versions of macos (like 26.x), it returns: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 SUCCESS - set SO_LINGER to value 32768 SUCCESS - set SO_LINGER to value 65535 SUCCESS - set SO_LINGER to value 65536 SUCCESS - set SO_LINGER to value 65578 However, on macos 27, this now fails with EDOM error ("Numerical argument out of domain") for values greater than 32767: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 FAILURE - failed to set SO_LINGER to value 32768, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65535, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65536, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65578, reason: Numerical argument out of domain I'm guessing this is an intentional change, but I wanted to confirm nonetheless. Should the documentation of SO_LINGER and SO_LINGER_SEC socket options, in man setsockopt, mention the acceptable value range for them? main.c.txt
2
0
156
6d
macos 27 - unexpected/new errno from BSD socket connect() when pending connections exceed backlog
Please consider the trivial C program attached to this thread. The code creates a socket() and listen()s for connections, but (intentionally) doesn't accept() the connections. The listen() is done using a small backlog (of 1). This test then does several connect() attempts and expects that the connect() attempts will accumulate in the pending queue and once the queue exceeds the backlog limit, then as specified in man listen: The backlog parameter defines the maximum length for the queue of pending connections. If a connection request arrives with the queue full, the client may receive an error with an indication of ECONNREFUSED. then the connect() attempt will receive a ECONNREFUSED. However, in macos 27, such a connect() attempt leads to ECONNRESET (Connection reset by peer) instead of ECONNREFUSED. Is this expected? Experiments show that prior versions of macos were returning a ETIMEDOUT for such connect() attempts. If this new error is expected from connect() when the backlog limit has exceeded, should it be specified in the man listen documentation? Rename the attached main.c.txt to main.c. Compiling the attached program on macos 27, using clang main.c and then running ./a.out results in: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- started server at at 127.0.0.1:52753 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - connected connect() attempt 3 - connected connect() attempt 4 - connected connect() attempt 5 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 6 - connected connect() attempt 7 - connected connect() attempt 8 - connected connect() attempt 9 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 10 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 11 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 On a related note, it's unclear why several of the connect() attempts succeeded instead of just 1 of them succeeding. On prior versions of macos, the output of the same program is: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- started server at at 127.0.0.1:52451 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - failed to connect() - Operation timed out connect() attempt 3 - failed to connect() - Operation timed out connect() attempt 4 - failed to connect() - Operation timed out connect() attempt 5 - failed to connect() - Operation timed out connect() attempt 6 - failed to connect() - Operation timed out connect() attempt 7 - failed to connect() - Operation timed out connect() attempt 8 - failed to connect() - Operation timed out connect() attempt 9 - failed to connect() - Operation timed out connect() attempt 10 - failed to connect() - Operation timed out connect() attempt 11 - failed to connect() - Operation timed out and this output is much more understandable and deterministic. main.c.txt
2
0
156
6d
Out-of-band data returned by recv() and read() on socket bound to non-loopback address even when SO_OOBINLINE is disabled
I've been investigating an issue with the SO_OOBINLINE socket option. When that option is disabled, the expectation is that out-of-band data that is sent on the socket will not be available through the use of read() or recv() calls on that socket. What we have been noticing is that when the socket is bound to a non-loopback address (and the communication is happening over that non-loopback address), then even when SO_OOBINLINE is disabled for the socket, the read()/recv() calls both return the out-of-band data. The issue however isn't reproducible with loopback address, and read()/recv() both correctly exclude the out-of-band data. This issue is only noticed on macos. I have been able to reproduce on macos M1, following version, but the original report which prompted me to look into this was reported on macos x64. My M1 OS version is: sw_vers ProductName: macOS ProductVersion: 14.3.1 BuildVersion: 23D60 Attached is a reproducer (main.c.txt - rename it to main.c after downloading) that I have been able to develop which reproduces this issue on macos. When you compile and run that: ./a.out it binds to a non-loopback address by default and you should see the failure log, resembling: ... ERROR: expected: 1234512345 but received: 12345U12345 To run the same reproducer against loopback address, run it as: ./a.out loopback and that should succeed (i.e. no out-of-band data) with logs resembling: ... SUCCESS: completed successfully, expected: 1234512345, received: 1234512345 Is this a bug in the OS? I would have reported this directly through feedback assistant, but my past few open issues (since more than a year) have not even seen an acknowledgement or a reply, so I decided to check here first. main.c.txt
8
0
1.2k
1w
URLSession fails with -1009 on physical iPhone 16 Pro Max running iOS 27 beta, works in Simulator
I’m building a SwiftUI app that fetches public JSON data using URLSession.shared. The request works correctly in the iPhone 17 Pro Max Simulator, but fails on my physical iPhone 16 Pro Max running iOS 27 beta. Endpoint: https://api.jolpi.ca/ergast/f1/2026/driverstandings.json?limit=100 Error: NSURLErrorDomain Code=-1009 “The Internet connection appears to be offline.” NWPath: unsatisfied (Denied over Wi-Fi interface) Resolved 0 endpoints in 1ms The device can access the endpoint through Safari, and the same request works in Simulator. VPN, cellular permissions, Wi-Fi changes, and ATS settings have been checked. Could this be an iOS 27 beta networking regression affecting URLSession on physical devices? Are there recommended workarounds or diagnostics?
1
0
704
1w
How to do line- and message-delimination
I'm trying to write a NWProtocolFramerImplementation class that will be channeled through a Framer wrapper. There are still some parts I need figuring out. For handleOutput(framer: message: messageLength: isComplete), what do the last two parameters do? Does isComplete refer to the end of the current conversation, or the entire connection? Why would we submit a messageLength if the data size should already be implied within message? If I parse by line breaks, is there a way to indicate if the latest line is the last of the current conversation, either input or output?
1
0
145
1w
Network Interface APIs
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" Network Interface APIs Most developers don’t need to interact directly with network interfaces. If you do, read this post for a summary of the APIs available to you. Before you read this, read Network Interface Concepts. Interface List The standard way to get a list of interfaces and their addresses is getifaddrs. To learn more about this API, see its man page. A network interface has four fundamental attributes: A set of flags — These are packed into a CUnsignedInt. The flags bits are declared in <net/if.h>, starting with IFF_UP. An interface type — See Network Interface Type, below. An interface index — Valid indexes are greater than 0. A BSD interface name. For example, an Ethernet interface might be called en0. The interface name is shared between multiple network interfaces running over a given hardware interface. For example, IPv4 and IPv6 running over that Ethernet interface will both have the name en0. WARNING BSD interface names are not considered API. There’s no guarantee, for example, that an iPhone’s Wi-Fi interface is en0. You can map between the last two using if_indextoname and if_nametoindex. See the if_indextoname man page for details. An interface may also have address information. If present, this always includes the interface address (ifa_addr) and the network mask (ifa_netmask). In addition: Broadcast-capable interfaces (IFF_BROADCAST) have a broadcast address (ifa_broadaddr, which is an alias for ifa_dstaddr). Point-to-point interfaces (IFF_POINTOPOINT) have a destination address (ifa_dstaddr). Calling getifaddrs from Swift is a bit tricky. For an example of this, see QSocket: Interfaces. IP Address List Once you have getifaddrs working, it’s relatively easy to manipulate the results to build a list of just IP addresses, a list of IP addresses for each interface, and so on. QSocket: Interfaces has some Swift snippets that show this. Interface List Updates The interface list can change over time. Hardware interfaces can be added and removed, network interfaces come up and go down, and their addresses can change. It’s best to avoid caching information from getifaddrs. If thats unavoidable, use the kNotifySCNetworkChange Darwin notification to update your cache. For information about registering for Darwin notifications, see the notify man page (in section 3). This notification just tells you that something has changed. It’s up to you to fetch the new interface list and adjust your cache accordingly. You’ll find that this notification is sometimes posted numerous times in rapid succession. To avoid unnecessary thrashing, debounce it. While the Darwin notification API is easy to call from Swift, Swift does not import kNotifySCNetworkChange. To fix that, define that value yourself, calling a C function to get the value: var kNotifySCNetworkChange: UnsafePointer<CChar> { networkChangeNotifyKey() } Here’s what that C function looks like: extern const char * networkChangeNotifyKey(void) { return kNotifySCNetworkChange; } Network Interface Type There are two ways to think about a network interface’s type. Historically there were a wide variety of weird and wonderful types of network interfaces. The following code gets this legacy value for a specific BSD interface name: func legacyTypeForInterfaceNamed(_ name: String) -> UInt8? { var addrList: UnsafeMutablePointer<ifaddrs>? = nil let err = getifaddrs(&addrList) // In theory we could check `errno` here but, honestly, what are gonna // do with that info? guard err >= 0, let first = addrList else { return nil } defer { freeifaddrs(addrList) } return sequence(first: first, next: { $0.pointee.ifa_next }) .compactMap { addr in guard let nameC = addr.pointee.ifa_name, name == String(cString: nameC), let sa = addr.pointee.ifa_addr, sa.pointee.sa_family == AF_LINK, let data = addr.pointee.ifa_data else { return nil } return data.assumingMemoryBound(to: if_data.self).pointee.ifi_type } .first } The values are defined in <net/if_types.h>, starting with IFT_OTHER. However, this value is rarely useful because many interfaces ‘look like’ Ethernet and thus have a type of IFT_ETHER. Network framework has the concept of an interface’s functional type. This is an indication of how the interface fits into the system. There are two ways to get an interface’s functional type: If you’re using Network framework and have an NWInterface value, get the type property. If not, call ioctl with a SIOCGIFFUNCTIONALTYPE request. The return values are defined in <net/if.h>, starting with IFRTYPE_FUNCTIONAL_UNKNOWN. Swift does not import SIOCGIFFUNCTIONALTYPE, so it’s best to write this code in a C: extern uint32_t functionalTypeForInterfaceNamed(const char * name) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return IFRTYPE_FUNCTIONAL_UNKNOWN; } struct ifreq ifr = {}; strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); bool success = ioctl(fd, SIOCGIFFUNCTIONALTYPE, &ifr) >= 0; int junk = close(fd); assert(junk == 0); if ( ! success ) { return IFRTYPE_FUNCTIONAL_UNKNOWN; } return ifr.ifr_ifru.ifru_functional_type; } Finally, TN3158 Resolving Xcode 15 device connection issues documents the SIOCGIFDIRECTLINK flag as a specific way to identify the network interfaces uses by Xcode for device connection traffic. Routing Sockets macOS supports the traditional BSD routine socket interface. See the route man page for details. Note You can access some routing socket functionality via sysctl, and all of this section applies to that as well. Other Apple platforms don’t support routing sockets [1]. On macOS it’s reasonable to use a routing socket to learn about the current state of the networking stack and be notified of changes to that state. Doing this on macOS 27 and later may require you to sign your code with the com.apple.developer.networking.topology-observation entitlement. In Xcode, add the Network Topology Observation capability [2] to your target. This is a restricted entitlement, which means it must be authorised by a provisioning profile. If you’re building a command-line tool, follow the advice in Signing a daemon with a restricted entitlement. Don’t use a routing socket to change the state of the networking stack. Such activities are not supported because macOS maintains its source of truth outside of the kernel, primarily in the System Configuration infrastructure [3]. If you make changes behind the back of this infrastructure then, in the best case, they’ll simply be overwritten at some point in the future, but in the worst case you could trigger stability problems. [1] You may or may not be able to open one, based on the current sandbox setup. Even if you can, that effort is not supported because the declarations required to use the socket, most obviously rt_msghdr, are only present in the macOS SDK. And no, copying declarations from one SDK to another is not supported (-; [2] There’s no link to the docs for this capability because that hasn’t yet landed (r. 181611259). [3] See System Configuration Programming Guidelines for a general introduction this architecture. Revision History 2026-09-23 Added the Routing Sockets section. 2025-12-10 Added info about SIOCGIFDIRECTLINK. 2023-07-19 First posted.
0
0
2.6k
2w
Appropriate API for measuring device-wide network traffic on iOS
I am developing a consumer iOS app for App Store distribution and would like to confirm the appropriate public API for the following use case. The app needs to measure the amount of network traffic passing through the device over short time intervals, for example once per second or more frequently. The app does not need to inspect packet contents, block or filter traffic, or provide a remote VPN service. It also should not generate dedicated network traffic solely for speed measurement. The goal is only to observe device-wide network traffic volume and convert that information into a simple real-time indicator for the user. I am currently investigating the Network Extension framework. Would NEPacketTunnelProvider be an appropriate API for this use case? If not, is there another supported Network Extension provider or other public iOS API intended for measuring device-wide network traffic in this manner? I would like to choose an architecture that is technically supported by Apple and appropriate for a consumer app distributed through the App Store before beginning implementation.
1
0
261
2w
iOS app loses Internet access after updates: wifiDenied and native URLSession -1009
Hello, Feedback Assistant report: FB24876147. I develop a Unity-based iOS app. Some customers in mainland China report losing Internet access after an app update, while most installations continue working. We have received similar reports since at least iOS 16, across several years and multiple app releases. Earlier iOS versions are uncertain, and we cannot confirm that all historical occurrences share the same cause. Updates without networking-code changes can be followed by failures. A later update sometimes restores connectivity, but not consistently. Customer-reported recovery attempts: The app's wireless-data permissions appear enabled in Settings. Switching the app's network permission to another setting and back did not help users who reported trying it. Reset Network Settings also did not help users who reported trying it. Some users reported that deleting and reinstalling the app restored connectivity. At least one user reported that deletion and reinstallation did not help. These are customer reports, not controlled tests on our development devices. We would prefer a recovery that preserves local save data. Captured evidence from one affected installation: App version 1.89, build 1; Unity 2022.3.62f3. Device identifier: iPhone18,1; iOS 26.2.1. App in foreground. Capture time: 2026-09-07 13:04:31–13:04:32 UTC. An unfiltered Network.framework default-path monitor reported: status=unsatisfied reason=wifiDenied interface=Wi-Fi UnityWebRequest and a newly created native ephemeral NSURLSession both failed against our public HTTPS origin and Apple's independent test endpoint: https://www.apple.com/library/test/success.html The native requests failed after approximately 1 ms and 3 ms, with NSURLErrorDomain -1009, underlying kCFErrorDomainCFNetwork -1009, and no HTTP response. The native session allowed cellular, expensive and constrained network access, used normal TLS verification, and had waitsForConnectivity=false. It bypassed Unity's reachability precheck. CTCellularData changed from unknown to notRestricted. We understand this does not establish successful cellular connectivity or Wi-Fi permission. Important limitations: The native probes ran inside the same Unity-built process, not a separate standalone native app. The captured measurements demonstrate a Wi-Fi failure. Cellular failures and enabled Settings permissions are customer reports, not independently verified by these measurements. We cannot reliably reproduce the affected state on our development devices and do not have a focused Xcode project that reproduces it. An affected-device sysdiagnose is not yet available. Unity Customer QA reviewed this evidence, assessed it as an iOS network-policy issue rather than a Unity bug, and referred us to Apple. We are seeking Apple's investigation, not presenting that assessment as a confirmed root cause. The Code-Level Support form directed us to these forums because we cannot currently provide a focused reproducer. Questions: Which affected-device diagnostics or logging profiles would help identify why the effective network policy reports wifiDenied? How should we investigate an installation-specific issue when a new minimal app may not reproduce that installation state? Is there a supported, data-preserving recovery or application-side mitigation when permission changes and network resets do not help, and reinstallation is not consistently effective? We have diagnostic screenshots and relevant probe source available. Any customer system logs would be collected with consent and shared privately with Apple, not posted publicly. Thank you.
1
0
208
2w
macos 26 - socket() syscall causes ENOBUFS "No buffer space available" error
As part of the OpenJDK testing we run several regression tests, including for Java SE networking APIs. These APIs ultimately end up calling BSD socket functions. On macos, starting macos 26, including on recent 26.2 version, we have started seeing some unexplained but consistent exception from one of these BSD socket APIs. We receive a "ENOBUFS" errno (No buffer space available) when trying to construct a socket(). These exact same tests continue to pass on many other older versions of macos (including 15.7.x). After looking into this more, we have been able to narrow this down to a very trivial C code which is as follows (also attached): #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <unistd.h> #include <sys/errno.h> static int create_socket(const int attempt_number) { const int fd = socket(AF_INET6, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "socket creation failed on attempt %d," " due to: %s\n", attempt_number, strerror(errno)); return fd; } return fd; } int main() { const unsigned int num_times = 250000; for (unsigned int i = 1; i <= num_times; i++) { const int fd = create_socket(i); if (fd < 0) { return -1; } close(fd); } fprintf(stderr, "successfully created and closed %d sockets\n", num_times); } The code very trivially creates a socket() and close()s it. It does this repeatedly in a loop for a certain number of iterations. Compiling this as: clang sockbufspaceerr.c -o sockbufspaceerr.o and running it as: ./sockbufspaceerr.o consistently generates an error as follows on macos 26.x: socket creation failed on attempt 160995, due to: No buffer space available The iteration number on which the socket() creation fails varies, but the issue does reproduce. Running the same on older versions of macos doesn't reproduce the issue and the program terminates normally after those many iterations. Looking at the xnu source that is made available for each macos release here https://opensource.apple.com/releases/, I see that for macos 26.x there have been changes in this kernel code and there appears to be some kind of memory accountability code introduced in this code path. However, looking at the reproducer/application code in question, I believe it uses the right set of functions to both create as well as release the resources, so I can't see why this should cause the above error in macos 26.x. Does this look like some issue that needs attention in the macos kernel and should I report it through feedback assitant tool?
8
0
1.6k
2w
Transparent proxy breaks apps on macOS 15.7.8 RC 5
Hello! Users of my app observed behaviour that some apps stopped working after update to 15.7.8 via Beta channel with transparent proxy network extension on. The app receives Protocol not available error, and I see setsockopt SO_FLOW_DIVERT_TOKEN failed [42: Protocol not available] error in Console. To reproduce, create two rules in basic NETransparentProxyProvider: [[NENetworkRule alloc] initWithDestinationNetwork:nil prefix:0 protocol:NENetworkRuleProtocolTCP], [[NENetworkRule alloc] initWithDestinationNetwork:nil prefix:0 protocol:NENetworkRuleProtocolUDP], You may even return NO in handleNewFlow, it does not matter. After that, Safari won't open some sites, and Weather app will work unreliably. Do anyone knows any workaround for this problem? I've also create a relevant FB23788740.
8
0
1.3k
2w
App rejected for entitlements the app needs
Hi— App review said: The app uses one or more entitlements which do not have matching functionality within the app. Apps should have only the minimum set of entitlements necessary for the app to function properly. Please remove all entitlements that are not needed by the app and submit an updated binary for review, including the following: • com.apple.security.device.camera • com.apple.security.network.server …but my app has a feature that does use the camera (continuity camera for macOS, and a bonjour feature for finding other local app instances, establishing a link, and sending data to other instances. I’ve tried declaring/justifying talking about it in App testing info and in my reply to the reviewer, about how to access the features that require it. do I really not need these entitlements and only seems like I would? do I simply test app scheme Release > no debug executable with fresh sandbox and see if features break? But no declaring these things seems like the opposite of what Apple would want… it seems like explicitly calling out these features makes a lot more sense? this is my first app— thank you
0
0
599
2w
Does "Connectivity Assist" bypass NEPacketTunnelProvider DNS interception on iOS 27?
We have a NEPacketTunnelProvider extension that intercepts and modifies DNS responses for specific hostnames as part of its normal operation. On iOS 27, we are seeing this interception being intermittently bypassed. Our extension still receives the DNS query, builds a response, and returns it promptly, but the client occasionally proceeds using a different address, presumably the actual DNS resolution result. This behavior does not reproduce on iOS 26 or earlier. The timing in our logs appears to correlate with the new Connectivity Assist feature (Settings → Wi-Fi), which Apple describes as using cellular data alongside Wi-Fi to improve reliability. Our suspicion is that Connectivity Assist may be performing DNS resolution over a cellular path in parallel, outside the tunnel, causing that resolution path to bypass our provider entirely. We have ruled out response timing and response format issues on our side. Varying the speed and format of our responses does not affect the outcome, suggesting that the behavior is occurring at a layer above the tunnel provider. We have the following questions: Does Connectivity Assist perform DNS resolution on a network path that can bypass an active NEPacketTunnelProvider? Is there any API, entitlement, or supported mechanism to disable Connectivity Assist for an app, or to ensure that all DNS resolution is routed through the active tunnel, similar to previous Wi-Fi Assist opt-out capabilities? Would a NEDNSProxyProvider-based DNS proxy be affected in the same way, or does it operate at a layer that Connectivity Assist cannot bypass? Any guidance, references to relevant documentation, WWDC session content, or confirmation of the expected behavior would be greatly appreciated.
5
0
951
3w
Networking Resources
General: Forums subtopic: App & System Services > Networking TN3151 Choosing the right networking API Networking Overview document — Despite the fact that this is in the archive, this is still really useful. TLS for App Developers forums post Choosing a Network Debugging Tool documentation WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi? TN3135 Low-level networking on watchOS TN3179 Understanding local network privacy Adapt to changing network conditions tech talk TCP and UDP ports used by Apple software products support article Understanding Also-Ran Connections forums post Extra-ordinary Networking forums post Foundation networking: Forums tags: Foundation, CFNetwork URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms. Moving to Fewer, Larger Transfers forums post Testing Background Session Code forums post Network framework: Forums tag: Network Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms. WWDC 2025 Session 250 Use structured concurrency with Network framework — This is a great introduction to the new Network framework API introduced in appleOS 2026. Building a custom peer-to-peer protocol sample code (aka TicTacToe) Implementing netcat with Network Framework sample code (aka nwcat) Configuring a Wi-Fi accessory to join a network sample code Moving from Multipeer Connectivity to Network Framework forums post NWEndpoint History and Advice forums post Wi-Fi (general): How to modernize your captive network developer news post Wi-Fi Fundamentals forums post Filing a Wi-Fi Bug Report forums post Working with a Wi-Fi Accessory forums post — This is part of the Extra-ordinary Networking series. Wi-Fi (iOS): TN3111 iOS Wi-Fi API overview technote Wi-Fi Aware framework documentation Building peer-to-peer apps sample code WirelessInsights framework documentation iOS Network Signal Strength forums post Network Extension Resources Wi-Fi on macOS: Forums tag: Core WLAN Core WLAN framework documentation Secure networking: Forums tags: Security Apple Platform Security support document Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS). WWDC 2017 Session 701 Your Apps and Evolving Network Security Standards [1] — This is generally interesting, but the section starting at 17:40 is, AFAIK, the best information from Apple about how certificate revocation works on modern systems. WWDC 2025 Session 314 Get ahead with quantum-secure cryptography Available trusted root certificates for Apple operating systems support article Requirements for trusted certificates in iOS 13 and macOS 10.15 support article About upcoming limits on trusted certificates support article Apple’s Certificate Transparency policy support article What’s new for enterprise in iOS 18 support article — This discusses new key usage requirements. Prepare your network environment for stricter security requirements support article — This is primarily of interest to folks developing management software, for example, an MDM server. Technote 2232 HTTPS Server Trust Evaluation Technote 2326 Creating Certificates for TLS Testing QA1948 HTTPS and Test Servers Miscellaneous: More network-related forums tags: 5G, QUIC, Bonjour On FTP forums post Using the Multicast Networking Additional Capability forums post Investigating Network Latency Problems forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] This video is no longer available from Apple, but the URL should help you locate other sources of this info.
Replies
0
Boosts
0
Views
6.5k
Activity
Sep ’26
libquic.dylib crash during QUIC path migration on iOS 26 (quic_migration_probe_path / nw_protocol_data_access_buffer)
libquic.dylib crashes with a null/invalid buffer access in nw_protocol_data_access_buffer during QUIC connection path migration on iOS 26. App code is not in the stack — this is entirely within Apple system libraries. We are seeing a consistent crash on iOS 26 that does not reproduce on iOS 17 or iOS 18. The crash occurs on a background thread ("com.apple.network.connections") with no application code in the crashed thread's stack. The crash trace begins in quic_migration_probe_path and terminates in nw_protocol_data_access_buffer + 180, suggesting a use-after-free or buffer lifetime violation during QUIC connection path migration (e.g., Wi-Fi ↔ Cellular handoff). This crash does not appear to be reproducible on demand — it correlates with network path transitions while QUIC connections are active. Our app uses standard URLSession with default/ephemeral session configurations and does not explicitly enable HTTP/3; iOS 26 is automatically upgrading eligible connections. Crash thread (abbreviated): 0 libquic.dylib quic_conn_send_packet + 144 1 libquic.dylib quic_conn_continue_sending + 424 2 libquic.dylib __quic_conn_send_frames_for_key_state_block_invoke_2 + 1244 3 Network nw_protocol_data_access_buffer + 180 ← crash 4 Network nw_protocol_data_copy_buffer 5 Network nw_endpoint_flow_output_frames 6 libquic.dylib quic_conn_send_frames_for_key_state 7 libquic.dylib quic_conn_send_frames 8 libquic.dylib quic_migration_probe_path + 1464 9 libquic.dylib quic_migration_path_established + 2608 10 libquic.dylib __quic_migration_path_event_block_invoke.21 11 libquic.dylib quic_migration_path_event 12 Network nw_protocol_implementation_connected There is no app code in the crashed thread. This is a regression introduced in iOS 26, where libquic.dylib was separated into its own dynamic library and new path migration probe logic was introduced.
Replies
5
Boosts
0
Views
1.1k
Activity
10h
Can't the input loop of a NWProtocolFramerImplementation be like...
Recently, I've been asking here about creating a NWProtocolFramerImplementation that splits across line breaks. Examples and questions usually involve some glob in a "while true" loop. From reading around, couldn't that function be implemented as: func handleInput(framer: NWProtocolFramer.Instance) -> Int { // Pull out objects until an incomplete object is discovered. var domainData: Data? while framer.parseInput( minimumIncompleteLength: 1, maximumLength: .max, parse: { buffer, isComplete in guard let buffer else { return 0 } // Why is `buffer` an Optional? // Other checks and computations // Mutate domainData with the result of this iteration. // Return how many bytes from the buffer are an irrevocable part of domainData. } ) { defer { domainData = nil } guard let domainData else { break } let domainMessage = //... let framerMessage = NWProtocolFramer.Message(myMessage: domainMessage) // The return value is whether or not the delivery was immediate. _ = framer.deliverInputNoCopy(length: domainData.count, message: framerMessage, isComplete: true) } return 0 } A clear separation of concerns, and makes figuring out what's going on easier.
Replies
1
Boosts
0
Views
247
Activity
11h
What is the estimated timeline for Apple to implement Wi-Fi Aware Release 5 (R5) support?
What is the estimated timeline for Apple to implement Wi-Fi Aware Release 5 (R5) support?
Replies
1
Boosts
0
Views
59
Activity
11h
SOCKS5 proxies (from PAC or ProxyConfiguration) are never applied to QUIC, and NWConnection silently connects directly
On macOS 27.0.1 (26A434), a SOCKS5 proxy is applied to TCP connections but never to QUIC. This happens whether the proxy comes from a PAC file in the system proxy settings or from an explicit ProxyConfiguration. The system SOCKS5 client only ever sends CONNECT; it never sends UDP ASSOCIATE (RFC 1928, CMD 0x03), so it has no way to carry UDP. URLSession handles this by staying on TCP through the proxy. A QUIC NWConnection instead connects directly to the origin, as if no proxy were configured. Setup. The system proxy settings use a PAC URL (ProxyAutoConfigURLString in scutil --proxy; in my test it was installed through NEProxySettings.proxyAutoConfigurationURL). For the test host, a public site that serves HTTP/3, the PAC returns SOCKS5 127.0.0.1:<port>. For the explicit cases I used a local SOCKS5 server that logs every command it receives. With the system PAC, default parameters, no explicit proxy: URLSession, assumesHTTP3Capable = true: goes through the proxy over TCP (transaction metrics: h2, isProxyConnection == true, remote address 127.0.0.1:<port>). HTTP/3 isn't used, which is consistent: the proxy can't carry it. NWConnection, TLS: currentPath.remoteEndpoint is 127.0.0.1:<port>. The PAC is honored. NWConnection, QUIC (ALPN h3): .ready in about 170 ms, and currentPath.remoteEndpoint is the origin's own address. The PAC is ignored. With an explicit proxy, set via NWParameters.PrivacyContext.proxyConfigurations: QUIC with a working SOCKS5 server: .ready, and the server receives nothing — no CONNECT, no UDP ASSOCIATE. QUIC with the proxy pointing at a port nothing listens on: still .ready, still connected to the origin's own address. TLS with that same dead proxy: stays in .waiting with ECONNREFUSED. The proxy is honored for TCP. At no point did the SOCKS5 server receive a UDP ASSOCIATE request. Cases 3–5 are the concerning part. An app that configures a proxy, or a user or administrator who installs a PAC, reasonably expects traffic to go through the proxy or fail. Instead, QUIC traffic goes straight to the origin, which then sees the device's own address, and nothing in the API signals that the proxy was skipped. Minimal snippet: import Network let host: NWEndpoint.Host = "YOUR_HTTP3_HOST" // any public host that serves HTTP/3 let parameters = NWParameters(quic: NWProtocolQUIC.Options(alpn: ["h3"])) // Remove these four lines to test with the system PAC instead. let privacy = NWParameters.PrivacyContext(description: "socks5-quic") privacy.proxyConfigurations = [ ProxyConfiguration(socksv5Proxy: .hostPort(host: "127.0.0.1", port: 1099)) // nothing listens on 1099 ] parameters.setPrivacyContext(privacy) let connection = NWConnection(host: host, port: 443, using: parameters) connection.stateUpdateHandler = { state in if case .ready = state { // Prints the origin's own address. With NWParameters.tls instead of QUIC, // the same proxy configuration leaves the connection in .waiting (ECONNREFUSED). print(connection.currentPath?.remoteEndpoint as Any) } } connection.start(queue: .main) I filed this as FB24760235 on 09/13/2026 and haven't had a response, so I'd like to ask here: Is it intended that a QUIC NWConnection ignores both the system PAC and proxyConfigurations? If so, how can an app find out that a connection went direct? And shouldn't a connection that can't honor the configured proxy fail rather than bypass it? Is UDP ASSOCIATE support planned for the system SOCKS5 client, so that QUIC and other UDP traffic can follow a SOCKS5 proxy the way TCP does? Thanks!
Replies
1
Boosts
0
Views
281
Activity
11h
Unexplained behavioural changes in BSD sockets on macos 26.6.x and 27
We have started seeing some unexplained behavioural differences in the BSD socket APIs on macos 26.6.x and macos 27. On a different front, there also seems to be some changes in the ptrace area for PT_DETACH. Historically, the release notes of macos don't include any mention of such changes. And unfortunately, prior experience of filing feedback assistant issues too hasn't been very motivating due to lack of any response on those tickets. These forums have been very helpful in trying to understand some of these changes, and I plan to raise separate topics for the issues shortly. In the past, the other useful option I have used is reading up the kernel sources published at https://opensource.apple.com/releases/. But there hasn't been any updates for macos 26.6 or macos 27. It will be very useful if macos 26.6 and 27 releases are published there. That will help expedite investigating some of these failures. BSD socket APIs in the recent releases of macos have seen several issues (feedback assistant issues have been filed). The implications of these failures is that we (in OpenJDK) have had to disable several tests on recent versions of macos which has reduced the test coverage and reliability of these very primitive networking APIs on this platform.
Replies
5
Boosts
0
Views
225
Activity
2d
Dual-stack UDP socket bound to port 0 can get a port already in use on 127.0.0.1 (FB25058707)
I filed FB25058707 and wanted to make sure it reaches the right people, because it causes silent datagram loss that's hard to trace. On macOS, when a dual-stack UDP socket (AF_INET6 with IPV6_V6ONLY=0) binds [::]:0, the kernel sometimes gives it a port that an AF_INET socket already has bound to 127.0.0.1. Datagrams sent to 127.0.0.1 on that port then go to the AF_INET socket, so the dual-stack socket never receives them. An explicit bind of the same socket to that port fails with EADDRINUSE; only port-0 assignment hands it out. This program binds 1000 AF_INET sockets to 127.0.0.1:0, then binds dual-stack sockets to [::]:0 and checks where a datagram to 127.0.0.1:port lands whenever the port is already held. It's loopback only and runs in a few seconds: /* * A dual-stack UDP socket (AF_INET6, IPV6_V6ONLY=0) bound to [::]:0 can be * assigned a port already bound by an AF_INET socket on 127.0.0.1. Datagrams * to 127.0.0.1:port then reach the AF_INET socket, not the dual-stack one. * Loopback only. Build: cc -O2 -o dualstack_port0 dualstack_port0.c */ #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #define HELD 1000 #define TRIALS 2000 static int held[65536]; static void die(const char *what) { perror(what); exit(1); } static int port_of(int s) { struct sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &len) != 0) die("getsockname"); if (ss.ss_family == AF_INET) return ntohs(((struct sockaddr_in *)&ss)->sin_port); return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); } static int bind_v4(in_addr_t addr) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket AF_INET"); struct sockaddr_in sin = { .sin_len = sizeof(sin), .sin_family = AF_INET, .sin_addr.s_addr = addr }; if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) die("bind AF_INET"); return s; } static int bind_dual(void) { int s = socket(AF_INET6, SOCK_DGRAM, 0), off = 0; if (s < 0) die("socket AF_INET6"); if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) != 0) die("IPV6_V6ONLY"); struct sockaddr_in6 sin6 = { .sin6_len = sizeof(sin6), .sin6_family = AF_INET6, .sin6_addr = in6addr_any }; if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) die("bind AF_INET6"); return s; } /* Returns 1 if s receives token within 100ms, skipping other datagrams. */ static int got(int s, const char *token) { struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 }; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) die("SO_RCVTIMEO"); char buf[64]; for (;;) { ssize_t n = recv(s, buf, sizeof(buf) - 1, 0); if (n < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; die("recv"); } buf[n] = 0; if (strcmp(buf, token) == 0) return 1; } } int main(void) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) die("getrlimit"); rl.rlim_cur = rl.rlim_max < 4096 ? rl.rlim_max : 4096; if (setrlimit(RLIMIT_NOFILE, &rl) != 0) die("setrlimit"); memset(held, -1, sizeof(held)); for (int i = 0; i < HELD;) { int s = bind_v4(htonl(INADDR_LOOPBACK)), p = port_of(s); if (held[p] >= 0) { close(s); continue; } held[p] = s; i++; } int sender = bind_v4(htonl(INADDR_LOOPBACK)); for (int dual = 1; dual >= 0; dual--) { int collisions = 0, to_held = 0, to_wild = 0; for (int i = 0; i < TRIALS; i++) { int w = dual ? bind_dual() : bind_v4(htonl(INADDR_ANY)), p = port_of(w); if (held[p] >= 0) { collisions++; char token[32]; snprintf(token, sizeof(token), "%d-%d", dual, i); struct sockaddr_in to = { .sin_len = sizeof(to), .sin_family = AF_INET, .sin_port = htons(p), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) }; if (sendto(sender, token, strlen(token), 0, (struct sockaddr *)&to, sizeof(to)) < 0) die("sendto"); to_held += got(held[p], token); to_wild += got(w, token); } close(w); } printf("%s: %d/%d wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket %d times, the wildcard socket %d times\n", dual ? "AF_INET6 V6ONLY=0 [::]:0" : "AF_INET 0.0.0.0:0 ", collisions, TRIALS, to_held, to_wild); } return 0; } On macOS 27.0 (26A428): AF_INET6 V6ONLY=0 [::]:0: 122/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 122 times, the wildcard socket 0 times AF_INET 0.0.0.0:0 : 0/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 0 times, the wildcard socket 0 times macOS 15.8.1 x86_64 gives the same pattern, and a Go version of the test reproduces on 15.7.9 and 26.6.2 as well. FreeBSD 15.1 gives 0/2000 with a dual-stack socket. From the public XNU source (xnu-12377.121.6), in6_pcbsetport checks candidate ports with in6_pcblookup_local, which skips PCBs without INP_IPV6, while in6_pcbbind does an IPv4 PCB lookup for dual-stack wildcard binds. That would explain why an explicit bind is refused but port 0 isn't. This is the cause of the long-standing Go issue golang/go#67226, since Go's net.ListenUDP("udp", 0.0.0.0:0) creates exactly this socket, and of intermittent failures in QUIC client tests. Using an AF_INET socket for IPv4-only traffic avoids it, but there's no workaround for a socket that needs both families on one port.
Replies
2
Boosts
0
Views
156
Activity
3d
macos 27 - EDOM error from setsockopt() for SO_LINGER socket option for values greater than 32767
On macos 27, there appears to be a change in the setsockopt() implementation for the SO_LINGER option. It looks like the implementation now imposes a different maximum limit on the value that is accepted for linger. Consider the trivial attached C program. Rename it from main.c.txt to main.c. Compiling it (using clang main.c) and running it (using ./a.out), on older versions of macos (like 26.x), it returns: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 SUCCESS - set SO_LINGER to value 32768 SUCCESS - set SO_LINGER to value 65535 SUCCESS - set SO_LINGER to value 65536 SUCCESS - set SO_LINGER to value 65578 However, on macos 27, this now fails with EDOM error ("Numerical argument out of domain") for values greater than 32767: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 FAILURE - failed to set SO_LINGER to value 32768, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65535, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65536, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65578, reason: Numerical argument out of domain I'm guessing this is an intentional change, but I wanted to confirm nonetheless. Should the documentation of SO_LINGER and SO_LINGER_SEC socket options, in man setsockopt, mention the acceptable value range for them? main.c.txt
Replies
2
Boosts
0
Views
156
Activity
6d
macos 27 - unexpected/new errno from BSD socket connect() when pending connections exceed backlog
Please consider the trivial C program attached to this thread. The code creates a socket() and listen()s for connections, but (intentionally) doesn't accept() the connections. The listen() is done using a small backlog (of 1). This test then does several connect() attempts and expects that the connect() attempts will accumulate in the pending queue and once the queue exceeds the backlog limit, then as specified in man listen: The backlog parameter defines the maximum length for the queue of pending connections. If a connection request arrives with the queue full, the client may receive an error with an indication of ECONNREFUSED. then the connect() attempt will receive a ECONNREFUSED. However, in macos 27, such a connect() attempt leads to ECONNRESET (Connection reset by peer) instead of ECONNREFUSED. Is this expected? Experiments show that prior versions of macos were returning a ETIMEDOUT for such connect() attempts. If this new error is expected from connect() when the backlog limit has exceeded, should it be specified in the man listen documentation? Rename the attached main.c.txt to main.c. Compiling the attached program on macos 27, using clang main.c and then running ./a.out results in: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- started server at at 127.0.0.1:52753 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - connected connect() attempt 3 - connected connect() attempt 4 - connected connect() attempt 5 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 6 - connected connect() attempt 7 - connected connect() attempt 8 - connected connect() attempt 9 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 10 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 11 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 On a related note, it's unclear why several of the connect() attempts succeeded instead of just 1 of them succeeding. On prior versions of macos, the output of the same program is: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- started server at at 127.0.0.1:52451 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - failed to connect() - Operation timed out connect() attempt 3 - failed to connect() - Operation timed out connect() attempt 4 - failed to connect() - Operation timed out connect() attempt 5 - failed to connect() - Operation timed out connect() attempt 6 - failed to connect() - Operation timed out connect() attempt 7 - failed to connect() - Operation timed out connect() attempt 8 - failed to connect() - Operation timed out connect() attempt 9 - failed to connect() - Operation timed out connect() attempt 10 - failed to connect() - Operation timed out connect() attempt 11 - failed to connect() - Operation timed out and this output is much more understandable and deterministic. main.c.txt
Replies
2
Boosts
0
Views
156
Activity
6d
Out-of-band data returned by recv() and read() on socket bound to non-loopback address even when SO_OOBINLINE is disabled
I've been investigating an issue with the SO_OOBINLINE socket option. When that option is disabled, the expectation is that out-of-band data that is sent on the socket will not be available through the use of read() or recv() calls on that socket. What we have been noticing is that when the socket is bound to a non-loopback address (and the communication is happening over that non-loopback address), then even when SO_OOBINLINE is disabled for the socket, the read()/recv() calls both return the out-of-band data. The issue however isn't reproducible with loopback address, and read()/recv() both correctly exclude the out-of-band data. This issue is only noticed on macos. I have been able to reproduce on macos M1, following version, but the original report which prompted me to look into this was reported on macos x64. My M1 OS version is: sw_vers ProductName: macOS ProductVersion: 14.3.1 BuildVersion: 23D60 Attached is a reproducer (main.c.txt - rename it to main.c after downloading) that I have been able to develop which reproduces this issue on macos. When you compile and run that: ./a.out it binds to a non-loopback address by default and you should see the failure log, resembling: ... ERROR: expected: 1234512345 but received: 12345U12345 To run the same reproducer against loopback address, run it as: ./a.out loopback and that should succeed (i.e. no out-of-band data) with logs resembling: ... SUCCESS: completed successfully, expected: 1234512345, received: 1234512345 Is this a bug in the OS? I would have reported this directly through feedback assistant, but my past few open issues (since more than a year) have not even seen an acknowledgement or a reply, so I decided to check here first. main.c.txt
Replies
8
Boosts
0
Views
1.2k
Activity
1w
URLSession fails with -1009 on physical iPhone 16 Pro Max running iOS 27 beta, works in Simulator
I’m building a SwiftUI app that fetches public JSON data using URLSession.shared. The request works correctly in the iPhone 17 Pro Max Simulator, but fails on my physical iPhone 16 Pro Max running iOS 27 beta. Endpoint: https://api.jolpi.ca/ergast/f1/2026/driverstandings.json?limit=100 Error: NSURLErrorDomain Code=-1009 “The Internet connection appears to be offline.” NWPath: unsatisfied (Denied over Wi-Fi interface) Resolved 0 endpoints in 1ms The device can access the endpoint through Safari, and the same request works in Simulator. VPN, cellular permissions, Wi-Fi changes, and ATS settings have been checked. Could this be an iOS 27 beta networking regression affecting URLSession on physical devices? Are there recommended workarounds or diagnostics?
Replies
1
Boosts
0
Views
704
Activity
1w
How to do line- and message-delimination
I'm trying to write a NWProtocolFramerImplementation class that will be channeled through a Framer wrapper. There are still some parts I need figuring out. For handleOutput(framer: message: messageLength: isComplete), what do the last two parameters do? Does isComplete refer to the end of the current conversation, or the entire connection? Why would we submit a messageLength if the data size should already be implied within message? If I parse by line breaks, is there a way to indicate if the latest line is the last of the current conversation, either input or output?
Replies
1
Boosts
0
Views
145
Activity
1w
Network Interface APIs
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" Network Interface APIs Most developers don’t need to interact directly with network interfaces. If you do, read this post for a summary of the APIs available to you. Before you read this, read Network Interface Concepts. Interface List The standard way to get a list of interfaces and their addresses is getifaddrs. To learn more about this API, see its man page. A network interface has four fundamental attributes: A set of flags — These are packed into a CUnsignedInt. The flags bits are declared in <net/if.h>, starting with IFF_UP. An interface type — See Network Interface Type, below. An interface index — Valid indexes are greater than 0. A BSD interface name. For example, an Ethernet interface might be called en0. The interface name is shared between multiple network interfaces running over a given hardware interface. For example, IPv4 and IPv6 running over that Ethernet interface will both have the name en0. WARNING BSD interface names are not considered API. There’s no guarantee, for example, that an iPhone’s Wi-Fi interface is en0. You can map between the last two using if_indextoname and if_nametoindex. See the if_indextoname man page for details. An interface may also have address information. If present, this always includes the interface address (ifa_addr) and the network mask (ifa_netmask). In addition: Broadcast-capable interfaces (IFF_BROADCAST) have a broadcast address (ifa_broadaddr, which is an alias for ifa_dstaddr). Point-to-point interfaces (IFF_POINTOPOINT) have a destination address (ifa_dstaddr). Calling getifaddrs from Swift is a bit tricky. For an example of this, see QSocket: Interfaces. IP Address List Once you have getifaddrs working, it’s relatively easy to manipulate the results to build a list of just IP addresses, a list of IP addresses for each interface, and so on. QSocket: Interfaces has some Swift snippets that show this. Interface List Updates The interface list can change over time. Hardware interfaces can be added and removed, network interfaces come up and go down, and their addresses can change. It’s best to avoid caching information from getifaddrs. If thats unavoidable, use the kNotifySCNetworkChange Darwin notification to update your cache. For information about registering for Darwin notifications, see the notify man page (in section 3). This notification just tells you that something has changed. It’s up to you to fetch the new interface list and adjust your cache accordingly. You’ll find that this notification is sometimes posted numerous times in rapid succession. To avoid unnecessary thrashing, debounce it. While the Darwin notification API is easy to call from Swift, Swift does not import kNotifySCNetworkChange. To fix that, define that value yourself, calling a C function to get the value: var kNotifySCNetworkChange: UnsafePointer<CChar> { networkChangeNotifyKey() } Here’s what that C function looks like: extern const char * networkChangeNotifyKey(void) { return kNotifySCNetworkChange; } Network Interface Type There are two ways to think about a network interface’s type. Historically there were a wide variety of weird and wonderful types of network interfaces. The following code gets this legacy value for a specific BSD interface name: func legacyTypeForInterfaceNamed(_ name: String) -> UInt8? { var addrList: UnsafeMutablePointer<ifaddrs>? = nil let err = getifaddrs(&addrList) // In theory we could check `errno` here but, honestly, what are gonna // do with that info? guard err >= 0, let first = addrList else { return nil } defer { freeifaddrs(addrList) } return sequence(first: first, next: { $0.pointee.ifa_next }) .compactMap { addr in guard let nameC = addr.pointee.ifa_name, name == String(cString: nameC), let sa = addr.pointee.ifa_addr, sa.pointee.sa_family == AF_LINK, let data = addr.pointee.ifa_data else { return nil } return data.assumingMemoryBound(to: if_data.self).pointee.ifi_type } .first } The values are defined in <net/if_types.h>, starting with IFT_OTHER. However, this value is rarely useful because many interfaces ‘look like’ Ethernet and thus have a type of IFT_ETHER. Network framework has the concept of an interface’s functional type. This is an indication of how the interface fits into the system. There are two ways to get an interface’s functional type: If you’re using Network framework and have an NWInterface value, get the type property. If not, call ioctl with a SIOCGIFFUNCTIONALTYPE request. The return values are defined in <net/if.h>, starting with IFRTYPE_FUNCTIONAL_UNKNOWN. Swift does not import SIOCGIFFUNCTIONALTYPE, so it’s best to write this code in a C: extern uint32_t functionalTypeForInterfaceNamed(const char * name) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return IFRTYPE_FUNCTIONAL_UNKNOWN; } struct ifreq ifr = {}; strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); bool success = ioctl(fd, SIOCGIFFUNCTIONALTYPE, &ifr) >= 0; int junk = close(fd); assert(junk == 0); if ( ! success ) { return IFRTYPE_FUNCTIONAL_UNKNOWN; } return ifr.ifr_ifru.ifru_functional_type; } Finally, TN3158 Resolving Xcode 15 device connection issues documents the SIOCGIFDIRECTLINK flag as a specific way to identify the network interfaces uses by Xcode for device connection traffic. Routing Sockets macOS supports the traditional BSD routine socket interface. See the route man page for details. Note You can access some routing socket functionality via sysctl, and all of this section applies to that as well. Other Apple platforms don’t support routing sockets [1]. On macOS it’s reasonable to use a routing socket to learn about the current state of the networking stack and be notified of changes to that state. Doing this on macOS 27 and later may require you to sign your code with the com.apple.developer.networking.topology-observation entitlement. In Xcode, add the Network Topology Observation capability [2] to your target. This is a restricted entitlement, which means it must be authorised by a provisioning profile. If you’re building a command-line tool, follow the advice in Signing a daemon with a restricted entitlement. Don’t use a routing socket to change the state of the networking stack. Such activities are not supported because macOS maintains its source of truth outside of the kernel, primarily in the System Configuration infrastructure [3]. If you make changes behind the back of this infrastructure then, in the best case, they’ll simply be overwritten at some point in the future, but in the worst case you could trigger stability problems. [1] You may or may not be able to open one, based on the current sandbox setup. Even if you can, that effort is not supported because the declarations required to use the socket, most obviously rt_msghdr, are only present in the macOS SDK. And no, copying declarations from one SDK to another is not supported (-; [2] There’s no link to the docs for this capability because that hasn’t yet landed (r. 181611259). [3] See System Configuration Programming Guidelines for a general introduction this architecture. Revision History 2026-09-23 Added the Routing Sockets section. 2025-12-10 Added info about SIOCGIFDIRECTLINK. 2023-07-19 First posted.
Replies
0
Boosts
0
Views
2.6k
Activity
2w
Appropriate API for measuring device-wide network traffic on iOS
I am developing a consumer iOS app for App Store distribution and would like to confirm the appropriate public API for the following use case. The app needs to measure the amount of network traffic passing through the device over short time intervals, for example once per second or more frequently. The app does not need to inspect packet contents, block or filter traffic, or provide a remote VPN service. It also should not generate dedicated network traffic solely for speed measurement. The goal is only to observe device-wide network traffic volume and convert that information into a simple real-time indicator for the user. I am currently investigating the Network Extension framework. Would NEPacketTunnelProvider be an appropriate API for this use case? If not, is there another supported Network Extension provider or other public iOS API intended for measuring device-wide network traffic in this manner? I would like to choose an architecture that is technically supported by Apple and appropriate for a consumer app distributed through the App Store before beginning implementation.
Replies
1
Boosts
0
Views
261
Activity
2w
iOS app loses Internet access after updates: wifiDenied and native URLSession -1009
Hello, Feedback Assistant report: FB24876147. I develop a Unity-based iOS app. Some customers in mainland China report losing Internet access after an app update, while most installations continue working. We have received similar reports since at least iOS 16, across several years and multiple app releases. Earlier iOS versions are uncertain, and we cannot confirm that all historical occurrences share the same cause. Updates without networking-code changes can be followed by failures. A later update sometimes restores connectivity, but not consistently. Customer-reported recovery attempts: The app's wireless-data permissions appear enabled in Settings. Switching the app's network permission to another setting and back did not help users who reported trying it. Reset Network Settings also did not help users who reported trying it. Some users reported that deleting and reinstalling the app restored connectivity. At least one user reported that deletion and reinstallation did not help. These are customer reports, not controlled tests on our development devices. We would prefer a recovery that preserves local save data. Captured evidence from one affected installation: App version 1.89, build 1; Unity 2022.3.62f3. Device identifier: iPhone18,1; iOS 26.2.1. App in foreground. Capture time: 2026-09-07 13:04:31–13:04:32 UTC. An unfiltered Network.framework default-path monitor reported: status=unsatisfied reason=wifiDenied interface=Wi-Fi UnityWebRequest and a newly created native ephemeral NSURLSession both failed against our public HTTPS origin and Apple's independent test endpoint: https://www.apple.com/library/test/success.html The native requests failed after approximately 1 ms and 3 ms, with NSURLErrorDomain -1009, underlying kCFErrorDomainCFNetwork -1009, and no HTTP response. The native session allowed cellular, expensive and constrained network access, used normal TLS verification, and had waitsForConnectivity=false. It bypassed Unity's reachability precheck. CTCellularData changed from unknown to notRestricted. We understand this does not establish successful cellular connectivity or Wi-Fi permission. Important limitations: The native probes ran inside the same Unity-built process, not a separate standalone native app. The captured measurements demonstrate a Wi-Fi failure. Cellular failures and enabled Settings permissions are customer reports, not independently verified by these measurements. We cannot reliably reproduce the affected state on our development devices and do not have a focused Xcode project that reproduces it. An affected-device sysdiagnose is not yet available. Unity Customer QA reviewed this evidence, assessed it as an iOS network-policy issue rather than a Unity bug, and referred us to Apple. We are seeking Apple's investigation, not presenting that assessment as a confirmed root cause. The Code-Level Support form directed us to these forums because we cannot currently provide a focused reproducer. Questions: Which affected-device diagnostics or logging profiles would help identify why the effective network policy reports wifiDenied? How should we investigate an installation-specific issue when a new minimal app may not reproduce that installation state? Is there a supported, data-preserving recovery or application-side mitigation when permission changes and network resets do not help, and reinstallation is not consistently effective? We have diagnostic screenshots and relevant probe source available. Any customer system logs would be collected with consent and shared privately with Apple, not posted publicly. Thank you.
Replies
1
Boosts
0
Views
208
Activity
2w
macos 26 - socket() syscall causes ENOBUFS "No buffer space available" error
As part of the OpenJDK testing we run several regression tests, including for Java SE networking APIs. These APIs ultimately end up calling BSD socket functions. On macos, starting macos 26, including on recent 26.2 version, we have started seeing some unexplained but consistent exception from one of these BSD socket APIs. We receive a "ENOBUFS" errno (No buffer space available) when trying to construct a socket(). These exact same tests continue to pass on many other older versions of macos (including 15.7.x). After looking into this more, we have been able to narrow this down to a very trivial C code which is as follows (also attached): #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <unistd.h> #include <sys/errno.h> static int create_socket(const int attempt_number) { const int fd = socket(AF_INET6, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "socket creation failed on attempt %d," " due to: %s\n", attempt_number, strerror(errno)); return fd; } return fd; } int main() { const unsigned int num_times = 250000; for (unsigned int i = 1; i <= num_times; i++) { const int fd = create_socket(i); if (fd < 0) { return -1; } close(fd); } fprintf(stderr, "successfully created and closed %d sockets\n", num_times); } The code very trivially creates a socket() and close()s it. It does this repeatedly in a loop for a certain number of iterations. Compiling this as: clang sockbufspaceerr.c -o sockbufspaceerr.o and running it as: ./sockbufspaceerr.o consistently generates an error as follows on macos 26.x: socket creation failed on attempt 160995, due to: No buffer space available The iteration number on which the socket() creation fails varies, but the issue does reproduce. Running the same on older versions of macos doesn't reproduce the issue and the program terminates normally after those many iterations. Looking at the xnu source that is made available for each macos release here https://opensource.apple.com/releases/, I see that for macos 26.x there have been changes in this kernel code and there appears to be some kind of memory accountability code introduced in this code path. However, looking at the reproducer/application code in question, I believe it uses the right set of functions to both create as well as release the resources, so I can't see why this should cause the above error in macos 26.x. Does this look like some issue that needs attention in the macos kernel and should I report it through feedback assitant tool?
Replies
8
Boosts
0
Views
1.6k
Activity
2w
What does Network.MessageProtocol do?
The documentation is pretty much blank. The same thing applies to the root NetworkProtocolOptions protocol. What are ContentType, LegacyMessage, BelowProtocol, Metadata, and ProtocolStorage? I can't determine if I should use these or not.
Replies
1
Boosts
0
Views
199
Activity
2w
Transparent proxy breaks apps on macOS 15.7.8 RC 5
Hello! Users of my app observed behaviour that some apps stopped working after update to 15.7.8 via Beta channel with transparent proxy network extension on. The app receives Protocol not available error, and I see setsockopt SO_FLOW_DIVERT_TOKEN failed [42: Protocol not available] error in Console. To reproduce, create two rules in basic NETransparentProxyProvider: [[NENetworkRule alloc] initWithDestinationNetwork:nil prefix:0 protocol:NENetworkRuleProtocolTCP], [[NENetworkRule alloc] initWithDestinationNetwork:nil prefix:0 protocol:NENetworkRuleProtocolUDP], You may even return NO in handleNewFlow, it does not matter. After that, Safari won't open some sites, and Weather app will work unreliably. Do anyone knows any workaround for this problem? I've also create a relevant FB23788740.
Replies
8
Boosts
0
Views
1.3k
Activity
2w
App rejected for entitlements the app needs
Hi— App review said: The app uses one or more entitlements which do not have matching functionality within the app. Apps should have only the minimum set of entitlements necessary for the app to function properly. Please remove all entitlements that are not needed by the app and submit an updated binary for review, including the following: • com.apple.security.device.camera • com.apple.security.network.server …but my app has a feature that does use the camera (continuity camera for macOS, and a bonjour feature for finding other local app instances, establishing a link, and sending data to other instances. I’ve tried declaring/justifying talking about it in App testing info and in my reply to the reviewer, about how to access the features that require it. do I really not need these entitlements and only seems like I would? do I simply test app scheme Release > no debug executable with fresh sandbox and see if features break? But no declaring these things seems like the opposite of what Apple would want… it seems like explicitly calling out these features makes a lot more sense? this is my first app— thank you
Replies
0
Boosts
0
Views
599
Activity
2w
Does "Connectivity Assist" bypass NEPacketTunnelProvider DNS interception on iOS 27?
We have a NEPacketTunnelProvider extension that intercepts and modifies DNS responses for specific hostnames as part of its normal operation. On iOS 27, we are seeing this interception being intermittently bypassed. Our extension still receives the DNS query, builds a response, and returns it promptly, but the client occasionally proceeds using a different address, presumably the actual DNS resolution result. This behavior does not reproduce on iOS 26 or earlier. The timing in our logs appears to correlate with the new Connectivity Assist feature (Settings → Wi-Fi), which Apple describes as using cellular data alongside Wi-Fi to improve reliability. Our suspicion is that Connectivity Assist may be performing DNS resolution over a cellular path in parallel, outside the tunnel, causing that resolution path to bypass our provider entirely. We have ruled out response timing and response format issues on our side. Varying the speed and format of our responses does not affect the outcome, suggesting that the behavior is occurring at a layer above the tunnel provider. We have the following questions: Does Connectivity Assist perform DNS resolution on a network path that can bypass an active NEPacketTunnelProvider? Is there any API, entitlement, or supported mechanism to disable Connectivity Assist for an app, or to ensure that all DNS resolution is routed through the active tunnel, similar to previous Wi-Fi Assist opt-out capabilities? Would a NEDNSProxyProvider-based DNS proxy be affected in the same way, or does it operate at a layer that Connectivity Assist cannot bypass? Any guidance, references to relevant documentation, WWDC session content, or confirmation of the expected behavior would be greatly appreciated.
Replies
5
Boosts
0
Views
951
Activity
3w