FIREWALL / IPv6
IPv6.
IPv6 doesn't NAT — every host gets a routable global address. This is great for symmetry and end-to-end connectivity, and bad for accidental security because the "we're hidden behind NAT" assumption goes away. The rules below re-establish a one-way membrane between WAN and LAN at the firewall layer instead.
IPv6 firewall is in different places on v6 vs v7
RouterOS v6 ships IPv6 as a separate package (ipv6). The command tree lives at /ipv6 firewall filter with space-separated paths.
If /ipv6 firewall filter doesn't exist, the package isn't installed: /system package print and enable it via /system package enable ipv6, then reboot.
RouterOS v7 has IPv6 integrated. The command tree is /ipv6/firewall/filter with slash-separated paths and matchers that line up almost 1:1 with the IPv4 set. No separate package, nothing to enable.
Input chain (IPv6)
Mirrors the IPv4 input chain with two
differences: icmpv6 replaces icmp and is
mandatory not just useful (Neighbor Discovery, MLD, PMTUD all
travel over ICMPv6 — block it and IPv6 stops working), and the loopback
address is ::1 not 127.0.0.1.
# IPv6 input chain (RouterOS v6 — separate ipv6 package)
/ipv6 firewall filter
add chain=input action=accept connection-state=established,related,untracked \
comment="mtkf6: accept established/related/untracked"
add chain=input action=drop connection-state=invalid \
comment="mtkf6: drop invalid"
add chain=input action=accept protocol=icmpv6 \
comment="mtkf6: accept icmpv6 (RFC 4890 mandatory types)"
add chain=input action=accept dst-address=::1 \
comment="mtkf6: accept loopback"
add chain=input action=drop in-interface-list=!LAN \
comment="mtkf6: drop everything not from LAN" # IPv6 input chain (RouterOS v7 — integrated)
/ipv6/firewall/filter
add chain=input action=accept connection-state=established,related,untracked \
comment="mtkf6: accept established/related/untracked"
add chain=input action=drop connection-state=invalid \
comment="mtkf6: drop invalid"
add chain=input action=accept protocol=icmpv6 \
comment="mtkf6: accept icmpv6 (RFC 4890 mandatory types)"
add chain=input action=accept dst-address=::1 \
comment="mtkf6: accept loopback"
add chain=input action=drop in-interface-list=!LAN \
comment="mtkf6: drop everything not from LAN" Forward chain (IPv6)
Simpler than the IPv4 forward chain because there's no
connection-nat-state to track — you don't NAT IPv6 (and if
you do, you're solving a different problem with worse tools). The
catch-all "drop new from WAN" replaces the dst-nat dance.
# IPv6 forward chain (RouterOS v6)
/ipv6 firewall filter
add chain=forward action=accept connection-state=established,related,untracked \
comment="mtkf6: accept established/related/untracked"
add chain=forward action=drop connection-state=invalid \
comment="mtkf6: drop invalid"
add chain=forward action=accept protocol=icmpv6 \
comment="mtkf6: accept icmpv6"
add chain=forward action=drop in-interface-list=WAN \
comment="mtkf6: drop new WAN-ingress" # IPv6 forward chain (RouterOS v7)
/ipv6/firewall/filter
add chain=forward action=accept connection-state=established,related,untracked \
comment="mtkf6: accept established/related/untracked"
add chain=forward action=drop connection-state=invalid \
comment="mtkf6: drop invalid"
add chain=forward action=accept protocol=icmpv6 \
comment="mtkf6: accept icmpv6"
add chain=forward action=drop in-interface-list=WAN \
comment="mtkf6: drop new WAN-ingress" Why ICMPv6 must stay open
Unlike IPv4 ICMP, ICMPv6 carries control-plane traffic that IPv6 cannot function without. Specifically:
- Neighbor Discovery (types 135–136) — IPv6's replacement for ARP. Block it and hosts can't find their next-hop MAC.
- Router Advertisements (type 134) — how clients learn the prefix and default route on a SLAAC network.
- Path MTU Discovery (type 2 "Packet too big") — IPv6 routers don't fragment, so PMTUD is the only way to negotiate MTU.
If you want to be more surgical than the blanket protocol=icmpv6
accept, RFC 4890 lists which types are required and which are safe
to drop on the public-facing interface. We use the blanket form because
the per-type rule list is long and the operational risk of getting it
wrong outweighs the marginal security gain.
When you'd want to deviate
- Server with public IPv6 services. Add specific
action=acceptrules for the listening ports (e.g.protocol=tcp dst-port=443) above the catch-all drop. Don't drop the catch-all — keep it. - IPv6 ULA-only network. If you're routing
fd00::/8internally and not delegating a public prefix to LAN clients, the WAN-drop rule is still appropriate (you may have a WAN with a public prefix even if clients don't use it).
References
- RFC 4890 — Recommendations for Filtering ICMPv6 Messages in Firewalls
- MikroTik wiki: Manual:IPv6/Firewall
- MikroTik forum thread on hAP ax² IPv6 hardware-offload status (FastTrack on IPv6 is v7-only and board-dependent)