Hosting a public DNS
When I installed this host (which is more powerful than the old one), I tought it might be cool to provide public service(s) to people on the internet. As a result, the first service which was publicly available was a teamspeak server (Yeah, I’m a gamer too). Few months ago, I discovered The OpenNIC project, which is pretty cool to bypass your ISP DNS/ICANN (for any reason, this post is not about why? but how?). You know where I’m going, right?
So, let’s see what do we need to set up a public recursive resolver and the features we want to provide:
- First think first, we need a DNS software
- Configure properly the firewall
- No logging (DNS requests)
- Use OpenNIC root servers
I decided to use unbound, which is a modern approach for DNS resolving, easy to configure, fast and secure.
To set up the resolver, all you need is this configuration:
server: verbosity: 1 statistics-interval: 3600 interface: W.X.Y.Z access-control: 0.0.0.0/0 allow root-hints: "/var/unbound/etc/opennic.cache" hide-version: yes log-queries: no
Important things here, which is part of my requirements, is:
which contains Dig results for OpenNIC glue servers.
And no logging for DNS requests:
Now, the last thing is to correctly configure our firewall, because once this service exposed, we don’t want to be part of a DNS Amplification attack. For details about this kind of attacks, I let you read the previous link, but basically, an attacker sends lot of ANY type requests. What we want is not blocking all ANY requests but limiting their rate.
This will limit to two ANY requests every 120 seconds per IP address:
iptables -A INPUT -p udp --dport 53 -m string --algo bm --hex-string "|00 00 ff 00 01|" --to 255 -m recent --set --name dnsanyquery iptables -A INPUT -p udp --dport 53 -m string --algo bm --hex-string "|00 00 ff 00 01|" --to 255 -m recent --name dnsanyquery --rcheck --seconds 120 --hitcount 2 -j DROP
Now we limit the amount of regular packets per IP to 40 per minute with 10 packets for burst traffic (free packets before averaging)
iptables -A INPUT -p udp -m hashlimit --hashlimit-srcmask 24 --hashlimit-mode srcip --hashlimit-upto 40/m --hashlimit-burst 10 --hashlimit-name DNSTHROTTLE --dport 53 -j ACCEPT
Of course you need to put these rules at the right positions in your INPUT chain. You also need to open the DNS port (53) for both UDP and TCP after these rules.
You will look something similar to this when listing rules:
0 0 DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 STRING match "|00000000000103697363036f726700|" ALGO name bm TO 65535 udp dpt:53 0 0 DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 STRING match "|0000000000010472697065036e6574|" ALGO name bm TO 65535 udp dpt:53 208K 14M udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 STRING match "|0000ff0001|" ALGO name bm TO 255 recent: SET name: dnsanyquery side: source mask: 255.255.255.255 208K 14M DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 STRING match "|0000ff0001|" ALGO name bm TO 255 recent: CHECK seconds: 120 hit_count: 2 name: dnsanyquery side: source mask: 255.255.255.255 5432 312K ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 limit: up to 40/min burst 10 mode srcip srcmask 24 udp dpt:53 2 92 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:53 2832 198K ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 root-hints: "/var/unbound/etc/opennic.cache"
- 208K packets hit the limit for ANY queries
- 5432 packets hit the limit for regular queries
- 2832 packets were accepted for resolving.
As a conclusion, I made this post to expose the configuration for my public resolver, I know this is succinct, but if you want further details, you should go see the OpenNIC project and/or post a comment. In addition, you can use freely this resolver using 22.214.171.124 as primary DNS. Hope you’ll enjoy it.