In setting up our OpenStack environment, I ran into a problem that was preventing instances from contacting a server running on the host. The metadata service (which exposes an HTTP API) runs on port 8775 on the host, and the OpenStack networking code adds the following DNAT rule to grant access via a special address on port 80:
-A PREROUTING -d 169.254.169.254/32
-p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8775
Instances are connected to the host via a local bridge device, and 169.254.169.254
is assigned to lo
.
While this rule successfully matches packets originating from a guest instance trying to access http://169.254.168.254/
, they never reach the listening service.
Replacing this DNAT rule with a largely equivalent REDIRECT makes everything work correctly:
-A PREROUTING -d 169.254.169.254/32
-p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8775
I'm trying to understand why the REDIRECT works and the DNAT fails. It's not clear from the iptables documentation whether or not the DNAT
rule is expected to work for locally destined traffic. I'm hoping someone here can provide an authoritative answer, ideally backed up by documentation, or can suggest what might be amiss in my configuration that is preventing the DNAT rule from working as expected.
What you're trying to do is explicitly denied by the kernel.
This presumably happens because
rp_filter
defaults to on. Possibly disabling it might alter this behavior (although that will disable some potentially crucial security protection).With the REDIRECT you're not changing the IP, which is why it works. To put it another way, if you're going to use DNAT you can send it to anything outside of 127.0.0.0/8.
According to the netfilter NAT HOWTO:
It's slightly more intelligent in that it chooses the DNAT target address as the address of the device which the packet was received on. In your case it would DNAT the packets to the address on the bridge device, and not to 127.0.0.1.