Normally when you set up a local DNS resolver you would keep a list of your local boxes with their associated local IP addresses and then just forward everything else to a remote resolver like OpenDNS, but this approach is ill-adviced if you're running a VPN connection on some of your computers as this setup is a security flaw that will cause a DNS leak.
If you run your entire local network through the VPN service for Internet connections then this issue isn't a problem as all requests runs through the VPN. But if you only run a single machine, like your desktop or laptop, through the VPN, while at the same time you use your local DNS resolver for DNS requests, you have created a security flaw that will cause your DNS requests to be leaked.
A DNS leak means that the true IP address of your Internet connection will be revealed to websites, despite the use of a VPN service to conceal it!
You don't have to run the entire network through the VPN connection in order to prevent DNS leakage, you can split your DNS requests between local requests and remote requests such that only the local requests goes to the local DNS resolver while the remote requests goes through the VPN connection.
Several methods exists that can split your DNS requests up between local ones and remote ones, but the easiest to set up is to use DNSMasq as a DNS splitter on the computers you run the VPN on. A positive side effect of this setup is also that you get DNS caching service on your computers.
In order for this to work correctly the best thing to do is to use a top-level domain on all your local machines, but you can also use something like
.internal instead. In this setup I will assume that you are going to use a real domain, but you can change it to your liking.
If you're a programmer and you're developing online applications and have to deal with both testing and production setups, then one huge advantage of using a real domain is that you don't need to have separated setups. This will hopefully be obvious in a moment.
I assume that on your local DNS server you have a list of computer hostnames with their associated IP addresses.
Unbound it would look like this:
local-data: "foo IN A 192.168.1.2" local-data: "bar IN A 192.168.1.3" local-data: "baz IN A 192.168.1.4"
DNSMasq it would look like this:
address=/foo/192.168.1.2 address=/bar/192.168.1.3 address=/baz/192.168.1.4
You need to change this setup into one that uses a top-level domain, whether you use
.internal or a real domain doesn't matter, but in this example I am going to use
Unbound it would then look like this:
local-data: "foo.example.com IN A 192.168.1.2" local-data: "bar.example.com IN A 192.168.1.3" local-data: "baz.example.com IN A 192.168.1.4"
DNSMasq it would then look like this:
address=/foo.example.com/192.168.1.2 address=/bar.example.com/192.168.1.3 address=/baz.example.com/192.168.1.4
In order to avoid having to type
foo.example.com every time you want to access machine
foo, you can add the
search parameter to your /etc/resolv.conf file. How you do that depends on whether you're manually editing /etc/resolv.conf or you have some kind of network manager handle that.
If you're using some kind of network manager you need to look into how to have it add the
search parameter to /etc/resolv.conf. You cannot simply add it manually as your network manager will overwrite /etc/resolv.conf once the computer is rebooted or the connection is restarted.
On Linux Mint, Ubuntu, and several other Linux distributions the system uses the resolvconf package to control the /etc/resolv.conf file (please notice that the similarity between the names is not a mistake, resolvconf is a program while resolv.conf is a text file).
On Linux Mint for example /etc/resolv.conf is replaced by a symbolic link to /etc/resolvconf/run/resolv.conf which is dynamically generated. This is why /etc/resolv.conf contains the following warning:
DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
On Linux Mint you can instead edit /etc/resolvconf/resolv.conf.d/base and add the
search parameter there, it will then be used as a template for /etc/resolv.conf
If you manually handle /etc/resolv.conf simply edit it and make sure you have the right
search parameter and that all future DNS requests goes to your local host on 127.0.0.1.
/etc/resolv.conf needs to look like this:
search example.com nameserver 127.0.0.1
This means that all DNS requests goes to 127.0.0.1, which is were you will install DNSMasq and then have that split the requests between your local DNS resolver and a remote one.
search parameter means that instead of writing
ping foo.example.com you can simply write
ping foo. The domain part
example.com will then automatically be added to
Once you have changed your settings you need to restart the network or simply reboot the machine.
You might consider adding the
search example.com part to /etc/resolv.conf on your server box as well in case you're running other services than DNS on that box. That way you don't need to change scripts or firewall rules from
If you're a programmer and you're running with different setups on a production system and a development system the benefit is that you don't need to change configuration options in your different files.
I'll use PHP as an example.
// Production setting. $hostname = 'foo.myproduction.com' // Development setting. $hostname = 'foo.testing.internal'
search parameter in place all you need is:
$hostname = 'foo'
If the application is running on the production machine
myproduction.com will automatically be added to
testing.internal will be added to
foo on the development machine.
Now you have to install
dnsmasq. On Debian based distributions
dnsmasq exists in the repositories so you can use
apt-get to install it.
# apt-get install dnsmasq
Once it has been installed you need to edit /etc/dnsmasq.conf and enter your local DNS resolver and the remote ones you want to use. You need to make sure that your local DNS resolver comes first. In this case I am assuming that your local DNS resolver runs on 192.168.1.1.
# Local DNS resolver. server=/example.com/192.168.1.1 # OpenDNS remote resolvers. server=126.96.36.199 server=188.8.131.52
Next you need to restart
# /etc/init.d/dnsmasq restart
Or if you're using systemd:
# systemctl restart dnsmasq
Now, whenever you're making a DNS request all local requests will first be added the top-level domain
example.com to the hostname and then forwarded to your local DNS resolver on 192.168.1.1.
You can test this by using
nslookup. If you're using
dig you need to know that it does not use the
search list from /etc/resolv.conf by default so you need to use it like this
dig +search foo in order to test.
$ dig +search foo ;; ANSWER SECTION: foo.example.com. 3461 IN A 192.168.1.2 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1)
$ nslookup foo Server: 127.0.0.1 Address: 127.0.0.1#53 Non-authoritative answer: Name: foo.example.com Address: 192.168.1.2
In both cases the
foo hostname is added to the
example.com domain part automatically and the request then goes to 127.0.0.1 which forwards the request to your local DNS resolver.
If you try to resolve a hostname that doesn't exists in your local DNS resolver you will get an empty reply like this:
$ dig +search bob ;; QUESTION SECTION: ;bob. IN A
Now comes the important part. In order to verify that your remote DNS requests goes to your remote resolvers through your VPN connection you need to listen to your VPN tunnel interface and verify it at that end. You can do that with
On Debian based distributions
tcpdump exists in the repositories so you can use
apt-get to install it.
# apt-get install tcpdump
In this case I am assuming that your VPN connection runs on the
tun0 interface, but you have to check your VPN settings.
Open up a console and perform a
tun0 as root:
# tcpdump -i tun0 -n
Next, open up another console and perform a
dig for say
$ dig yahoo.com
On the console where you're performing the
dig you will notice that the request still goes to DNSMasq on 127.0.0.1, but the console with the
tcpdump will reveal that the request is actually forwarded to OpenDNS via your
tun0 VPN interface.
IP 10.0.10.3.27248 > 184.108.40.206.53: 15420+ [1au] A? yahoo.com. (38)
The IP 10.0.10.3 is the IP address for the
tun0 interface and the 220.127.116.11 IP address is the main DNS resolver at OpenDNS.
If you have made a mistake or something isn't working right and the request goes to your local DNS resolver, the
tcpdump will stay quiet and you won't be able to see the request. If this is the case you need to verify your DNSMasq setup.
If your VPN service has their own DNS servers it is maybe preferable to use theirs, but using other remote DNS servers isn't a problem because all remote DNS requests still run through the VPN interface.
Feel free to email me any suggestions or comments.