At home, I wanted to bring up two pihole docker containers: One to block ads for all devices in my home network, the other one to additionally block youtube and adult content for our kids only.
First, I just blocked some domains via the FritzBox's childlock capabilities.
But this leads to generally blocking all client requests on IPs...
So if you enable website filtering on your FritzBox all calls by IP are blocked...
This makes it impossible to watch Netflix, as the Netflix client always calls its streaming servers via IP, not DNS name :|
I was looking for a solution which allowed me to
- block youtube and adult content on kids' devices
- block ads on all devices
- allow Netflix
Finally I was able to do it with two pihole docker containers.
The piholes run on docker on my gentoo server at home.
Setup and configuration of the piholes is straight forward as described on pihole's github for the docker image.
The piholes get fixed IPs, so the iptables rules always point to these fixed addresses for DNS lookups.
To route only the kids' devices to the kids' pihole, I'm routing their DNS traffic based on source MAC address.
So to achieve this task, your iptables have to support the mac matching extension (CONFIG_NETFILTER_XT_MATCH_MAC=y
).
You may compile it into your kernel or load it as a module.
I realized, many android devices nowadays set google's DNS as default or secondary DNS or switch to other DNS services if they cannot reach a DNS server.
For this case I reroute these connections via my FritzBox back to my home server's piholes.
haproxy is used to distinguish between calls to the piholes' http ports and calls to my apache running on the same host.
My setup
- gentoo linux server (here: 192.168.0.11)
- docker
- docker-compose
- haproxy
- iptables (with mac matching extension loaded)
- pihole docker image
- pihole-adults container (here: 172.31.10.10)
- pihole-kids container (here: 172.168.5.10)
- FritzBox 7430 (here: 192.168.0.1)
Start the piholes
Set DNS to the IP of your FritzBox and the ServerIP to your docker host.
Keep the port forwardings, so docker will make the appropriate iptables entries in the chains POSTROUTING and DOCKER.
pihole-adults.yml
|
pihole-kids.yaml
|
Save these docker-compose.ymls with your favourite editor and launch the piholes.
|
After starting, you should note the random generated admin passwords from the log output.
|
Setup haproxy
As mentioned above, I'm running a local apache which serves other stuff.
pihole needs to be available on ports 80 and 443 via the docker host's IP to serve its "blocked by pihole" site.
So at home I'm addressing my apache websites via the hostname of my server (here: thrall) and all other requests by IP should be answered by pihole-adults / pihole-kids.
My apache binds to port 8000 and haproxy does the proxying work.
Just replace thrall and 192.168.0.11
with your server's hostname / IP and (re)start your haproxy.
/etc/haproxy/haproxy.cfg
global log /dev/log local0 info daemon maxconn 256 defaults mode http option http-server-close timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend http-in bind :::80 v4v6 bind :::443 v4v6 ssl crt /etc/ssl/apache2/apache.pem option forwardfor # Define hosts acl host_thrall hdr(host) -i thrall use_backend apache if host_thrall default_backend pihole-http backend apache server thrall 127.0.0.1:8000 maxconn 32 backend pihole-http server thrall 192.168.0.11:8080 maxconn 32 |
pihole Admin Panels
Your pihole admin panels should now be available on
pihole-adults: http://192.168.0.11/admin
pihole-kids: http://192.168.0.11:9980/admin
Block Youtube and adult websites on pihole-kids
Go to the admin panel of your pihole-kids and login.
Youtube
Add these domains to your blacklist:
|
Youtube regexes
Add these to your Blacklist in pihole-kids as regex:
|
Adult Websites
I found an article which points to a list hosted on github containing 11868 domains at the time of this writing.
Just add this URL
to "Settings" -> "Block Lists".
Gather MAC addresses of your kids' devices
Now there is everything in place to serve filtered DNS to all devices in the LAN and extra filtered DNS for our kids' devices.
But now we have to distinguish between the kids' devices and all the other ones.
This is done by MAC address filtering capability of iptables.
So first, we need to look up the MACs of the kids' devices, eg. in the networking overview of the FritzBox.
Just click on the edit button on one of the kids' devices to get further information.
The MAC address is shown, so we can simply copy+paste it.
Cancel if you are done with the device.
Reroute DNS traffic via iptables
We now need to add the rules to our docker host's iptables NAT table.
Before any other actions are done by iptables, the packages run through the PREROUTING table.
We fetch packages for the ports 67 and 53 and send them to the correct piholes based on the latter gathered MAC addresses.
To easily add / remove those rules, I wrote a simple script which is loaded at boot time on my home server.
So if you're on gentoo, you could save this script to eg. /etc/local.d/piholes_iptables_rules.start
This script also adds routing of packages which request popular DNS servers like google.dns or opendns.net.
These rules still don't have any effect, as no device in the LAN ask our home server about these DNS server IPs.
We will enforce this in the next step.
Alter the script with your values.
MACS
= MACs of your kids' devices you collected before, space separatedDOCKER_HOST_IP
= your docker host / home server ipETH
= your ethernet device on your docker host / home server
Save it with your favourite text editor, make it executable and run it as root.
|
If you made any mistake, you could remove these rules again by calling the script with the "-D" switch before you make any changes to the script!
Altered rules will not be removed as they have to be in the same state as commited before.
# ./piholes_iptables_rules.sh -D |
You should now have a bunch of new rules in your NAT table.
# iptables -t nat -L -n -v |
piholes_iptables_rules.sh
|
Reroute google.dns / popular DNS servers to your piholes
You will find many website with the specific topic "block google dns on fritzbox" which reroute the requests to a non-existant IP in your network.
Yes, this works, but will ridiculously increase website loading time in your browsers at home.
The browsers will wait for a timout of their requests ... which could take a very long time, just try it :)
So we point those DNS servers back to our home server to send them to our piholes.
We already defined the corresponding iptables rules in the previous step.
I block these DNS servers for direct use by our LAN devices:
|
Replace 192.168.0.11
with your docker host's / home server's IP.
Add them to your FritzBox's IPv4 routing tables.
Do not forget to activate the entry by clicking on the "enable" checkbox.
Open your FritzBox admin panel and go to "Network" -> "Network Settings" -> "Static Routing Table" -> "IPv4 Routing".