Today I wanted to transparantly redirect the DNS requests coming at the output of a tunnel to a local caching DNS resolver. The caching DNS was listening only on the loopback as port 53 was already bound to other interfaces. That would be fairly simple on Linux:
echo 1 > /proc/sys/net/ipv4/ip_forward iptables -t nat -A PREROUTING -i tun0 -p udp --dport 53 -j DNAT --to-destination 127.0.0.1 iptables -A FORWARD -i tun0 -o lo -p udp --dport 53 -j ACCEPT
But… The kernel will refuse to route packets with the loopback as source or destination because this qualify as a martian packet. The solution was to enable the route_localnet
flag. As stated in the kernel documentation:
route_localnet – BOOLEAN: Do not consider loopback addresses as martian source or destination while routing. This enables the use of 127/8 for local routing purposes (default FALSE).
This is per interface. So I just had to enable this on the tunnel interface:
echo 1 > /proc/sys/net/ipv4/conf/tun0/route_localnet
Omfg, I’ve been spending days to searching for an answer and trying countless of commands on the terminal. Finally I can get it to work. Thank you very much.
Thanks for sharing your finds … I need to redirect DNS queries originated from localhost to loopback BIND resolver … for example, an app on localhost, sends dns queries to 1.1.1.1, but I want to redirect it to the same 127.0.0.1 host …
Any help will be appreciated.
I’m assuming that 1.1.1.1 is a globally routable address that has a default route on some interface, like eth0. Did you try to DNAT on this interface? Like:
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to-destination 127.0.0.1
Also did you check that the request was made with IPv4, and not IPv6?
Also it’s strange that a local app resolves to some specific address that differs from the local resolver. What about /etc/resolv.conf?
I have VLESS+Trojan proxy on a server which receives DNS queries and sends them to selected destination by user. For example, if a user has selected to proxy dns queries to 1.1.1.1, the proxy receives and directs them to 1.1.1.1.
But I want to forward them to 127.0.0.1 since a local BIND resolver is present on the server.
I exactly executed your command except ‘OUTPUT’ instead of ‘PREROUTING’ since the proxy which should handle received dns traffic, is present on the localhost. So, ‘OUTPUT’ chain is for that.
I also did other tricks like enabling IP forwarding, changing FORWARD chain default policy to ACCEPT, turning on route_localnet, but nothing answered.
A simple dig command returns nothings. (No internal_route error, no destination unreachable error, nothings)
I’m suspicious about NAT (SNAT, MASQUERADE, …), but don’t have any idea how to use them.
well I don’t know, did you got any clue running tcpdump on the interfaces? Are the DNS requests actually sent? Are they translated correctly on the output interface?