MikroTik RouterOS IPv6 firewall rules

  • Note: This article has been updated to include the change made in RouterOS v7.14 to the UDP traceroute rule in the default config. Specifically, port=33434-33534 has been changed to dst-port=33434-33534.

If you have already configured a MikroTik router before enabling IPv6 functionality, and thus don’t want to apply the entire defconf default configuration/quickset or otherwise just need a set of IPv6 firewall filters, you can copy the default IPv6 firewall rules without losing any current config. You can accomplish this by dumping the contents of the router’s default config script via the terminal.

The default configuration will vary slightly with certain devices, so there isn’t quite a one-size-fits-all firewall script. You may need to expand upon these filters to cover your network’s particular needs, like inter-VLAN routing or VPN access. (I’ll cover these scenarios in future posts.) With this in mind, the defconf firewall configuration (both IPv4 and IPv6) is a well-thought-out, secure and performant starting point for a SOHO network that also takes CPU usage into account. Our only issue here in the context of configuring our IPv6 firewall from scratch is that the firewall is only one portion of the default config. We will copy and apply only the IPv6 firewall section.

To export your device’s defconf script in its entirety, open a terminal in Winbox or an SSH session and enter the following command:

/system default-configuration print file=defaults

This will output the full defconf script contents to a file named defaults.txt. Alternatively, you can print the contents to the console:

/system default-configuration print

Either way, browse through the script and find the IPv6 firewall portion. It will be in a block that starts with the line /ipv6 firewall {, and continues with about 30 lines of firewall rules and address-lists until the closing curly brace. Copy only that section and paste it into the terminal, or as I prefer, into a text editor to format it properly since it will contain now-unnecessary extra whitespace from the original code block it was copied from. After making it a little neater, save it as something like IPv6firewall.rsc and import it.

For a hEX S (RB760iGS) running RouterOS 7.14.1 stable (current version as of 3/25/2024), the IPv6 firewall from defconf will look like this:

/ipv6 firewall {
  address-list add list=bad_ipv6 address=::/128 comment="defconf: unspecified address"
  address-list add list=bad_ipv6 address=::1 comment="defconf: lo"
  address-list add list=bad_ipv6 address=fec0::/10 comment="defconf: site-local"
  address-list add list=bad_ipv6 address=::ffff:0:0/96 comment="defconf: ipv4-mapped"
  address-list add list=bad_ipv6 address=::/96 comment="defconf: ipv4 compat"
  address-list add list=bad_ipv6 address=100::/64 comment="defconf: discard only "
  address-list add list=bad_ipv6 address=2001:db8::/32 comment="defconf: documentation"
  address-list add list=bad_ipv6 address=2001:10::/28 comment="defconf: ORCHID"
  address-list add list=bad_ipv6 address=3ffe::/16 comment="defconf: 6bone"
  filter add chain=input action=accept connection-state=established,related,untracked comment="defconf: accept established,related,untracked"
  filter add chain=input action=drop connection-state=invalid comment="defconf: drop invalid"
  filter add chain=input action=accept protocol=icmpv6 comment="defconf: accept ICMPv6"
  filter add chain=input action=accept protocol=udp dst-port=33434-33534 comment="defconf: accept UDP traceroute"
  filter add chain=input action=accept protocol=udp dst-port=546 src-address=fe80::/10 comment="defconf: accept DHCPv6-Client prefix delegation."
  filter add chain=input action=accept protocol=udp dst-port=500,4500 comment="defconf: accept IKE"
  filter add chain=input action=accept protocol=ipsec-ah comment="defconf: accept ipsec AH"
  filter add chain=input action=accept protocol=ipsec-esp comment="defconf: accept ipsec ESP"
  filter add chain=input action=accept ipsec-policy=in,ipsec comment="defconf: accept all that matches ipsec policy"
  filter add chain=input action=drop in-interface-list=!LAN comment="defconf: drop everything else not coming from LAN"
  filter add chain=forward action=accept connection-state=established,related,untracked comment="defconf: accept established,related,untracked"
  filter add chain=forward action=drop connection-state=invalid comment="defconf: drop invalid"
  filter add chain=forward action=drop src-address-list=bad_ipv6 comment="defconf: drop packets with bad src ipv6"
  filter add chain=forward action=drop dst-address-list=bad_ipv6 comment="defconf: drop packets with bad dst ipv6"
  filter add chain=forward action=drop protocol=icmpv6 hop-limit=equal:1 comment="defconf: rfc4890 drop hop-limit=1"
  filter add chain=forward action=accept protocol=icmpv6 comment="defconf: accept ICMPv6"
  filter add chain=forward action=accept protocol=139 comment="defconf: accept HIP"
  filter add chain=forward action=accept protocol=udp dst-port=500,4500 comment="defconf: accept IKE"
  filter add chain=forward action=accept protocol=ipsec-ah comment="defconf: accept ipsec AH"
  filter add chain=forward action=accept protocol=ipsec-esp comment="defconf: accept ipsec ESP"
  filter add chain=forward action=accept ipsec-policy=in,ipsec comment="defconf: accept all that matches ipsec policy"
  filter add chain=forward action=drop in-interface-list=!LAN comment="defconf: drop everything else not coming from LAN"
}

Note that this RouterOS firewall filter config will accept anything that hasn’t matched a filter by the end of a chain; look closely at the last filter, which drops everything in the forward chain not coming from LAN. Personally I prefer to drop everything and explicitly allow what I need (whitelist style). The config in its current state will allow anything that’s tracked in the forward chain from the local side, for example inter-VLAN connections etc. To create a whitelist style filter chain, edit the last filter to accept from LAN, and add one more new filter at the end to explicitly drop everything, so the last 2 filters now look like this:

  filter add chain=forward action=accept in-interface-list=LAN out-interface-list=WAN comment="Internet access from LAN"
  filter add chain=forward action=drop comment="Drop everything not explicitly allowed" log=yes log-prefix="blocked-not-whitelisted"

Note how I’ve included the log=yes option with a semantic prefix; this will help in future troubleshooting when you inevitably forget to allow something as your network expands.