It seems finally I could get it working with the combined ideas of @lurker888, @wiseroute, @Larsa and myself.
Note that neither DNAT or SNAT by itself work for the reasons I mentioned a couple of times. It is important to indeed use a separate dummy device for DNAT. It is also necessary to create a dummy routine table and PBR rules based on source address
Anyway, let me just post my solution:
/interface bridge
add arp=disabled fast-forward=no name=dum1 protocol-mode=none
/ip address
add address=172.20.215.1 interface=dum1 network=172.20.215.1
/routing table
add comment="Dummy table containing a default route for everything from 172.20.215.1" fib name=bugfix_wg
/routing rule
add action=lookup-only-in-table src-address=172.20.215.1 table=bugfix_wg
/ip firewall mangle
add action=mark-routing chain=output log=yes log-prefix="[***WG-MANGLE-RT]" new-routing-mark=default_myas passthrough=yes protocol=udp src-address=172.20.215.1 src-port=51820
/ip firewall nat
add action=dst-nat chain=dstnat dst-address=192.0.2.210 dst-port=51820 log=yes log-prefix="[***WG-DNAT]" protocol=udp to-addresses=172.20.215.1 to-ports=51820
This is how I think it works:
- The DNAT rule as prev proposed translates 192.0.2.210 → 172.20.215.1
- For the translation of the return packet to work, it is instrumental that wireguard will use 172.20.215.1 as source address
- This is accomplished by using dummy table bugfix_wg and looking it up when the source address comes from the dum1 interface (src-address=172.20.215.1). (Note: Would it be correct what @lurker suggested that for the initial “routing decision” the src-address rule can’t be selected because source address is empty, this wouldn’t work. But my table is clearly selected)
- Now the packet is in interface dum1 with source address 172.20.215.1. This is important because only now the source address can be reverted by the connection tracking of the DNAT rule!
- However, now the packet would never get out because it’s stuck in dum1 (via dummy routing table). Hence the mangle rule ensures that the routing decision is overruled and the “default_myas” table is selected
I did not expect this could ever work and this is the worst hack I have ever done. In 3 months from now I will have no clue how and why this configuration works. Only because of an (in my opinion), terrible wireguard design decision and implementation. Would just one of these be implemented, one wouldn’t have to revert to such criminal hacks:
- Do not just bind to any interface/address of the system; at least support “bind-address”
- Do not just leave the source port unset (especially when there was no connection context before and a client just connected to the right endpoint address)
- Do implement VRF for wireguard