This is an English translation of the Japanese blog post from the RubyKaigi NOC team, primarily written by @hanazuki. This translation is done by @sorah also from the team, prepared for the IETF community and broader audience interested in IPv6-mostly network deployments.
The RubyKaigi NOC team is providing Wi-Fi at conferences on the Ruby programming language in Japan, including RubyKaigi 2025 and Kaigi on Rails 2025. Starting this year, we began experimenting1 IPv6-mostly networks instead of traditional IPv4/IPv6 dual-stack networks.
At RubyKaigi 2025 held in April, we encountered interoperability issues with Apple devices2. Following the conference, we conducted additional tests to diagnose these issues and developed workarounds. Apple released macOS 26 Tahoe and iOS 26 in September, shortly before Kaigi on Rails 2025, showing behavioral improvements addressing the discovered issues.
This blog post documents the issues we discovered with macOS 15 Sequoia and iOS 18, the workarounds we implemented, and verifies the behavioral changes in the newly released macOS 26 Tahoe and iOS 26.
In conclusion, the major issues appear to have been resolved in macOS 26 Tahoe and iOS 26. However, to support connectivity without issues for devices on previous releases, we implemented a workaround at Kaigi on Rails 2025, which successfully prevented the issues from occurring. Continue reading for details on the issues and workarounds.
tl;dr
- On our IPv6-mostly Wi-Fi served via Cisco WLC, Apple devices (macOS 15 Sequoia, iOS 18) could lose IPv4 connectivity after ~30 minutes
- We discovered that Apple devices don't respond correctly to unicast Neighbor Solicitations for CLAT addresses; the source address in NA is set to a link-local address instead. This causes entries to expire from WLC's Neighbor Binding table
- The issue was mitigated by increasing binding lifetime. We also verified that a fix was delivered in the latest macOS/iOS releases (macOS 26 Tahoe and iOS 26)
Recap: What is IPv6-mostly Network?
An IPv6-mostly network encourages supported devices to use IPv6-only mode, while providing IPv4 connectivity using NAT64 with CLAT. This network still acts as a traditional IPv4/IPv6 dual-stack network for unsupported devices, ensuring backward compatibility.
Furthermore, using CLAT instead of DNS64 provides better compatibility for delivering IPv4 connectivity over an IPv6 network. In short, CLAT locally transforms IPv4 packets into IPv6, letting applications use IPv4-only APIs, including direct IPv4 addresses, whereas DNS64 requires native IPv6 support. This methodology is battle-tested on many mobile networks as 464XLAT.
Technically, when a DHCPv4 server detects CLAT support via RFC 8925, it can withhold an IPv4 address assignment. Instead, the client discovers PREF643 through RFC 8781 (via RA options) or RFC 7050 (via DNS), enabling CLAT on the device. These devices use only IPv6 connectivity for network transport, with IPv4 traffic translated through the network's PLAT using the discovered PREF64 prefix.
Enabling IPv6-mostly is useful for addressing IPv4 private address exhaustion, reducing IPv4 network management scope, and facilitating migration to IPv4-as-a-Service architectures.
No response for Unicast Neighbor Solicitations to its CLAT address
The first issue we discovered was when we provided IPv6-mostly Wi-Fi at RubyKaigi 2025: Apple devices would lose connectivity to IPv4 hosts after some time; typically around 30 minutes, though timing varied. Since the issue didn't reproduce on wired connections, and we were using Cisco Mobility Express in our test environment whilst our production network uses a dedicated Cisco WLC, we suspected this might be a compatibility issue between Apple's CLAT implementation and Cisco WLC.
Initial test via wired network
After returning home from RubyKaigi in April, we conducted tests using the same Cisco WLC model used in production to diagnose the issue.
In summary, our initial investigation revealed that macOS 15 Sequoia did not respond with Neighbor Advertisement (NA) to unicast Neighbor Solicitation (NS) messages sent to the CLAT IP address; the address marked as clat46 in ifconfig output.
However, it responds normally to multicast NS messages. Therefore, even if it fails to respond to unicast NS from the router and gets removed from the neighbor cache, it will respond to subsequent multicast NS, so in most environments it might appear to work without issues (though there may be slight delays).
To isolate the issue from potential Wi-Fi layer complications, we recorded NS/NA exchanges with the router (3560-CX) and MacBook connected via wired Ethernet:
en8: flags=89e3<UP,BROADCAST,SMART,RUNNING,NOARP,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=404<VLAN_MTU,CHANNEL_IO>
ether c8:a3:62:00:67:74
inet6 fe80::1e:79e8:6ce7:f060%en8 prefixlen 64 secured scopeid 0x14
inet6 2001:df0:8500:ca31:1c20:bd02:b146:2ddc prefixlen 64 autoconf secured
inet6 2001:df0:8500:ca31:a00d:5968:8e62:f5e8 prefixlen 64 autoconf temporary
inet 192.0.0.2 netmask 0xffffffff broadcast 192.0.0.2
inet6 2001:df0:8500:ca31:148a:b2a:d796:4886 prefixlen 64 clat46
nat64 prefix 2001:df0:8500:ca64:a9:8200:: prefixlen 96
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
status: active
| No. | Time | Source | Destination | Protocol | Length | Info |
|---|---|---|---|---|---|---|
| 83048 | 13:55:05.310318 | fe80::66c:9dff:fe31:41c6 | 2001:df0:8500:ca31:a80d:5968:8e62:f5e9 | ICMPv6 | 86 | Neighbor Solicitation for 2001:df0:8500:ca31:a80d:5968:8e62:f5e9 from 04:6c:9d:31:41:c6 |
| 83049 | 13:55:05.317197 | fe80::de:79e8:6c9f:b968 | fe80::66c:9dff:fe31:41c6 | ICMPv6 | 78 | Neighbor Advertisement 2001:df0:8500:ca31:a80d:5968:8e62:f5e9 (sol) |
| 83087 | 13:55:08.371306 | fe80::66c:9dff:fe31:41c6 | 2001:df0:8500:ca31:148a:d2a:d796:4806 | ICMPv6 | 86 | Neighbor Solicitation for 2001:df0:8500:ca31:148a:d2a:d796:4806 from 04:6c:9d:31:41:c6 |
| 83102 | 13:55:09.462731 | fe80::66c:9dff:fe31:41c6 | 2001:df0:8500:ca31:148a:d2a:d796:4806 | ICMPv6 | 86 | Neighbor Solicitation for 2001:df0:8500:ca31:148a:d2a:d796:4806 from 04:6c:9d:31:41:c6 |
| 83108 | 13:55:10.514967 | fe80::66c:9dff:fe31:41c6 | 2001:df0:8500:ca31:148a:d2a:d796:4806 | ICMPv6 | 86 | Neighbor Solicitation for 2001:df0:8500:ca31:148a:d2a:d796:4806 from 04:6c:9d:31:41:c6 |
| 83115 | 13:55:11.625881 | fe80::66c:9dff:fe31:41c6 | ff02::1:ff96:4806 | ICMPv6 | 86 | Neighbor Solicitation for 2001:df0:8500:ca31:148a:d2a:d796:4806 from 04:6c:9d:31:41:c6 |
| 83116 | 13:55:11.626185 | fe80::de:79e8:6c9f:b968 | fe80::66c:9dff:fe31:41c6 | ICMPv6 | 78 | Neighbor Advertisement 2001:df0:8500:ca31:148a:d2a:d796:4806 (sol, ovr) is at c8:a3:62:08:ab:e0 |
This capture shows macOS Sequoia not responding to unicast NS sent from the router to its CLAT address. It responds with NA to unicast NS for temporary address sent just before, and to multicast NS sent immediately after.
Follow-up test on the production gear
During the setup day of Kaigi on Rails 2025, we performed additional checks and tests of the behavior of Neighbor Solicitations for CLAT addresses on several macOS and iOS versions.
While the earlier results on our test networks indicated no response to unicast Neighbor Solicitations, the production network showed different behavior. This time we detected solicited Neighbor Advertisements, though their behavior was as follows:4
- macOS 15.5, macOS 15.6.1, iOS 18.5: The target address in the solicited Neighbor Advertisement content is the CLAT address (GUA), but the source in the IPv6 header is different; a link-local address was set instead!
- Update: There is an information that macOS 26 still sending lladdr as a source address of solicited NA packets, so I am double checking my investigation log to verify whether this observation was correct and are going to update later.
- macOS 26, iOS 26: Both the target address in the solicited Neighbor Advertisement and the source in the IPv6 header are the CLAT address
This difference might be related to the test environment: post-RubyKaigi tests used Cisco Catalyst 3560-CX as the first hop router, while production used Juniper EX3400. C3560-CX may be dropping solicited NA packets with mismatched source addresses.
The behavior in macOS Sequoia (macOS 15) and iOS 18, where the source address doesn't match the target address, appears ambiguous when roughly evaluated against RFC 4861 and related standards.5 However, since this behavior changed in iOS 26 and macOS 26 Tahoe to use matching addresses, we believe some interoperability improvement or bug fix was implemented.
What happens if solicited Neighbor Advertisement is broken
Cisco WLC has a feature called Neighbor Discovery Proxy that snoops NS/NA and responds on behalf of clients. This feature is typically enabled by default to reduce multicast frames transmitted over Wi-Fi. When a Cisco WLC sees an NA, it records it in its Neighbor Binding table. If a matching NS arrives within Reachable Lifetime seconds after receiving an NA, it drops the NS and responds with NA on their behalf. If a unicast NS arrives after (Reachable Lifetime) seconds but within (Stale Lifetime) seconds, it forwards the NS to the client. Normally, the WLC receives the NA that the client returns in response to this unicast NS, and the Neighbor Binding timer is updated. Multicast NS is not forwarded by default.
However, since macOS Sequoia doesn't respond correctly to unicast NS for CLAT addresses (at least not in a way compatible with Cisco WLC), the Neighbor Binding timer for the CLAT address isn't updated. Consequently, the entry expires from both the WLC's Neighbor Binding table and the next-hop router's neighbor cache. As a result, packets toward upstream arrive, but packets toward downstream do not.
Since WLC always sends unicast NS when probing clients, the connectivity issue cannot be resolved automatically. In contrast, on wired networks without WLC, routers might eventually fall back to sending multicast NS after unicast attempts fail, potentially receiving responses and restoring connectivity.
Mitigations
After the initial test, we considered two mitigation strategies for this issue. Either one is sufficient, and we chose the strategy #1 (increasing lifetime) for Kaigi on Rails 2025.
- Increase lifetime: By setting a larger Reachable Lifetime for WLC's Neighbor Binding, you can extend the period during which WLC responds to NS from adjacent routers on behalf of Wi-Fi clients. If this is longer than the duration that the clients maintain their connection, connectivity can be maintained.
- You need to be aware of the maximum value that can be set for Neighbor Binding entries when determining the value, e.g., 36,000 for Cisco 3504.
- Forward multicast NS packets to Wi-Fi: Allowing Unknown Address Multicast NS Forwarding on WLC causes it to forward multicast NS that doesn't match its Neighbor Binding to clients. Since the CLAT on Apple devices does respond to multicast NS, NA is recorded in WLC's Neighbor Binding, and WLC will respond on behalf thereafter.
- This solution could be problematic, as multicast frames consume Wi-Fi airtime. Particularly, the RubyKaigi network doesn't have an IPv6 stateful firewall, so large amounts of multicast NS could be generated by address scanning from the Internet.
It is worth noting that draft-ietf-v6ops-claton-08 mentions implementations showing different behavior between CLAT addresses and regular IPv6 addresses; the macOS issue documented here might be known in those circles, but we couldn't find documentation about its interaction with wireless appliances. This appears to have been fixed in macOS 26 Tahoe and iOS 26, as demonstrated in the follow-up test results above.
Result with mitigation and new macOS/iOS release
We ran the IPv6-mostly experiment again with the above mitigation at Kaigi on Rails 2025 held on Sep 26-27. The issue was no longer observed, with help of new macOS/iOS releases.
However, we observed a different issue where DHCPv4 and RA packets could be dropped at the WLC for some clients, which we couldn't resolve during the conference. We're unsure if this new issue is related to the mitigation. Nevertheless, we plan to remove this mitigation following macOS/iOS 27 release, expecting an increased adoption rate of macOS/iOS 26 by then. We aim to remove it at or after RubyKaigi 2027.
CLAT activated with DNS can get disabled after sleep
Another issue we encountered was related to RFC 7050, a mechanism that allows client devices connected to networks with NAT64 to recognize PREF64 using DNS. In environments using RFC 7050, we've confirmed that when some timer expires while a MacBook is sleeping, CLAT might stop functioning afterward. This state can be verified using commands like ifconfig to confirm that CLAT is disabled.
We tried various approaches like extending the TTL of ipv4only.arpa. records, but couldn't find a workaround. Disconnecting and reconnecting to Wi-Fi restores functionality.
Normal state (CLAT is enabled and visible):
% ifconfig en0
en0: flags=89e3<UP,BROADCAST,SMART,RUNNING,NOARP,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether f2:22:7b:94:99:c7
inet6 fe80::41:4a0c:9034:bb5c%en0 prefixlen 64 secured scopeid 0xb
inet6 2001:df0:8500:ca31:66:bc01:e0a2:a774 prefixlen 64 autoconf secured
inet6 2001:df0:8500:ca31:2034:f93d:238:a003 prefixlen 64 autoconf temporary
inet 192.0.0.2 netmask 0xffffffff broadcast 192.0.0.2
inet6 2001:df0:8500:ca31:1863:bba2:38de:72fe prefixlen 64 clat46
nat64 prefix 2001:df0:8500:ca64:a9:8200:: prefixlen 96
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
Abnormal state; CLAT disabled after sleep:
% ifconfig en0
en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether f2:22:7b:94:99:c7
inet6 fe80::41:4a0c:9034:bb5c%en0 prefixlen 64 secured scopeid 0xb
inet6 2001:df0:8500:ca31:66:bc01:e0a2:a774 prefixlen 64 autoconf secured
inet6 2001:df0:8500:ca31:2034:f93d:238:a003 prefixlen 64 autoconf temporary
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
While we encountered this issue in test environment during initial implementation, our production network migrated to RFC 8781-compliant routers (RA-based PREF64 discovery), which eliminated the need for RFC 7050 (DNS-based) entirely and avoided this sleep-related issue.
Therefore, we did not retest this specific issue on macOS 26 Tahoe since the production network worked without problems.
As discussed in RFC 9872, RFC 8781 is the preferred approach. RFC 7050 has many shortcomings and should be considered a transitional technology until RFC 8781 becomes widespread in router implementations.
Other Reported Issues
macOS (and iOS) had other reported issues6 as follows:
- Leaking the CLAT-internal IPv4 address
192.0.0.2to the network- This address is assigned to the CLAT interface for internal translation purposes and should never appear on the network
- Cisco WLC can detect this behavior as an abuse and it can result in deassociation. We had to disable IP Theft or Reuse detection in Client Exclusion settings:
config wps client-exclusion ip-theft disable
- Being unable to connect to IPv4 hosts when using the ssh command with the "-4" option.
- No response for ICMPv6 Echo Requests to a CLAT address
These issues were reproducible in macOS Sequoia but appear to have been fixed in macOS 26 Tahoe. The remaining issue is that a traceroute to IPv4 hosts cannot receive ICMP errors from intermediate hosts.
Our deployment and gears
Production equipment is as follows:
- First-hop router: Juniper EX3400 (Junos 24.2R1-S2.5)
- WLC: Cisco 3504 (AIR-CT3504-K9, 8.10.196.0)
- DHCPv4: Kea 3.1.1
- PLAT: Ubuntu box. Combining the followings to implement as a working PLAT:
- Stateful NAT66: Linux nftables
- Stateless NAT64: https://github.com/sorah/xlat
- Details on blog post (Japanese).
Stats
Stats taken from our most recent conference, Kaigi on Rails 2025.
- Approx 900 clients
- 80% of IPv4 traffic traverses NAT64 boxes
- roughly 50-60% of traffic is IPv6 native

Outro
This post documents the interoperability issues we discovered with Apple's CLAT implementation in an IPv6-mostly network using Cisco WLC. We describe the issues found at our first deployment in April, the investigation and mitigation strategies developed over the following months, and the results from our second deployment in September. We hope this helps those planning to deploy IPv6-mostly networks.
Authors: @hanazuki, @sorah on behalf of RubyKaigi NOC and AS59128 KMC
-
At RubyKaigi NOC, we are keen to implement the latest standards as enthusiasts, and try not to be repetitive at every conference Wi-Fi we run. ↩
-
Originally reported at this blog post (Japanese) ↩
-
The IPv6 prefix used for NAT from IPv4 to IPv6, defined in RFC 6146 ↩
-
This might be related to different verification methods or means of sending Neighbor Solicitations ↩
-
If you found or know specific language in standards indicating whether this behavior is problematic, please let me know ↩