I'm not affiliated with MT
"DNS leak" in VPN scenario usually denotes "resolving names through DNS server other than VPN provider's".
If you'll route traffic from a "client group" (identified with network addresses, ports, L7 patterns used, whatever) to a VPN, but don't use VPN provider's DNS servers to resolve names for this client group (you're asking for it when you want to disable adding DNS servers received with IPsec mode-config to ROS DNS client), it would create a genuine DNS leak - the traffic goes though VPN, but names are resolved through your ISP's (or Google's/other) DNS servers.
Your "leak" is different, and your "hotfix" is just a required part of configuration for proper VPN use. (You really shouldn't expect a system to do this configuration for you.)
But this would work properly only if you have no other DNS servers in ROS DNS configuration. Otherwise you'll still get a DNS leak - ROS would also query DNS servers other than your VPN provider's.
DNS server in ROS is very basic
. Merely a responder on top of built-in resolver (client). It doesn't have advanced features like source-based query forwarding and separate caches for different client groups. Without these features you can't use one DNS server to serve two or more client groups that have to be separated (like "normal clients" and "VPN clients").
So if you want two client groups to be separated, you shouldn't use ROS DNS server for at least one group.
Luckily, DNS protocol is generally server-agnostic (you may NAT or otherwise redirect a query to another server and in most cases nobody would notice), so the solution would be dst-NAT'ting DNS queries
with proper selectors (the same as you're using to distinguish your client groups - network addresses, ports, L7 patterns used, whatever).
As you'll do it in prerouting chain, you'll effectively bypass ROS DNS server (as a side effect your local static DNS entries won't resolve).
/ip firewall nat add chain=dstnat action=dst-nat protocol=udp dst-port=53 <your "VPN clients" selectors> to-addresses=<right address>
Another problem that currently you can't disable adding DNS servers received with IPsec mode-config to ROS DNS client
. It was discussed here since at least 2015, but I don't know if the feature was ever requested from MT (and, if it was requested, will it be ever added).
To make the matter worse, you can't dst-NAT in output chain
, so you can't just redirect queries made to VPN provider's DNS servers back to your ISP's DNS servers.
There's a solution that is used to emulate cDNS (conditional DNS server selection - query domain-a from DNS-a, domain-b from DNS-b, etc.) in ROS DNS client, but it may not worth the comlexity added (and some users may find it quite mind-blowing
) - as you can only dst-NAT in input and prerouting chains, you need to somehow get outbound packets from DNS client into these chains, and it could be done with a tunnel looped back, with corresponding connection-marks, some extra NAT and routing (original cDNS implementation courtesy of @Sob, based on similar config by @sindy):
# Make a (bridge) interface for loopback tunnels, and set an local address to it.
/interface bridge add name=bridge-loopback protocol-mode=none
/ip address add address=127.0.0.2 interface=bridge-loopback network=127.0.0.2
# Make two IPIP tunnels pointing at each other. Addresses on them are not required.
# Since some 6.4x version it's required to have allow-fast-path=no on at least one of these tunnels, or the packets won't pass through
/interface ipip add local-address=127.0.0.2 name=ip2t-loopback-in remote-address=127.0.0.1
/interface ipip add local-address=127.0.0.1 name=ip2t-loopback-out remote-address=127.0.0.2 allow-fast-path=no
# Step 0: DNS client sends query to a wrong server.
# Step 1: Outbound queries from DNS client to wrong server are routed to "out" tunnel with routing mark. In cDNS scenario level7 condition goes here.
/ip firewall mangle add chain=output action=mark-routing protocol=udp dst-port=53 dst-address=<wrong address> new-routing-mark=rm-loopback
/ip route add distance=1 gateway=ip2t-loopback-out routing-mark=rm-loopback
# Step 2: Queries src-NATted as they go out to the "out" tunnel to some address not used elsewhere, to recognize replies when they'll come back. Here we may use more addresses with corresponding conditions (useful in cDNS scenario if you have more than one conditional server). Routing to this subnet is added to get replies back to "in" tunnel.
/ip firewall nat add chain=srcnat action=src-nat protocol=udp dst-port=53 out-interface=ip2t-loopback-out to-addresses=10.53.0.1
/ip route add distance=1 dst-address=10.53.0.0/16 gateway=ip2t-loopback-in
# Step 3: Queries coming in from "in" tunnel are dst-NATted as required (all the BS is for this line!). In cDNS scenario with more than one conditional server we'll add src-address condition with address used in #2 and corresponding to-addresses.
/ip firewall nat add chain=dstnat action=dst-nat protocol=udp dst-port=53 in-interface=ip2t-loopback-in to-addresses=<right address>
# Step 4: Source address in queries changed once again to proper one for the outbound interface as they are sent out.
/ip firewall nat add chain=srcnat action=masquerade protocol=udp dst-port=53 out-interface=<proper outbound interface> src-address=10.53.0.0/16
# Step 5: Replies coming in and their dst address is getting NATted (back to 10.53.0.1) per #4.
# Step 6: Replies (now to 10.53.0.1) are routed to "in" tunnel per routing in #2.
# Step 7: Src address in replies NAtted (back to <wrong address>) as they go out to the "in" tunnel per #3.
# Step 8: Dst address in replies NAtted (back to ROS address) as they come in from "out" tunnel per #1.
# Step 9: DNS client receive replies that appear to be from <wrong address>, but actually they're from <right address>.
If you'll use both kludges, your VPN clients will not leak DNS queries as they will be always forwarded to VPN provider's DNS, and your ROS DNS client will work normally, never resolving anything through VPN provider's DNS (even though it will have these servers in its list).