3C-Meraki-MX-IPv6

IPv6 at Home with Meraki: Less Magic, More Clarity

Why I did this

(Note: public blog — I slightly altered my real public prefix. Structure and lessons are unchanged.)

This started as a practical home office project: turn on IPv6, make it stable, and learn enough to stop treating it like a mysterious cousin of IPv4. It worked, eventually, but not before I learned that most “IPv6 issues” are actually “we’re still thinking IPv4” or “clients have opinions”.


From IPv4 to IPv6: what you expect to see (and what you won’t)

In IPv4, troubleshooting tends to be wonderfully explicit:

  • What’s my IP?
  • What’s my subnet?
  • What’s my default gateway?
  • Can I ping the gateway?

IPv6 keeps the same fundamentals (addressing + default route), but it often looks different.

Link-local gateways are normal

In IPv6 it’s very common that your default route points to a link-local next hop (fe80::/10) rather than a “nice” global address. That does not mean routing is broken.

So instead of “ping the gateway IP”, the IPv6 mental model is:

  • Do I have a global IPv6 address on the client?
  • Do I have a default route (::/0)?
  • Does the default route use a link-local next hop on the correct interface?

Once that clicks, a lot of the perceived “magic” disappears.


Your ISP gave you a /56: you now have ridiculous address space

My ISP provided a prefix shaped like:

  • 2a02:22a0:bbba:7300::/56 (slightly altered)

A /56 is meant to be split into /64s internally:

  • A /56 contains 256 separate /64 networks.
  • Each /64 contains such a huge number of addresses that scarcity is no longer your design constraint.

Best practice: one VLAN = one /64.

The tidy plan: VLAN → /64 mapping (and my first attempt to be clever)

With a prefix like …:7300::/56, you can create:

  • …:7300::/64 through …:73ff::/64

That last byte (00..ff) is essentially your subnet selector. So naturally I thought:

“Let’s map VLAN IDs to /64s in a predictable way.”

For example, mapping VLAN numbers (in hex) into the last byte of the 4th hextet makes it reversible and easy to document:

  • VLAN 20 → …:7314::/64 (20 decimal = 0x14)
  • VLAN 40 → …:7328::/64 (0x28)
  • VLAN 42 → …:732a::/64 (0x2a)
  • VLAN 50 → …:7332::/64 (0x32)
  • VLAN 60 → …:733c::/64 (0x3c)
  • VLAN 172 → …:73ac::/64 (0xac)
  • VLAN 192 → …:73c0::/64 (0xc0)

VLAN 999 doesn’t fit into one byte, so it needs a “specials” slot (e.g., …:73f9::/64) and a line in your documentation.

Plot twist: the mapping didn’t behave as expected (yet)

When I tried to force deterministic /64s per VLAN on the Meraki MX, I ended up at a classic symptom:

  • The MX itself could ping IPv6 destinations ✅
  • Clients behind the MX could not ❌

That’s when your IPv4 reflex whispers: “Firewall!”

It wasn’t firewall.

The practical lesson was:

If Prefix Delegation is working, don’t casually outsmart it.

So I reverted to automatic assignment on the MX, stabilized the environment, and parked the “pretty mapping” for a future deep dive—because stability beats aesthetics.

Meraki MX: boring is beautiful (Prefix Delegation first)

The stable end state for me looked like:

  1. WAN has IPv6
  2. ISP delegates a prefix (commonly DHCPv6-PD)
  3. MX assigns /64 per VLAN automatically
  4. Clients use Router Advertisements + SLAAC

Lesson: Build a stable baseline with automatic prefix/VLAN assignment first. Once it’s boring and reliable, then experiment with deterministic VLAN prefixes—with a rollback plan.

Wi-Fi twist: two SSIDs, same VLAN, different IPv6 behavior

This surprised me: two SSIDs can land in the same VLAN and still behave differently, because SSID-level policy can affect the exact mechanisms IPv6 relies on:

  • Router Advertisements / Solicitations
  • DHCP enforcement that collides with SLAAC expectations
  • splash/captive portal gating
  • client isolation and SSID firewall/policy

Conclusion: “Same VLAN” does not always mean “same client experience”.

If IPv6 differs per SSID, compare SSID settings first (Access Control / Splash / Isolation), not routing.

macOS: “no VPN active” doesn’t mean “no tunnels exist”

After I got the network into a stable state, the most interesting chapter started:

  • iPhone on the SSID: works immediately ✅
  • macOS (Tahoe / “26”): inconsistent ❌

Basics looked fine (global address + default route), but the routing table showed multiple defaults via utun interfaces.

What are utun interfaces?

On macOS, utunX is typically created by:

  • VPN clients
  • security and content filters
  • “threat protection” tools
  • DNS proxies / endpoint security stacks

And importantly: they can exist and influence traffic even without an active VPN tunnel.

Command of the day (Code Block)


netstat -rn -f inet6 | grep default
route -n get -inet6 2001:4860:4860::8888

If macOS chooses utunX as the interface to a real IPv6 destination, you’re no longer debugging Wi-Fi. You’re debugging client plumbing.

The “hidden hands”: Network Extensions + MDM reality

The real “aha” moment was discovering active Network Extensions (e.g., AnyConnect socket filter, NordVPN Shield) even when the UI suggested nothing was “connected”.

This is where these checks are gold:

Command of the day (Code Block)

systemextensionsctl list | egrep -i "network|filter|vpn"
profiles status -type enrollment

If the Mac is MDM-managed (e.g., Intune), app removal isn’t always enough to remove the system extension. Policies can keep extensions present or re-enable them, which can absolutely cause intermittent IPv6 behavior.

IPv6 myths I believed for 30 minutes

  • “If the MX can ping IPv6, the clients should be fine.”Not necessarily, client prefix binding/return path can still be wrong.
  • “The default gateway must be a global address.”No, link-local next hops are normal.
  • “Two SSIDs in the same VLAN are identical.”SSID policy can make them behave very differently.
  • “No VPN active means no tunnels.”macOS: utun says hi.

Troubleshooting checklist (wrap-up)

A) MX can reach IPv6, clients cannot

  • ☐ Client has a global IPv6 from your delegated prefix
  • ☐ Client has a default route (::/0) via a link-local next hop
  • ☐ MX shows delegated prefix and VLANs are actually receiving prefixes (auto mode)
  • ☐ If you forced manual /64s: revert to auto, confirm stability, then revisit deterministic mapping later

B) Same VLAN, different SSID behavior

Compare SSID settings:

  • ☐ Bridge vs NAT/tunneling mode
  • ☐ DHCP enforcement / “Mandatory DHCP” style settings
  • ☐ Splash/captive portal settings
  • ☐ Client isolation and SSID firewall/policy differences

C) macOS flaky, iPhone stable

On the Mac:

  • ☐ ifconfig en0 | grep inet6 → global IPv6 present?
  • ☐ netstat -rn -f inet6 | grep default → utunX defaults present?
  • ☐ route -n get -inet6 <dest> → traffic chooses en0 or utunX?
  • ☐ systemextensionsctl list … → filters active?
  • ☐ profiles status -type enrollment → MDM-managed? If yes, disabling/removal may require IT action

 

Comments are closed.