An irritating iptables limitation
I have a machine that runs both a caching DNS server (to answer local queries) and an authoritative DNS server; the caching server is bound to localhost:53, and the authoritative server to my-IP:53. Recently I wanted to let another machine use the caching DNS server.
The obvious general approach is to remap queries from the specific IP so that they hit the caching nameserver instead of the authoritative one. I can see two ways of doing this with Linux iptables: DNAT and REDIRECT. Unfortunately neither work:
- REDIRECT redirection doesn't work because it 'redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface' (emphasis mine), not to localhost. In effect REDIRECT is a no-op here.
- DNAT redirection to localhost doesn't work at all, apparently because the kernel discards outside packets to localhost as 'martians', which matches the behavior I saw. Nor can you combine the DNAT rule with a SNAT rule to rewrite the source address to 127.0.0.1 to get around it, as far as I can tell.
Now, there are hacky ways around this. One of them would be to give the machine an additional completely private IP address, have the caching DNS server listen on it too, and use DNAT to reroute packets to that instead of localhost. But the need for that sort of workaround irritates me.
(The one useful thing to come out of this is that I had it pointed out to me that REDIRECT doesn't have to change the destination port; for some reason I had had the impression that it did.)