Mikrotik router as Wireguard VPN gateway
In my new apartment I luckily have a fibre (FTTH) which terminates in the living room. My first excitement was curbed when I investigated about the technology in use. The ISP uses a technique called GPON which is probably smart from a economical point of view but also enables some possible (sniffing) attacks. Additionally the provider seems to do some filtering which is not just DNS blocking. Long story short I decided to route all traffic through a VPN and so I began to config a Mikrotik hex POE router to use a Njal.la Wireguard VPN.
Configuring the router
This is the first time I actually use Mirotik router in non default config so it took quite a while for me to figure out how everything fits together. The requirements are:
- DHCP Client on Uplink port
- working Wireguard tunnel
- default route through the wireguard tunnel
- forbid traffic to go directly to the uplink (eg. on Wireguard connection loss)
- DHCP server on all other interfaces
- working DNS resolver on the router
- working IPv6
DHCP Client + LAN Bridge
First we setup a standard behaviour: use the
ether1 port for uplink as DHCP client and bridge the remaining interfaces together.
/interface list member add comment=uplink interface=ether1 list=WAN /ip dhcp-client add add-default-route=no comment=uplink interface=ether1 use-peer-dns=no \ use-peer-ntp=no /interface bridge add admin-mac=AA:BB:CC:DD:EE:FF auto-mac=no comment=local-bridge name=bridge \ protocol-mode=none /interface bridge port add bridge=bridge comment=defconf interface=ether2 add bridge=bridge comment=defconf interface=ether3 add bridge=bridge comment=defconf interface=ether4 add bridge=bridge comment=defconf interface=ether5 add bridge=bridge comment=defconf interface=sfp1
Be aware, that we do not want to automatically set a default route to the gateway of the uplink network
since we want all traffic go through the VPN at all times.
DHCPv4 is also a very common configuration which, I think, does not need further explanation. The hex POE router has DHCPv4 on its LAN bridge by default enabled. Anyway here is a configuration example with one static lease:
/ip pool add name=domainmess-home-dhcp-range ranges=192.168.0.100-192.168.0.200 /ip dhcp-server add address-pool=domainmess-home-dhcp-range authoritative=yes disabled=no interface=bridge \ lease-script="" lease-time=10m name=domainmess-home-dhcp-server use-radius=no /ip dhcp-server lease add address=192.168.0.200 client-id=\ aa:bb:cc:ee:ff:aa:bb:cc:ee:f:faa:bb:cc:ee:ff:aa:bb:cc:ee:ff mac-address=\ AA:BB:CC:DD:EE:FF server=domainmess-home-dhcp-server
DHCPv6 isn’t really the right term as the Mikrotik RouterOS does prefix delegation. That means it announces a prefix which the client can get and might use for further delegation or address selection. I use it to assign a /64 network to each client which then will configure automatically one address from that.
/ipv6 pool add name=domainmess-home-ipv6-ula prefix=fc00:99ff:4400::/32 prefix-length=64 /ipv6 dhcp-server add address-pool=domainmess-home-ipv6-ula dhcp-option="" disabled=no interface=bridge lease-time=3d \ name=domainmess-home-dhcpv6-pd preference=255 rapid-commit=yes route-distance=1 \ use-radius=no
Wireguard is new in RouterOS 7 and is integrated quite well into the Mikrotik config.
We define a interface of the type „Wireguard” and at least on Peer to which we want to connect to.
In our case that is the Njalla VPN server.
The other settings come from the Njalla config, but the important one is that we set
::/0 in the
so that we can route all internet traffic through it and not just a specific subnet.
# keys are just examples /interface wireguard add disabled=no listen-port=13231 mtu=1280 name=njalla01 private-key=\ "gDV016J81d9dWkkw7j9MjDcnmt0HhQHnsG7favtiJU8=" /interface wireguard peers add allowed-address=0.0.0.0/0,::/0 disabled=no endpoint-address=\ wg235.njalla.no endpoint-port=51820 interface=njalla01 \ persistent-keepalive=25s public-key=\ "YAV6HyThvZgLTYD6nDIeMeUNKgwnp6jnLdiYYNb9Bnc="
Hint: Using a hostname instead of an IP as EndPoint is supported since RouterOS 7.6
Routes + DNS
Now Wireguard isn’t able to connect to its remote, since there is no working Routing+DNS. Setting DNS servers is trivial but we need also to route all encrypted Wireguard traffic to the Njalla network via our uplink port. Same goes for at least one DNS server so that Wireguard can lookup its remote.
Be aware: This will make at least some your DNS request bypass the VPN and be victim to censorship or monitoring. To prevent that, use a static IP as Wireguard remote!
As a default gateway we then set the Wireguard Interface instead of a IP address. That is possible since Wireguard is an IP protocol (Layer 3) and creates a TUN device which has no need for a Ethernet header with a gateway MAC address inside it. The traffic must be routed anyway on the other side of the tunnel (on the Njalla routers) and we therefore can just send IP packets into it.
# route to njalla network via uplink /ip route add disabled=no distance=1 dst-address=220.127.116.11/19 gateway=[/ip dhcp-client get [find interface=ether1] gateway] pref-src="" routing-table=main suppress-hw-offload=no # default route via njalla VPN add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=njalla01 pref-src="" \ routing-table=main suppress-hw-offload=no # DNS bypass add disabled=no distance=1 dst-address=18.104.22.168/32 gateway=192.168.1.254 \ pref-src="" routing-table=main suppress-hw-offload=no
Like on more or less every home route IPv4 source NAT is used to use the IPv4 VPN address for all outgoing traffic. This is also part of the default conf of many Mikrotik router.
/ip firewall nat add action=masquerade chain=srcnat comment="defconf: masquerade" \ ipsec-policy=out,none out-interface-list=WAN
This is definitely the most ugly part. Since Njalla only gives one IPv6 address per VPN connection we have to setup a IPv6 source NAT (yes, that is possible, didn’t believe that either…)
/ipv6 firewall nat add action=masquerade chain=srcnat ipsec-policy=out,none out-interface=\ njalla01
Works as designed and is better than no IPv6 at all!
configuring the clients
To use the IPv6 prefix delegation we configured before in the DHCPv6 Server section, we must also ensure that the client is asking for it. For systemd-networkd this is done by adding the following lines to the interface configuration:
[Network] DHCP=yes DHCPPrefixDelegation=yes
During the whole configuration I learned some related stuff which came in quite handy for using and debugging Mikrotik Routers.
Find IPv6 hosts in network
To find IPv6 hosts in the local network one doesn’t need to
nmap but one can use multicast packets on which specific hosts will answer.
For example to find all routers you can just ping
$ ping -6 ff02::2%wlan0
This way you can find a router even if no DHCP is working in your LAN or if the router has no static IP due to some configuration errors.
Use Link-Local addresses
Of course you can also use the Link-Local address to access your router. Well at least you can if you don’t want to use the Webinterface because I couldn’t find any browser that properly supports using Link-Local addresses. That is not a new phenomenon and is otherwise documented. However accessing the router via SSH via it’s link local address even works if’s been rebooted with completely network config.
- https://forum.mikrotik.com/viewtopic.php?t=181205#p897582 https://web.archive.org/web/20221024234723/https%3A%2F%2Fforum.mikrotik.com%2Fviewtopic.php%3Ft%3D181205
- https://wiki.mikrotik.com/wiki/Setting_up_DHCPv6 https://web.archive.org/web/20221024235049/https://wiki.mikrotik.com/wiki/Setting_up_DHCPv6