Routing rule VS mangle mark routing

Hi,

According to the docs, one can use any or both of the following methods for policy routing:

  • routing rule, e.g.
/routing rule 
add action=lookup dst-address=9.9.9.9/32 src-address=192.168.2.0/24 table=vrf-wan2
  • mangle mark routing, e.g.
/ip firewall mangle
add action=mark-routing chain=prerouting dst-address=9.9.9.9/32 new-routing-mark=vrf-wan2 src-address=192.168.2.0/24

In my experience it is routing rules that work on v7.12.1 while mangle rules won’t. Routing rules don’t accept address lists and generally provide very few parameters for traffic filtering. Thus, I would like to use mangle rules instead, but can’t make them work the way routing rules do.

Does anybody know what the actual difference is between these 2 methods? Do I miss any more mangle rules that routing rules have under the hood?

Maybe. but we can’t see what you have missed if you do not post more of your configuration.
Post the rest of your config when you are trying to use mangle rules so we can see where there might be an error.

Also the requirement should be expressed in terms of user traffic required.
Mangling and routing rules are simply tools to use, for a purpose, and that purpose has not been communicated…

Fair enough. Below is a list of other relevant commands for simplicity. All drop/reject filter rules disabled, no other nat/mangle/raw rules enabled.

/ip vrf
add interfaces=wan2 name=vrf-wan2

/interface list member
add interface=wan2 list=WAN

/ip address
add address=10.16.51.242/24 interface=wan2 network=10.16.51.0

/ip route
add disabled=no distance=100 dst-address=0.0.0.0/0 gateway=10.16.51.1@vrf-wan2 routing-table=vrf-wan2 suppress-hw-offload=no
add disabled=no distance=100 dst-address=192.168.2.0/24 gateway=lan routing-table=vrf-wan2 suppress-hw-offload=no

/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=WAN



What I would like to achieve is a domain-based VPN: some domains are resolved, their addresses put into lists, these lists used by mangle rules to route traffic through VRF.

UPD: fixed the config excerpt above to be consistent with a full config posted below.

Created an empty CHR and tested the same config. Sadly, the problem persists: route rule works, mangle mark routing doesn’t work.

/interface bridge
add ingress-filtering=no name=bridge vlan-filtering=yes

/interface bridge port
add bridge=bridge interface=ether1 pvid=17

/interface bridge vlan
add bridge=bridge tagged=bridge untagged=ether1 vlan-ids=17

/interface vlan
add interface=bridge name=wan1 vlan-id=17

/interface vxlan
add mtu=1370 name=lan port=8472 vni=1000 vrf=main vteps-ip-version=ipv4
add mtu=1370 name=wan2 port=8472 vni=4147 vrf=main vteps-ip-version=ipv4

/interface vxlan vteps
add interface=lan remote-ip=10.19.16.1
add interface=wan2 remote-ip=10.80.16.1

/interface list
add name=WAN

/interface list member
add interface=wan1 list=WAN
add interface=wan2 list=WAN

/ip vrf
add interfaces=wan2 name=vrf-wan2

/ip address
add address=10.16.51.242/24 interface=wan2 network=10.16.51.0
add address=192.168.2.1/24 interface=lan network=192.168.2.0

/ip dhcp-client
add default-route-distance=100 interface=wan1 use-peer-dns=no use-peer-ntp=no

/ip dns
set servers=1.1.1.1,1.0.0.1

/ip firewall filter
add action=accept chain=input
add action=accept chain=forward

/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=WAN

/ip route
add disabled=no distance=100 dst-address=0.0.0.0/0 gateway=10.16.51.1@vrf-wan2 routing-table=vrf-wan2 suppress-hw-offload=no
add disabled=no distance=100 dst-address=192.168.2.0/24 gateway=lan routing-table=vrf-wan2 suppress-hw-offload=no

# THIS IS WHAT DOESN'T WORK: if enabled, icmp traceroute from 192.168.2.2 to 9.9.9.9 never goes beyond 192.168.2.1
/ip firewall mangle
add action=mark-routing chain=prerouting dst-address=9.9.9.9/32 new-routing-mark=vrf-wan2 passthrough=yes src-address=192.168.2.0/24

# THIS IS WHAT ACTUALLY WORKS: if enabled, icmp traceroute from 192.168.2.2 to 9.9.9.9 goes through 192.168.2.1 and 10.16.51.1 (wan2 gw)
/routing rule
add action=lookup disabled=yes dst-address=9.9.9.9/32 interface=lan src-address=192.168.2.0/24 table=vrf-wan2

# IT IS ALSO FINE WITH BOTH RULES DISABLED: icmp traceroute from 192.168.2.2 to 9.9.9.9 goes through 192.168.2.1 and wan1 gw

I use domain based vpn with mangle (mark routing).
Additionally you have to add ip-route rule to route (what you marked with mangle) to vpn gateway.
Example:

/ip firewall mangle:
add action=mark-routing chain=prerouting dst-address=!192.168.2.0/24 \
dst-address-list=!LIST new-routing-mark=ipsec passthrough=yes src-address=\
192.168.2.0/24

/ip route
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=l2tp-out1 pref-src=\
"" routing-table=ipsec scope=30 suppress-hw-offload=yes target-scope=10

LIST - local country ip list.

If you want I can post here step by step config.
My setup uses local country internet directly. And everything that is not local country with vpn .
My vpn is remote vps with libreswan ipsec
Mikrotik is an ipsec client .

I tried to use remote vps\vpn as chr mikrotik but I failed to get speeds more than 40-50 mbps.
Simple ubuntu with libreswan 1 cpu 512 ram can be set up with scripts from github in 5 min, produce up to 185 mbps thru ipsec.


Same easily can be done thru wireguard.
You should be awared that chr withiut licence is limited to 1mbps.

Hi,
I built an approximation to this, but with no vxlans (just used another bridge, and ether2 as wan2)

It seemed to mostly work, but the vrf-wan2 being a vrf made it quite painful.
I seemed to need to reboot whenever I had done more than a couple of changes.

I was also unable to traceroute from the router using src-address=192.168.2.1
My laptop on 192.168.2.220 was fine, (though this is somewhat expected).

I turned vrf-wan2 into just routing table (in fib) entry and adjusted for that and it seemed to work quite a bit better and easier.
(You do lose some isolation, but you don’t seem to really need any in this instance)

Some (my) notes on routing, seem to be how it is currently working. (not really checked for vrf’s)

First:
If the packet has a routing mark on it, and there is a matching entry in the routing table.
(IP range, routing table matches routing mark) it WILL use that routing entry.
This means if there is an item like
add disabled=no distance=100 dst-address=192.168.2.0/24 gateway=lan pref-src=“” routing-table=
vrf-wan2 scope=30 suppress-hw-offload=no target-scope=10
It seems it will (attempt to) send the marked packet out the lan interface, even if it is going to 192.168.2.1

Next:
It will then use the Routing Rules table, (in order) and grab the first match, and do what it says.

Next2:
It will then process the packet through the routing table again, potentially with a different routing mark obtained from the rules table.
(But it seems perhaps a bit more lenient this time)


You can (and it works well) use the routing rules table with routing marks.

mangle:
mark selected packets with routing mark eg. rule-wan2

routing rule
action=lookup table=main dst-address=192.168.2.0/24
action=lookup table=vrf-wan2 routing-mark=rule-wan2

Thank you for a detailed reply. This is roughly what I have, I just simplified the config to a single target address, but I have the same problem if I use lists in mangle rules instead. And I certainly have a default gateway in vrf-wan2. Is your “ipsec” routing table a VRF or a simple routing table created manually?

Do you have anything else in your config that is relevant? E.g. firewall rules, ip routes, routing rules, etc.

These speed issues are probably due to ipsec. I use wireguard and it easily handles 200-300 mbps between 2 CHRs or CHR and RB5009, at least as shown by the built-in bandwidth test tool. I think, it can even do faster, but it is VPS bandwidth that seems to be a limitation for me in terms of speed.

First of all, thank you for your effort.

It’s a good idea to replace VRF with a simple routing table in FIB. Unfortunately, it barely changed anything for me. Tested on an empty CHR, changes to the full config posted above are the following:

/ip vrf
add interfaces=none name=vrf-wan2

/routing table
add disabled=no fib name=rtab-wan2

/ip route
add distance=100 dst-address=0.0.0.0/0 gateway=10.16.51.1 routing-table=rtab-wan2
add distance=100 dst-address=192.168.2.0/24 gateway=lan routing-table=rtab-wan2

# IT DOESN'T WORK: icmp traceroute from 192.168.2.2 to 9.9.9.9 never goes beyond 192.168.2.1
/ip firewall mangle
add action=mark-routing chain=prerouting disabled=yes dst-address=9.9.9.9/32 new-routing-mark=rtab-wan2 src-address=192.168.2.0/24

# IT WORKS: icmp traceroute from 192.168.2.2 to 9.9.9.9 goes via 192.168.2.1 and 10.16.51.1 (wan2 gw)
/routing rule
add action=lookup disabled=yes dst-address=9.9.9.9/32 interface=lan src-address=192.168.2.0/24 table=rtab-wan2

# IT ALSO WORKS WITH BOTH RULES DISABLED: icmp traceroute from 192.168.2.2 to 9.9.9.9 goes via 192.168.2.1 and wan1 gw



That’s another good idea I tested myself. In fact, it equals to enabling both mangle and routing rules (because mangle mark routing only allows setting routing tables as marks). It doesn’t work for me either. But I’m not sure whether it should, since it is discouraged to combine the two methods of policy routing according to the docs.

That is a key, thanks! I replaced vxlan with eoip and mangle mark routing now works.

So, it seems to be a vxlan bug, will report to MikroTik support soon.

UPD: SUP-136716 + reply on 27 December 2023:

We have managed to reproduce the issue locally in our labs and look forward to fixing it on upcoming RouterOS versions, unfortunately, I cannot provide a release date now.

you guys guess worked well on this case and it’s useful for others like me. Thank you.

Anyone know when this was fixed? It’s working in 7.15.3 but not 7.12.1 or below

Tested several configuration, and there are some approach to address this issues with its own pros and cons.

  1. Totally using Tables Rule.
    Pros: simple when dealing with few vlan/subnet, auto-block vlan/subnet i.e. can not ping each other, etc.
    Cons: more vlan more headache, and need to work out to make some ip/subnet (i.e. local server) accessible from other vlan/subnet.

  2. Combining Tables Rule with Mangle>Mark Routing.
    Pros: more flexible, and if it configured properly (with nat and ip>route) then no need to worry about access vlan/port/subnet on same bridge.
    Cons: I guess it takes more resources (cpu, memory), but I’m not sure.

Here how I approached it with Mangle and Table Rule:

/interface list
add name=WAN
add name=LAN
add name=MGMT

#WAN2, WAN3, WAN4 using DHCP
/ip dhcp-client
#add interface=ether1-WAN1 use-peer-dns=no use-peer-ntp=no add-default-route=no
add interface=ether2-WAN2 use-peer-dns=no use-peer-ntp=no add-default-route=yes default-route-distance=12 comment=WAN2 
add interface=ether3-WAN3 use-peer-dns=no use-peer-ntp=no add-default-route=yes default-route-distance=13 comment=WAN3 
add interface=ether4-WAN4 use-peer-dns=no use-peer-ntp=no add-default-route=yes default-route-distance=14 comment=WAN4 

#WAN1 using PPPoE
/interface pppoe-client
add interface=ether1-WAN1 name=pppoe-WAN1 user=secretuser add-default-route=yes default-route-distance=11 comment=WAN1 

#ADD all internet connection into list=WAN
/interface list member
add interface=pppoe-WAN1  list=WAN
add interface=ether2-WAN2 list=WAN
add interface=ether3-WAN3 list=WAN
add interface=ether4-WAN4 list=WAN


/ip firewall address-list
#local subnet: needed for Mangle
add address=192.168.0.0/16 list=local_subnet
add address=172.16.0.0/12 list=local_subnet
add address=10.0.0.0/8 list=local_subnet
#WAN1 ip address
add address=192.168.10.0/24 list=WAN1-conn
add address=192.168.11.0/24 list=WAN1-conn
add address=192.168.12.0/24 list=WAN1-conn
#WAN2 ip address
add address=192.168.20.0/24 list=WAN2-conn
#WAN3 ip address
add address=192.168.30.0/24 list=WAN3-conn
#WAN4 ip address
add address=192.168.40.0/24 list=WAN4-conn
add address=192.168.41.0/24 list=WAN4-conn


#VRF
/routing table
add disabled=no fib name=rtab-WAN1
add disabled=no fib name=rtab-WAN2
add disabled=no fib name=rtab-WAN3
add disabled=no fib name=rtab-WAN4
add disabled=no name=rtab-toBlackhole

#MANGLE
/ip firewall mangle
add action=mark-routing chain=prerouting dst-address-list=!local_subnet \
    dst-address-type="" new-routing-mark=rtab-WAN1 passthrough=no \
    src-address-list=WAN1-conn comment=WAN1 
add action=mark-routing chain=prerouting dst-address-list=!local_subnet \
    dst-address-type="" new-routing-mark=rtab-WAN2 passthrough=no \
    src-address-list=WAN2-conn comment=WAN2 
add action=mark-routing chain=prerouting dst-address-list=!local_subnet \
    dst-address-type="" new-routing-mark=rtab-WAN3 passthrough=no \
    src-address-list=WAN3-conn comment=WAN3 
add action=mark-routing chain=prerouting dst-address-list=!local_subnet \
    dst-address-type="" new-routing-mark=rtab-WAN4 passthrough=no \
    src-address-list=WAN4-conn comment=WAN4

#NAT
/ip firewall nat
add action=masquerade chain=srcnat out-interface=pppoe-WAN1  routing-mark=rtab-WAN1 comment=WAN1 
add action=masquerade chain=srcnat out-interface=ether2-WAN2 routing-mark=rtab-WAN2 comment=WAN2
add action=masquerade chain=srcnat out-interface=ether3-WAN3 routing-mark=rtab-WAN3 comment=WAN3
add action=masquerade chain=srcnat out-interface=ether4-WAN4 routing-mark=rtab-WAN4 comment=WAN4
add action=masquerade chain=srcnat out-interface-list=WAN comment=WAN-Fallback

#CREATE RULE for ROUTING-MARK defined in Mangle
/routing rule
add action=lookup disabled=no routing-mark=rtab-WAN1 table=rtab-WAN1
add action=lookup disabled=no routing-mark=rtab-WAN2 table=rtab-WAN2
add action=lookup disabled=no routing-mark=rtab-WAN3 table=rtab-WAN3
add action=lookup disabled=no routing-mark=rtab-WAN4 table=rtab-WAN4


#NOW Time to setup IP>ROUTE
#WAN-Fallback: distance 11,12,13,14 dynamically added in DHCP and PPPoE configuration above
/ip route
add disabled=no distance=2 dst-address=0.0.0.0/0 gateway=pppoe-WAN1 \
    routing-table=rtab-WAN1 scope=30 target-scope=10
add disabled=no distance=2 dst-address=0.0.0.0/0 gateway=ether2-WAN2 \
    routing-table=rtab-WAN2 scope=30 target-scope=10
add disabled=no distance=2 dst-address=0.0.0.0/0 gateway=ether3-WAN3 \
    routing-table=rtab-WAN3 scope=30 target-scope=10
add disabled=no distance=2 dst-address=0.0.0.0/0 gateway=ether4-WAN4 \
    routing-table=rtab-WAN4 scope=30 target-scope=10

Look at this line:
/ip firewall mangle
add action=mark-routing chain=prerouting dst-address-list=!local_subnet new-routing-mark=rtab-WAN1
It is substantial when we only want to mark connection to internet. So local connection not affected by Table Rule.

Cheers

An easier way is simply add :
dst-address-type=!local

local - already defined value.

So - no need to manage local_subnet list

I tried it on Router OS v7.16, but it doesn’t seem to work as I expected.

No! dst-address-type local is not what you think. local in this case means all the individual IP addresses of the router itself, and it includes any WAN public IP addresses of the router too. It doesn’t contain the subnets of the LAN interfaces!

I might be wrong, lets find out the truth.
https://wiki.mikrotik.com/Manual:IP/Firewall/Mangle
dst-address-type (unicast | local | broadcast | multicast; Default: )
local - if dst-address is assigned to one of router’s interfaces

So my guess is that ip-to-interface assignments located : IP->Adresses
I suppose that all the interface-to-address assignments are included into “local” alias.
As well as defconf bridge like this:
/ip address
add address=192.168.0.1/24 comment=defconf interface=bridge network=192.168.0.0

There is normally another defconf:
/interface list member
add comment=defconf interface=bridge list=LAN

Am I wrong ?

In your example dst-address-type=local will match 192.168.0.1 (that single /32 address) but not 192.168.0.2, 192.168.0.3, etc… So, you can’t use it to replace dst-address=192.168.0.0**/24**! Similarly, dst-address-type=!local excludes 192.168.0.1 but will happily match 192.168.0.40, which means it’s not a replacement for dst-address=!192.168.0.1/24.

with this definition of local_subnet from @Lokamaya’s post:


/ip firewall address-list
#local subnet: needed for Mangle
add address=192.168.0.0/16 list=local_subnet
add address=172.16.0.0/12 list=local_subnet
add address=10.0.0.0/8 list=local_subnet

then

dst-address-type=!local

is 100% not a replacement for

dst-address-list=!local_subnet

It would only replace

dst-address-list=!router_ips

if router_ips were for example defined as:

/ip firewall address-list
add address=192.168.10.1/32 list=router_ips
add address=192.168.20.1/32 list=router_ips
add address=91.82.73.64/32 list=router_ips

where 91.82.73.64 is a WAN IP addresses provided by the ISP, and for instance 192.168.10.1/24 and 192.168.20.1/24 were assigned to two interfaces of the routers.

Great point. Agree..