My ISP (Sky TV in the UK) does something rather irritating. They run a packet level filter on all traffic and intercept port 53 traffic in order to handle all DNS requests within their own system. You can test if your ISP does this by issuing this command.
nslookup google.com 45.45.45.45
Since 45.45.45.45 is not a public DNS server, the request should fail. If however it works and returns a result, then your ISP is caching DNS requests. This is REALLY bad because it negates the use of public DNS servers like 8.8.8.8 and causes latency on DDNS updates. There's privacy issues too, especially if the ISP is logging the requests (which it probably is). There's a whole host of other issues this can cause as well. Your ISP can resolve non-existent domains to their own IPs in order to show a custom "This Webpage does not exist" message in your browser. While that seems harmless at first, if you use DDNS systems a lot, this can cause huge issues when the software thinks a domain exists when it does not because it gets a DNS resolution from it. Trust me, it's a bad thing.
So anyway, enough with the rant. Let's get on to how I solved this.
First, I got myself a VPS (Virtual Private Server). I actually already had one, but I strongly recommend you get one. They are useful for a whole host of stuff. They are also quite inexpensive, mine only costs $5 a month. The place I use is called Digital Ocean, but that's just who I use, any VPS should do the trick. In my setup I also enabled IPv6 but that's optional. I also selected Ubuntu 18.04 as the operating system, so my tutorial here will be based on that. I should also mention that my Pi-Hole is also running on Ubuntu 18.04 which is on a thin client connected to my LAN.
Once logged into the VPS with SSH I went ahead and installed bind with this command
sudo apt install bind9
Once that was installed, I edited the config file with the following command
sudo nano /etc/bind/named.conf.options
There will be some stuff in here, just delete all of that and replace it with this
options {
directory "/var/cache/bind";
dnssec-validation auto;
recursion yes;
auth-nxdomain no;
listen-on-v6 { any; };
forwarders {
8.8.8.8;
8.8.4.4;
};
forward only;
listen-on port 5555 { any; };
query-source port 5555;
allow-query { any; };
};
The listen-on-v6 line is only if you are using IPv6 of course. Obviously, you can change the forwarders to whatever you like and I would recommend changing the port from 5555 to any random port you want. Avoid using 5353 or other easily guessable port. And remember to open the port in the linux firewall. I won't go into that because different VPS providers use different ways of firewalling. They may have a network level firewall or may have to use linux iptables. I'll leave that up to you how you manage that. If your home IP is static it is worth only allowing access from your static IP. If it's dynamic, it'll probably always be in the same subnet, so only allow access from that subnet to limit the chances of your server being found and abused. I recommend using a firewall to block requests rather than using ACP because although ACP will deny requests it will expose that there is a service running. Also remember that if you're using IPv6 that there is a completely separate firewall for that, make sure you make the changes to both IPv4 and IPv6 firewalls.
Now restart the server
sudo service bind9 restart
Check it's working with
sudo service bind9 status
Now, that part of the setup is complete. Let's go over to Pi-Hole. Open your Pi-Hole Admin Console and select Settings on the left. Then select DNS at the top. Untick all the Upstream DNS servers on the left. On the right tick Custom 1 (IPv4) and enter the IP address of your VPS into the box followed by a # and the port number you chose. Assuming my VPS's IP is 66.77.88.99 and the port I used is 5555 I would enter
66.77.88.99#5555
Also, if you have IPv6 you should also tick Custom 3 (IPv6) and do the same, except use the IPv6 address followed a # and the port number. So assuming my v6 IP is 2a06:4433:1:a5::500a you would enter
2a06:4433:1:a5::500a#5555
Now scroll to the bottom and hit Save. That should be it.
Note: You may have to jump into the Pi-Hole server shell and restart it. I had to at least.
sudo service pihole-FTL restart
Job's done. No more ISP DNS caching.
Thanks to DanSchaper for showing me how to configure non-standard ports in Pi-Hole.