I am using ipset with Pi-hole for a long time. It is very performant and a lot better than what other popular script like fail2ban are doing with adding thousands of individual rules to the firewall.
The dnsmasq man page wrongly suggests that you need a domain for this to work but maybe this is only a Pi-hole enhancement. You can simply use
ipset=pihole
to add the IPs of all queries to the pihole ipset. You can see what happens as lines like ipset add ... are added to /var/log/pihole.log if you do it properly.
The ipset needs to exist, created by something like
ipset create pihole hash:ip
or you will see errors.
First, add a rule for the Pi-hole itself that allows the Pi-hole to connect to ports 53 worldwide to exclude the Pi-hole from being blocked to reach the DNS servers:
iptables -A INPUT -d 127.0.0.1 --sport 53 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 127.0.0.1 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
Finally, configure iptables to permit only addresses in that set:
iptables -I INPUT -m set --match-set pihole src -j ACCEPT
iptables -I FORWARD -m set --match-set pihole dst -j ACCEPT
iptables -I OUTPUT -m set --match-set pihole dst -j ACCEPT
and set the default policies to DROP:
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
This configures you firewall to only permit outgoing and forwarding to and incoming from traffic to IP addresses derived via DNS.
Pro tips:
- You can check the IP addresses with
ipset list pihole - Do the same for IPv6 using
ip6tables - Add Pi-hole port 53 rules for IPv6, too
- The ipset you have created is stored in memory for speed. It will be gone after reboot. Use
ipset save > /some/backup.fileto backup youripsetwhen rebooting or your clients may experience issues when rebooting the device.