Mangle rules to add routing mark

As above.

Brief summary of what I’m trying to achieve.

I’ve had a vpn (IP Vanish) that I’ve used for years. Until now, I just use the app on whatever device I need to use to change my location at that time but I recently got a Meta Quest 3S that doesn’t have the IP Vanish app without going through the hassle of setting up sideloading, so I decided to setup a wireguard connection on the Router itself to route everything through the VPN. It works, but I don’t want to use it unless I need it.

I set up using a guide I found on Youtube based on two routing tables and some rules that I can toggle on and off to enable or disable the vpn (ryzenvanish, metavanish which route individual devices, and allvanish which routes everything)

You’ll notice some entries to route things through the main routing table (essentially my internal network traffic, traffic from my Pihole and traffic from my own internal VPN that I use to dial into my services from outside. I had to allow my own OpenVPN server (10.10.10.63) to just get straight out to the internet, bypassing the VPN, in order for me to connect to it fully. I do have a secondary OpenVPN profile on each device that just routes my internal lan traffic and DNS queries through my network with everything else going straight to the big bad internet and that worked ok but I digress, I’m happy for my VPN server to just bypass the IP Vanish DNS for outbound connections of its own - even with the rule sending traffic from 10.10.10.63 straight to the normal WAN interface, I confirmed that clients connected to it routed through the IP Vanish VPN.

The only issue is, it’s a bit of a hassle toggling the routing rules on and off. I’ve setup scripts but I still have to ssh to run them.

Home Assistant has a custom Mikrotik integration that allows Mangle Rules to be toggled on and off so I thought I could do something with routing marks and configuring the tables that way, but I hit a brick wall when I was trying to assign a Mangle Rule to mark packets FROM my local LAN TO my Local LAN. As soon as I create the rule, (chain pre-routing, src-address-list LAN, dst-address-list LAN, action- mark routing-main) I lose connection to the router. Luckily I planned ahead and was in safe mode.

I’m assuming the problem is that the router itself is included within the lan address list ?

Can anyone shed any light on how I could progress? I just need to get past the point where I can have my local traffic marked with the routing mark “main” then I can figure the rest out myself.

config.rsc (68.9 KB)

Apologies for the config, you can tell I've done a lot of experimentation over the years and not all of it has been removed but it works for me.

Without reading the config: you can add a dst-address-type=!local (note the exclamation mark) match condition to your problematic rules. Doing so will prevent them from matching on packets whose destination address is one of the router’s own ones.

You can replace those 6 routing rules:

/routing rule
add action=lookup comment="lan to lan" disabled=no dst-address=10.10.0.0/16 \
    src-address=10.10.0.0/16 table=main
add action=lookup comment="lan to vpn" disabled=no dst-address=10.8.0.0/24 \
    src-address=10.10.0.0/16 table=main
add action=lookup comment="vpn to lan" disabled=no dst-address=10.10.0.0/16 \
    src-address=10.8.0.0/24 table=main
add action=lookup comment="vpn to vpn" disabled=no dst-address=10.8.0.0/24 \
    src-address=10.8.0.0/24 table=main
add action=lookup disabled=no dst-address=192.168.0.1/32 table=main
add action=lookup disabled=no dst-address=192.168.0.69/32 table=main

with this single rule at the top of your Routing Rules table:

/routing rule
add action=lookup min-prefix=0 table=main

Once you have that routing rule in place, don't do this:

instead, your mangle rule with the condition FROM my local LAN TO my Local LAN should be a rule with action=accept and not action=mark-connection/action=mark-routing. And the accept rule should be placed at the top of the mangle table.

/ip firewall mangle
add action=accept chain=prerouting src-address-list=lan dst-address-list=lan

The reason I didn’t do that is that I’d rather keep my VPN and local lan lists separate but I suppose I could create a second list containing both.

No local in @sindy's post is not an address list with the list of local IP addresses. Please note that the name of the property is dst-address-type.

  • dst-address-type=!local means any IP addresses that are NOT one of the router's IP addresses.
  • dst-address-type=local means any IP addresses that are one of the router's IP addresses.

The router's IP addresses are the IP addresses (not including the prefix length!) you see assigned to the interfaces under /ip address (and /ipv6 address for IPv6).

Could you explain what this does?

For your last bit

The point of the mangle rules was to put a routing mark on the packets so that the routing rules could essentially be reduced to

routing mark “main” > table “main”

routing mark “ipvanish-sw” > table “ipvanish-sw”

Or will marking the packet in the mangle rules automatically send it to the correct routing table?

My routing table has two routes for 0.0.0.0/24 as you’ll see. The main one which routes everything to my WAN interface and the ipvansih-sw one which routes everything to the wireguard interface.

I could then enable/disable mangle rule that marks the packets I want routed through the wireguard interface when I want to enable/disable the VPN, but the mangle rules are aimed at allowing the traffic I want to bypass the VPN to just go straight to the main routing table

Ah I see now, so it will ONLY ignore addresses of the router itself rather than the local addresses on my network. Every day’s a school day.

This rule, that you should put at the top of the routing rule table, will cause the route for the packets (that don't have routing mark) to be lookup from the routes in the main table that don't have dst-address=0.0.0.0/0. Which means all the routes that have dst-address=a.b.c.d/e where e > 0 in main will be used as candidate. If one of those routes matches the packet's destination, the route is used and the routing rule table are no longer processed.

Only if none of those routes matches the address, does the lookup continues with the next rule in the table.

Which means if the packet has a destination that is in any of your VLAN subnets, it will use main (because a connected route with prefix length /e where e > 0 exists that matches). If the destination is an "outside" destination (where a route with dst-address=0.0.0.0/0) is needed, then there will be no match (because those routes has been explicitly excluded by min-prefix=0), which means the default route in main will not be used by this rule.

action=accept in the mangle table chain prerouting is just like action=accept everywhere else that if that rule matches, the processing will skip all the rest of the rules below it in the same chain (prerouting in this case).

So, if the condition (in this case source list is lan and destination list is lan) is matched, action=accept is performed and the rules that does mark-routing below will not be applied to the packet. Which means the packet will have no routing mark (not even the main routing mark).

With no routing mark it will be able to be matched by the min-prefix=0 rule at the top of the routing rule table, and will use main for the lookup if the destination address can use any non 0.0.0.0/0 route in main.

You don't need routing-mark=main. Only set routing-mark=ipvanish-sw for packets that you want to use that 2nd table. For anything that should use the main table, don't set any routing mark.

That worked perfectly, thank you.

I’m interested to know if there’s a more elegant way of achieving what I want.

From 10.10.10.63 or 10.10.10.99 > straight to wan

To 192.168.0.1 (my ISP router which sits just in front of my Mikrotilk router) > no not pass through wireguard interface

From LAN (10.10.0.0/16) or VPN (10.8.0.0/24) to LAN or VPN > do not pass through wireguard interface

But for now I think I can work with the routing marks the way I’ve started.

Ok, so having the rule you provided will negate the need for any internal routing rules at all. I’m thinking in that case, the only thing I’d need to consider are the two IP addresses I want to bypass the VPN at all times and the ip address of my ISP router. I’ll get to work.

Thank you both

The "elegant" way is the routing rule with min-prefix=0. As you can see, all the example that you listed that should skip the WireGuard interface have connected routes in the main table with prefix /xx where xx > 0.

/ip firewall mangle
add action=accept chain=prerouting comment="local passthrough"dst-address-list=lan src-address-list=lanadd action=accept chain=prerouting comment="tensoon and ham passthrough"src-address-list=nonvanishadd action=accept chain=prerouting comment="router 192 address passthroughs"dst-address-list=novanishdestadd action=mark-routing chain=prerouting comment=allvanish dst-address=0.0.0.0/0 new-routing-mark=ipvanish-sw src-address=10.0.0.0/8
/routing rule add action=lookup comment="local passthrough" disabled=no min-prefix=1 table=mainadd action=lookup comment=allvanish disabled=no routing-mark=ipvanish-swtable=ipvanish-swadd action=lookup disabled=no routing-mark=main table=main

Much more elegant than what I was going for.

I’m not convinced I need

add action=accept chain=prerouting comment="router 192 address passthroughs"
dst-address-list=novanishdest

the 192 routes are defined in the routing table but I can’t browse to my ISP router without it. I’m also not sure the

add action=lookup comment="local passthrough" disabled=no min-prefix=1 table=
main

is required anymore as I added all the addresses I want to communicate directly to the mangle rules and the only packets that will route through the wireguard interface are those that get routing-marked but it works and it’s much more streamlined than before. Thank you

EDIT

I’m not sure why the 192 bypass won’t get picked up by the min-prefix=1 rule. I even tried re-enabling the direct rules for destinations of 192.168.0.1 and 192.168.0.62 to be sent to the main routing table (in the routing rules) but I still couldn’t reach the ISP router with the routing-mark mangle rule enabled. But I disabled the rule for the novanishdestadd address list and added it as a NOT address list on the final routing mark rule and it’s doing what I want so I’m going to stop fiddling.