A simple IPv6 firewall for the Mikrotik

Once my little Mikrotik RB951-2n was working properly, I decided to give it a proper packet filter. My IPv6 hosts are all quite capable of defending themselves, but a packet filter at the border reduces traffic on the network, plus I wanted to see how Mikrotik did it.

I wanted to stop the Internet getting to the Mikrotik itself, and forward only ICMPv6 and ssh into my network, while not preventing any outbound connections.

This is a pretty minimal approach, but starting small is generally a good idea. The more rules you have the greater the load on your router, and for a very small unit such as the RB951-2n, that can be a real problem. Worst case, large rulesets can slow the delivery of packets. Also, large rulesets are difficult to understand, and therefore harder to create, inspect and modify. Simplicity is itself a security positive. So rulesets should in general be kept as small as possible.

By the way – the input chain controls packets arriving at the router addressed to interfaces actually on the router (any interface on the router, including loopback interfaces). The output chain controls packets leaving the router, sourced from an interface on the router. The forward chain controls packets passing through the router – neither destined for nor sourced from interfaces on the router. It’s possible to create your own chains, too, but that wasn’t needed in this simple ruleset.

Within a given chain, the order of the rules is critical, as they are applied in the order given. If you have a rule that allows everything, followed by a rule that blocks (say) HTTP, then the second rule will never have any effect. Generally speaking, you should have rules that allow specific things, followed by a catch-all rule that blocks everything else. The other approach is to have rules that block specific things, then allow everything else, but this is not as safe.

My first attempt looked like this (note that the default policy on all default chains is “accept”):

/ipv6 firewall filter 
add action=accept chain=forward connection-state=established in-interface=pppoe-out1
add action=accept chain=forward connection-state=related in-interface=pppoe-out1
add action=accept chain=forward in-interface=pppoe-out1 protocol=icmpv6
add action=accept chain=forward dst-port=22 in-interface=pppoe-out1 protocol=tcp 
add action=drop chain=forward in-interface=pppoe-out1 
add action=accept chain=input in-interface=pppoe-out1 protocol=icmpv6 
add action=drop chain=input in-interface=pppoe-out1 
add action=drop chain=input in-interface=ether1-gateway

The above allows established and related packets to be forwarded into my networks, it allows ICMPv6 in, and allows anything into my network on port 22 (ssh). It stops all input to the Mikrotik itself from outside, however, except for ICMPv6. And it allows anything outbound.

Why do I need ICMPv6? For two reasons – firstly, it is essential to the operation of IPv6, or at least the Packet Too Big message is. PMTUD (Path MTU Discovery) needs ICMPv6, and fragmentation will not work without PMTUD. Secondly, echo requests and echo responses (“pings”) are very useful tools when troubleshooting. Fine-grained control of ICMPv6 does make sense in larger contexts, but for a SOHO network, allowing all ICMPv6 is simpler.

My new packet filters seemed to be working well at first, but I found that after a while, IPv6 connectivity would disappear. It wasn’t all connectivity – the PPPoE link still showed “connected” and IPv4 was completely unaffected. To figure out what was going on, I edited the rule that blocked all input on pppoe-out1, changing “drop” to “log”, and bounced the PPPoE link. Seconds later it was clear what my mistake had been – I had forgotten that the router is doing DHCPv6-PD, and the remote end needs to be able to communicate with the router on port 546.

The solution was to add a rule permitting inbound DHCPv6 (UDP on port 546) to the PPPoE interface:

/ipv6 firewall filter
add action=accept chain=forward connection-state=established in-interface=pppoe-out1
add action=accept chain=forward connection-state=related in-interface=pppoe-out1
add action=accept chain=forward in-interface=pppoe-out1 protocol=icmpv6
add action=accept chain=forward dst-port=22 in-interface=pppoe-out1 protocol=tcp
add action=drop chain=forward in-interface=pppoe-out1
add action=accept chain=input in-interface=pppoe-out1 protocol=icmpv6
add action=accept chain=input dst-port=546 in-interface=pppoe-out1 protocol=udp
add action=drop chain=input in-interface=pppoe-out1
add action=drop chain=input in-interface=ether1-gateway

With the above rules, a lot of unnecessary traffic is stopped before it reaches my network. The traffic load on my link is irritating, but there is little I can do about it. Choosing to “drop” rather than “reject” packets causes connections to take a lot longer to fail, which is good, but that’s about all you can do. If you have any very persistent “nuisance callers”, discuss them with your ISP – they may be able to help, particularly if the same nuisance is being experienced by other customers.

This is a very simple ruleset. The Mikrotik has a lot of sophisticated features that let you mark, track and rate-limit, plus a lot more besides. But the above is enough for now.

PS: The above discusses only IPv6 rules! If you are also running IPv4, as you almost certainly are, then you will need to set up similar rules for IPv4. An IPv6 ruleset has no effect on IPv4 at all, and an IPv4 ruleset has no effect on IPv6.

 

6 Replies to “A simple IPv6 firewall for the Mikrotik”

  1. Great start, thanks for sharing.

    I added established/related on the input chain as well to get DNS (and other things) to work.

    jcole says:
    1. You are talking about getting DNS to work from the Mikrotik itself. You are right that additional rules are needed, because the two rules in the ruleset presented above stop anything reaching the Mikrotik from outside except ICMPv6 – which means DNS answers will be dropped. Suitable rules to allow the Mikrotik itself to do DNS (or anything else) would be something like:


      add action=accept chain=input connection-state=established in-interface=pppoe-out1
      add action=accept chain=input connection-state=related in-interface=pppoe-out>

      These should be inserted as the first rules in the input chain.

  2. In my test environment, the router was using IPv6 for proxied DNS requests from IPv4-only hosts. This probably isn’t ideal, but I haven’t quite sorted out how it’s supposed to work.

    Anwyay, the router may source DNS for local diagnostics, NTP, software updates, etc., so having established and related accepted on the input chain is probably better long-term.

    Thanks again for sharing!

    jcole says:
  3. I’m a very new user of a Mikrotik router. So please excuse what may be a dumb question but in your example, is interface “pppoe-out1” connected to your inside network? Trying to get my mind around this as it seems to me that firewall commands would normally be applied to the outside (wan) interface but you’ve got only one applied to ether1-gateway, the outside interface – I think.

    Thanks much.

    Steve W says:
    1. The physical outside interface is ether1-gateway, but a PPPoE client is running on that interface to provide the logical outside interface, pppoe-out1. ether1-gateway is involved in layer 2 – pppoe-out1 is the place where IP packets are happening.

      There is only one rule on ether1-gateway and it blocks everything, because we are not interested in anything that might arrive on layer 3 on that interface. ether1-gateway is just for PPPoE.

      Firewall commands can be applied to any interface – it’s generally a good idea to apply them to the earliest possible control point (usually an interface) in the packet’s path.

Leave a Reply

Your email address will not be published. Required fields are marked *