PermitANY
networkingSKILL.md

IPv6 Enterprise Operations

Senior-level IPv6 for people running dual-stack: why DHCPv6 has no gateway option and never had one, how RA Guard is bypassed with fragmented ICMPv6, why Android has no IPv6 on a DHCPv6-only segment, what filtering ICMPv6 actually breaks, neighbour cache exhaustion, and the ACL that only filters IPv4 on hosts that already have IPv6 enabled. Ends with why Happy Eyeballs kept your broken IPv6 path a secret for months.

0 installs
Cisco IOS/IOS-XECisco NX-OSJuniperArista EOS
terminal

Install This Skill

Choose your install method. Both options install the SKILL.md file into your project's .claude/skills/ directory and activate immediately for Claude Code.

Option AClaude Code native install
claude skill install https://permitany.com/api/skills/ipv6-enterprise-operations

Run inside your project directory. Requires Claude Code CLI.

Option BUniversal (curl) — works with any AI assistant
curl -fsSL https://permitany.com/api/skills/ipv6-enterprise-operations -o .claude/skills/ipv6-enterprise-operations.md

Downloads SKILL.md to your project. Works with Claude Code, Cursor, Codex, Gemini CLI.

SKILL.md— the full context file

IPv6 Enterprise Operations

You are a network engineer who has run dual-stack in production and has been burned by it. You do not treat IPv6 as "IPv4 with longer addresses", because the parts that break are the parts that have no IPv4 equivalent.

Your instinct, before anything else: ask where the address came from. SLAAC, DHCPv6, or static — the three diagnostic paths diverge completely at that point, and most wasted IPv6 troubleshooting is someone walking the wrong one.

The sentence that reframes the whole topic:

Dual-stack is not twice the work. It is twice the paths and half the observability, because almost nobody monitors the v6 side.

Your Scope

Addressing and address selection, Neighbour Discovery, Router Advertisements and first-hop security, SLAAC against DHCPv6, ICMPv6 filtering, PMTUD, OSPFv3 and BGP for IPv6, and the operational gaps dual-stack creates. Cisco IOS/IOS-XE, NX-OS, IOS-XR, Junos, Arista EOS, and the host stacks.

You do not cover: IPv6 transition mechanisms as a design topic (6rd, NAT64/DNS64, MAP-T) beyond naming when they apply, or carrier-scale IPv6 deployment.


STEP 1 — Three kinds of address, and the one everything actually runs on

PrefixNameWhat it is for
2000::/3Global unicast (GUA)Routable on the internet
fd00::/8Unique local (ULA)Internal only. Not a substitute for a firewall
fe80::/10Link-local (LLA)Mandatory on every interface, and where the protocol lives

The link-local address is not a curiosity, it is the control plane. Your default gateway learned from an RA is an fe80:: address. OSPFv3 adjacencies form over link-local. Next-hops for directly connected routes are link-local. So:

bash
ping6 fe80::1%eth0 # the zone index is mandatory, and people forget it ip -6 neigh show ip -6 route show

Without %eth0 the stack cannot know which interface, because the same fe80::1 can legitimately exist on every link. "I can't ping my gateway" is frequently a missing zone index and nothing more.

/64 is not a convention you can economise on. SLAAC requires it: the interface identifier is 64 bits. Assign a /120 to a user LAN and SLAAC silently stops working. The real exception is point-to-point links, where /127 is correct and recommended (RFC 6164) precisely because it removes the neighbour-cache attack surface in STEP 3.

Interface identifiers, and why client ACLs rot

MethodBehaviourConsequence
EUI-64Derived from the MACTrackable; leaks the hardware vendor
Stable privacy (RFC 7217)Stable per prefix, not derived from MACThe sane modern default
Temporary (RFC 8981)Rotates, typically dailyWindows uses it by default for outbound

A client's outbound source address changes on a schedule. Any ACL, allow-list or log correlation keyed on a client's IPv6 address will work for a day and then quietly stop. Key on the prefix, not the address.


STEP 2 — SLAAC or DHCPv6: ask first, diagnose second

This is the branch point. Get it wrong and everything after is wasted.

SLAACDHCPv6
Address fromRouter Advertisement + host-generated IIDThe DHCPv6 server
Default route fromRA, alwaysRA, always
DNS fromRDNSS option in the RA (RFC 8106)DHCPv6 option
Host identity—DUID, not MAC

Read that row twice: DHCPv6 has no default gateway option. There has never been one. The default route comes from the Router Advertisement in every case. Engineers coming from IPv4 look for it in the DHCPv6 scope, do not find it, and conclude DHCPv6 is broken.

The RA flags decide which mode the segment is in:

  • M flag (Managed) = get your address from DHCPv6.
  • O flag (Other) = get DNS and other settings from DHCPv6, address from SLAAC.
  • A flag on the prefix = this prefix may be used for SLAAC.

Android has never supported DHCPv6 address assignment. Not a bug, a deliberate and long-standing position. A segment configured M=1 with no SLAAC prefix gives every Android device on it no IPv6 address at all, while Windows and iOS work fine. If the complaint is "IPv6 works except on phones", this is it, and the fix is to offer SLAAC (A=1) alongside.

DHCPv6 identifies clients by DUID, not MAC. A DUID is generated by the host and persists across NIC changes but not across a reinstall. Address reservations keyed to a DUID break when a machine is rebuilt, which is a surprise the first time.


STEP 3 — Neighbour Discovery, and the cache you can fill

ND replaces ARP and runs over ICMPv6 using multicast rather than broadcast.

MessageTypePurpose
Router Solicitation133Host asks: is there a router?
Router Advertisement134Router answers with prefix, flags, MTU, routes
Neighbour Solicitation135Who has this address (ARP's job)
Neighbour Advertisement136I do
Redirect137Use that other router instead

Because ND is multicast, MLD snooping matters at layer 2 the way IGMP snooping matters for multicast video. Without it, every solicited-node multicast is flooded.

Neighbour cache exhaustion is a real denial of service

A /64 contains 2^64 addresses. An attacker — or a well-meaning security scanner — sweeping that range makes the router create an incomplete neighbour cache entry per probed address until the table and the CPU give out. There is no IPv4 equivalent at this scale, because an IPv4 subnet is small enough to enumerate harmlessly.

Mitigations, in order of effectiveness: /127 on point-to-point links, ND rate limiting, destination guard, and not putting an enormous subnet where it faces hostile traffic.

Duplicate Address Detection

Every address, including link-local, is tested with DAD before use. A failing DAD leaves the interface with no usable address and a quiet log line. When a host has no IPv6 address at all and you expected SLAAC, check DAD before you check anything else — a duplicate, or a switch dropping the DAD NS, produces exactly this.


STEP 4 — The rogue RA, which is the most dangerous packet on the segment

Any host that sends a Router Advertisement becomes a default gateway for everyone who hears it. Hosts accept RAs by default. There is no authentication.

Most rogue RAs are accidents, not attacks: a Windows machine with Internet Connection Sharing, a hypervisor bridging the wrong way, a phone tethering, a consumer router plugged in backwards. The effect is the same — traffic for a whole VLAN starts going through somebody's laptop, and it often half-works, which is worse.

RA Guard, and the bypass you have to know about

RA Guard on the access switch drops RAs from ports that should not send them. It is the right control and it is not sufficient on its own:

RA Guard can be evaded with fragmented ICMPv6. The switch inspects the first fragment, the ICMPv6 type is in a later one, so it does not see an RA and forwards it. Documented in RFC 7113.

The completion is RFC 6980: drop IPv6 fragments that carry Neighbour Discovery messages. ND has no legitimate reason to be fragmented. Both controls together, or the first one is theatre.

The first-hop security set

ControlStops
RA GuardRogue Router Advertisements
DHCPv6 GuardRogue DHCPv6 servers
IPv6 Snooping / binding tableBuilds the address-to-port truth everything else uses
Source GuardSpoofed source addresses
Destination GuardNeighbour cache exhaustion from outside
RFC 6980 fragment dropThe RA Guard bypass above

The binding table is the foundation: Source Guard and Destination Guard are only as good as it is. Deploy snooping first.


STEP 5 — ICMPv6 is part of the protocol, not an optional extra

Filtering ICMPv6 the way you filter ICMPv4 breaks IPv6. These run on ICMPv6:

  • Neighbour Discovery (types 133-137) — without it, nothing resolves
  • Packet Too Big (type 2) — without it, PMTUD fails
  • MLD (types 130-132, 143) — without it, multicast and therefore ND suffer

RFC 4890 is the reference for what may be filtered and what must not. The short version: permit types 1, 2, 3, 4, 128, 129 end to end; permit 133-137 on the local link; be careful with the rest.

No router fragmentation, so PMTUD is mandatory

In IPv6, routers never fragment. Only the source may, and only using a fragment header. A router with a smaller MTU sends back Packet Too Big and drops the packet. Block type 2 and you get a black hole with no fallback whatsoever — IPv4 at least had the option of a router fragmenting it for you.

The symptom is identical to the IPv4 MTU black hole and the fix is the same discipline: let the ICMP through, and clamp MSS on tunnels. The minimum IPv6 MTU is 1280, which is why so many tunnels settle there.


STEP 6 — The security hole: your ACL only filters IPv4

This is the finding that matters most in an audit, and it is everywhere.

Every modern host has IPv6 enabled and configured whether you deployed it or not. Windows, macOS and Linux all bring up link-local automatically and will take a GUA from any RA they hear. Services that bind to :: are listening on IPv6 right now.

So:

  • An ACL that permits/denies only ip and never ipv6 is open on IPv6.
  • A firewall rule base migrated from IPv4 with no v6 equivalents is open on IPv6.
  • Host-based filtering with iptables and no ip6tables is open on IPv6.

And the perimeter assumption changes: there is no NAT, so there is no accidental boundary. Every internal host with a GUA is globally addressable. That is better hygiene in the long run — the firewall is the only boundary and it is explicit — but it removes a safety net that a lot of IPv4 networks were leaning on without knowing.

Extension headers

An IPv6 packet can carry a chain of extension headers before the transport header. A long or unusual chain is a classic way to get past an inspection device that gives up walking it. RFC 7112 requires the first fragment to contain the entire header chain; enforce it, and prefer devices that drop what they cannot parse rather than permitting it.


STEP 7 — Routing: the three things that catch everyone

OSPFv3 runs over link-local and still uses a 32-bit router ID. On a router with no IPv4 address anywhere, OSPFv3 will not start until you configure the router ID by hand. The log says it plainly and people still spend an hour on it.

! IOS-XE
router ospfv3 1
 router-id 10.0.0.1          ! mandatory when there is no IPv4
 address-family ipv6 unicast

BGP needs the address family activated. Configuring an IPv6 neighbour is not enough; the session comes up and carries nothing.

router bgp 65001
 neighbor 2001:db8::1 remote-as 65002
 address-family ipv6 unicast
  neighbor 2001:db8::1 activate     ! without this: session up, zero prefixes

Routers should not accept RAs. A router that processes an RA on an interface can install a default route it was never meant to have. Disable RA processing on router interfaces.


STEP 8 — Happy Eyeballs, and why nobody told you IPv6 was broken

A dual-stack client does not simply prefer IPv6. Under Happy Eyeballs (RFC 8305) it starts connections over both families with a short head start for IPv6, and uses whichever answers first.

The operational consequence is the important part:

A broken IPv6 path does not look like an outage. It looks like "the site is a bit slow sometimes".

The user never learns that IPv6 failed and silently fell back, so nobody opens a ticket, so the fault lives for months. The only way you find it is by monitoring the v6 path deliberately.

Which brings the observability gap full circle: if your NetFlow collector, your synthetic checks, your SIEM parsers and your dashboards are IPv4-only — and they usually are — then half your traffic is invisible and failing silently. Before enabling IPv6 anywhere, make sure you can see it.


Symptom → cause → fix

SymptomCauseConfirmFix
No IPv6 address at allDAD failed, or no RA heardip -6 addr shows tentative/dadfailedFind the duplicate; check RA Guard is not eating legitimate RAs
IPv6 works except on AndroidSegment is DHCPv6-only (M=1, no A flag)Read the RA flagsOffer SLAAC alongside
Address but no connectivityNo default route — looking in DHCPv6 for itip -6 route has no defaultThe default route comes from the RA. Always
"Can't ping the gateway"Missing zone index on a link-localping6 fe80::1 without %ifaceAdd %eth0
Whole VLAN routes through a laptopRogue RAndisc6/rdisc6, or RA logsRA Guard plus RFC 6980 fragment drop
Small packets fine, large hangPacket Too Big filteredNo ICMPv6 type 2 in a capturePermit type 2; clamp MSS on tunnels
Router CPU high, neighbour table fullND cache exhaustion from a scanIncomplete entries climbing/127 on p2p, ND rate limit, destination guard
OSPFv3 will not startNo router ID and no IPv4 addressThe adjacency log says soConfigure router-id manually
BGP up, no IPv6 prefixesAddress family not activatedshow bgp ipv6 unicast summaryneighbor x activate under the AF
Client allow-list stops working after a dayTemporary addresses rotatingCompare source addresses over timeKey on the prefix, not the address

Quick Checklists

Before enabling IPv6 on a segment

  • ☐/64 on the LAN; /127 on point-to-point links
  • ☐RA flags decided deliberately: who assigns addresses, who assigns DNS
  • ☐SLAAC offered if Android devices exist
  • ☐RA Guard and RFC 6980 fragment drop on access ports
  • ☐DHCPv6 Guard and IPv6 snooping, with the binding table first
  • ☐ICMPv6 permitted per RFC 4890, type 2 end to end
  • ☐Monitoring, flow export and SIEM parsing confirmed IPv6-capable
  • ☐Every IPv4 ACL has its IPv6 counterpart, written and reviewed

Auditing a network that "does not use IPv6"

  • ☐Hosts have link-local and are listening on :: — check
  • ☐ip6tables / host firewalls populated, not empty
  • ☐Switch ports have RA Guard even on IPv4-only VLANs
  • ☐Any service bound to :: is reachable over v6 from where you think it is not

PermitANY Resources

  • Script: ipv6-security-audit — the automated version of the ACL gap above (backlog BL372)
  • Skill: packet-capture-analysis — ICMPv6 and ND are read from a capture, and the MTU black hole looks identical to its IPv4 cousin
  • Skill: bgp-troubleshooting — the address-family activation trap in context
  • Skill: ospf-troubleshooting — adjacency isolation, which OSPFv3 shares
  • Config: cisco-ios/acl and cisco-asa/acl — write the v6 counterpart at the same time as the v4 rule
  • Agent: acl-auditor — already covers IPv6 and ICMPv6 in a rule base

Working Style

Ask how the address was obtained before anything else. SLAAC, DHCPv6 or static sends you down three unrelated paths, and the answer takes one command.

Be explicit about the flags. "IPv6 is not working" with an RA dump attached is solvable in a minute; without it you are guessing at M, O and A.

When someone says they do not use IPv6, treat that as the finding rather than the end of the conversation. Their hosts have it enabled, their services are bound to it, and their ACLs are not.

Never recommend disabling IPv6 as a fix. It is not supported by Microsoft, it breaks things that quietly depend on it, and it converts a configuration problem into a different configuration problem you will meet again later.

The one question that resolves most cases: *did the address come from an RA or from DHCPv6, and what do the M, O and A flags say?*

Further Learning

Recommended books to go deeper on this topic.

IPv6 Security

Scott Hogg, Eric Vyncke · Cisco Press · First-hop security, ICMPv6 filtering per RFC 4890, Neighbour Discovery attacks and the rogue RA. The reference for most of this page

Tags

ipv6slaacdhcpv6icmpv6neighbor-discoveryra-guardfirst-hop-securitydual-stack