Redirect traffic to loopback

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

5 thoughts on “Redirect traffic to loopback

  1. 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.

  2. 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?

Leave a Reply

Your email address will not be published. Required fields are marked *

four + three =