Wireguard routing when one tunnel is down

Hi,

I have implemented 2 Wireguard tunnels to different destinations. I want to make sure that certrain traffic is always routed through one of the tunnels.

I have a Mangle-rule which sets a routing mark (in prerouting) and I have two routes for that routing table and destination 0.0.0.0, one for each Wireguard interface.

The routes have different distances to make sure that the traffic to one destination is not routed through different tunnels at the same time.

Until here, everything is working as expected.

When the tunnel with the smaller destination is down (log shows “handshake for peer did not complete after 5 seconds”) I want the traffic to be automatically be routed through the tunnel which is still up. Currently I have to manually disable the route for the tunnel, which is down.

Is there any way to configure this?

Best regards,

cyb

I usually dont comment without evidence, aka the config.

/export file=anynameyouwish ( minus router serial number, any public WANIP information, keys, dhcp lease lists )

What is not clear from your description is if the external sites are remote clients connecting to your router or more likely you are using third party VPN connections, for some users to go out the internet at a different location?

These details are important to understand regarding setting a correct and efficient config for those requirements.

Once we understand how you partition users, and which users are supposed to use wireguard vice normal WAN internet, it will be possible to try to automate any "failover".

The main problem is that wireguard is not a normal interface and methods of checking whether wireguard is up or down is not as straightforward, however it is possible.

Hi anav,

thanks for your reply!

You are right about the config. But it is actually quite huge (~700 lines). When I posted it the last time I had to argue about several things I configured consciously, which were questioned by some users and which actually did not have to do anything with the actual question/problem. So I was hoping to get any ideas about solving the problem without posting the config.

You are also right about my description that it is not precise enough. I am talking about ougoing third party vpn connections to route certain traffic to the internet through it. The mangle rule has a source address list with some IPs for which the traffic shall be tunneled.

Best regards,

cyb

How many users are you talking need to be forced into the tunnel............ Are they all from one subnet or across subnets etc...

A possibility:

Configure an IP address/mask on the wireguard interfaces, with the peer having an IP address/mask on its wireguard interface in that same range and include the remote peers wireguard IP address in your peers allowed IP address list, and the peer has your wireguard IP address in its allowedIP list. (Not an uncommon setup)

In your tunnel1 routing table, you can then route via the "wireguard1 remote Peer IP address" (rather than wireguard1 interface) with check gateway set to ping.

Peer will likely need to be configured similarly, so return traffic goes the long way back when wireguard1 is down.

Note: Only route to wireguard1's peer's wireguard IP address must be via wireguard1.
This requirement should normally be met ok. (But worth remembering)

rplant, you should post an example of what you mean......words alone do not do justice to the text.

@rplant Thanks for your input. Indeed I did not understand your guidance completely…

I finally managed to get a working solution for my requirements. If somebody is interested: scheduler executes the following script every 30 seconds. The script checks, if a destination in internet can be reached through the wireguard-interface. If not, the interface is “disabled” by increasing the distance. If it is working again, the distance is decremented again.

:local iface1 "wireguard-interface-1"
:local iface2 "wireguard-interface-2"

:local route1 [/ip route find gateway=$iface1 routing-table=custom-routing-table]
:local route2 [/ip route find gateway=$iface2 routing-table=custom-routing-table]

:if ([/ping 9.9.9.9 count=3 interface=$iface1]=0) do={
    # interface 1 is not up, check if interface 2 needs to be enabled
    :if ([/ip route get $route2 distance]=2) do={
        :log info "Enabling <$iface2>, because <$iface1> seems to be down"
        /ip route set $route1 distance=2
        /ip route set $route2 distance=1
    }
} else={
    # interface 1 is up, check if it needs to be re-enabled
    :if ([/ip route get $route1 distance]=2) do={
        :log info "Re-enabling <$iface1>, because it seems to be up again"
        /ip route set $route1 distance=1
        /ip route set $route2 distance=2
    }
}

To make it clearer.
Is this for the case where, you
a. have a mikrotik router
b. have two different Third party VPN providers, the router is client to, for handshake.
c. wish all users to go out wireguard 1 when it is available and if not available use wireguard 2??

ARE WE TALKING ONE WIREGUARD INTERFACE or TWO WIREGUARD INTERFACES as I do not understand why you have the SAME custom-routing table for both.

Logic: There is no point in having difference as any kind of factor across two different tables.
(Custom routing tables are used to point to the wireguard interface and not the local WAN.)

I am missing something here.........
Perhaps its for the case where Same Provider, Same assigned address, but endpoint address and possibly port is different ( aka points to a different location )???

this looks like a job for https://help.mikrotik.com/docs/spaces/ROS/pages/26476608/Failover+WAN+Backup

@anav: a=yes, b=yes, c=yes (except that it’s not for all users, but only for certain traffic which is marked by the prerouting-mangle-rule). There are two interfaces, because it’s two different wireguard connections. They have the same custom-routing-table, because the marked traffic shall be routed through tunnel 1 and in case tunnel 1 is down through tunnel 2.

@infabo: Thanks for the link. I tried that before but it did not work. The routes to 8.8.8.8/8.8.4.4 and the private gateway ip were working (=online), but the default routes to 8.8.8.8/8.8.4.4 with check-gateway=ping were not working (always in state “unreachable”). I assume it does not work with Wireguard interfaces.

cyb2
Unless the wireguard subnet is the same, ( aka just different port and endpoint address but same assigned wireguard address ) it will not work.

Facts: The router does not care about distance differences between different tables.
The reply is but you are using only one table.

Facts: You have no route to the second wireguard gateway address at all ????

+++++++++++++++++++++++++++++++++++++++++

cyb2 You are correct, wireguard is not a normal interface and checkgateway=ping does not change the state of the wireguard interface (it will always be in the UP position). One has to do more such as netwatch ping the remote wireguard address for example ).

Both wg tunnels have their own interface address from different subnets and yes, it does work. There are two routes, one with distance=1, one with distance=2, both with the same routing table. The script I created yesterday changes the distance of the “active” tunnel to 1 and the “non-active” to 2. It works perfectly in case one tunnel is not working.

Okay, I understand what you are doing sweet.

If its just a few users then I prefer routing rules to mangling for forcing users into a tunnel.
Or if its a full subnet ( like create a vlan/WLAN-ssid just for wireguard users ).

Anything else, mangling is the way and I suppose you probably use a firewall address list to identify which users. The issue will be in mangling to allow them to still partake in local traffic.

/ip firewall address-list
add local subnetA list=connected
add local subnetB list=connected
add local subnetC list=connected
add adddress=X  list=wg comment="user from subnet A for wireguard"
add address=Y list=wg  comment="user from subnet B for wireguard"
add address=Z list=wg  comment="user from subnet C for wireguard"
etc....
/ip firewall mangle
add action=accept chain=prerouting src-address-list=connected dst-address-list=connected
add action=mark-connections chain=forward connection-mark=no-mark \
   src-address-list=wg new-connection-mark=ForWG  passthrough=yes
add action=mark-routing chain=prerouting connection-mark=ForWG 
   new-routing-mark=custom-routing-table passthrough=no

and fastrack rule

add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
    connection-state=established,related hw-offload=yes connection-mark=no-mark

Something similar to the following might work

/ip route
add check-gateway=ping disabled=no distance=1 dst-address=0.0.0.0/0 gateway=
9.9.9.9%wireguard-interface-1 pref-src=[wireguard-interface-1 IP Address]
routing-table=custom-routing-table scope=10
suppress-hw-offload=no target-scope=30