I have a Bind9 on a host.
I have several guest virtual machines.
I want my virtual machines to use the Bind9 located on the host.

I know how to make Bind9 accept requests from my vitual machines (listen-on + allow-recursion).
I want to achieve it using iptables/netfilter, without modifing Bind9 configuration (aka listen only on
--> this is just a local port redirection. I know how to do it with socat, but I'm stuck when doing it with iptables/netfilter

Bind listen only on, so the packets must originate from
The virtual machines are on a bridge vmbr0
The host is also on the bridge at

Should I make the packets enter into a custom chain, then DNAT+SNAT them, or is there a simplier way?

I did that (but does not work):

sysctl -w net.ipv4.conf.vmbr0.route_localnet=1     # not sure if necessary. Let's see that when everything will work

iptables  --table nat  --new-chain dns-prerouting
iptables  --table nat  --append PREROUTING  --source  --destination  --protocol udp  --destination-port 53  --jump dns-prerouting
iptables  --table nat  --append PREROUTING  --source  --destination  --protocol tcp  --destination-port 53  --jump dns-prerouting

iptables  --table nat  --new-chain dns-postrouting
iptables  --table nat  --append POSTROUTING  --source  --destination  --protocol udp  --destination-port 53  --jump dns-postrouting
iptables  --table nat  --append POSTROUTING  --source  --destination  --protocol tcp  --destination-port 53  --jump dns-postrouting

iptables  --table nat  --append dns-prerouting   --jump DNAT  --to-destination
iptables  --table nat  --append dns-postrouting  --jump SNAT  --to-source

You have to use sysctl -w net.ipv4.conf.XXX.route_localnet=1 as you did, but probably on the virtual Ethernet interface.
This allow the kernel to keep martin packets.

Also keep in mind that locally generated packets does not pass into the PREROUTING chain. So you have to use the OUTPUT chain.

And finally don't try to NAT for this very special case. Use --jump TPROXY instead.
I can't give you a working example by memory, you have to find the exact setup. Then please complete the answer for future reference.

| improve this answer | |
  • Many thanks for TPROXY. I didn't even knew it. My first tests give way much better results: the packets reach BIND, which was not the case with every previous tests. I have to refine the rules to let packets return to the sender. I think the final result will involve only 4 rules. I will update the question and the answer once everything will be ok. – Gregory MOUSSAT Feb 7 '17 at 12:40


You will need DNAT because you will need the packages coming from the VMs to go to on lo instead of You obviously can't configure the VMs to access localhost as DNS, either, at least that would only further complicate things.

On lo, you might need SNAT, because in lo you might have problems with non-local addresses that don't belong to the network.

I'm assuming bind is only listening on lo: It also appears you've forgotten about the return way of the DNS packets from BIND to the VMs in your configuration sample. BIND can then only put packages into lo. So you will need to get those out of lo and into the VM network, here you might not need SNAT, depending on how picky the DNS client on your VM is. If you've used SNAT above, you will need DNAT now.

Finally, I'm a bit curious why it would be worth the effort... it sounds like it might be much easier to implement the firewall rules to isolate BIND from whatever you want to isolate it from, even to give it its own other virtual network, then to use lo. Maybe if you'd describe why BIND must be on lo, it might be possible to find a better way to solve the problem.

For the way to the DNS:

iptables -F -t nat
echo 1 >| /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p udp -d --dport 53 \
 -j DNAT --to 

For the way back to the VMs:

iptables -A FORWARD -i lo -o vmbr0 -m state \

If that doesn't work you might need:

iptables -t nat -A POSTROUTING -o lo -j MASQUERADE

It's all a bit 90% there because I don't have such a setup to try. Please be aware it's generally not a good security decision to forward anything to lo. lo is mean to be exclusively localhost.

| improve this answer | |

The complete setup for UDP, TCP, IPv4 and IPv6 is complex. Use a DNS forwarder (proxy) for your VMs. My recommendation is dnsmasq:

dnsmasq -dq -I lo -S

Forwards all requests to the server running on localhost, but ignores the loopback device itself. Later, run dnsmasq as daemon without the -dp options.

-d or --no-daemon
-q or --log-queries
-S or --server
-I or --except-interface
| improve this answer | |
  • 1
    The question is related to iptables/netfilter, not to installing+configuring a software on whatever computer. And it is clearly stated in the question I already know how to make BIND listen for VMs, which is simplier than installing another program. And I also know how to deal with dnsmasq, but this don't meet my goal, else the question wouldn't exist. – Gregory MOUSSAT Feb 5 '17 at 21:41
  • Sorry, I just wanted to help. – ingopingo Feb 11 '17 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.