If you’re looking for parental control content filtering on Linux, you will find few commercial application support, and plenty of outdated solutions (privoxy, dansguardian, E2Guardian, …). E2Guardian might be worth a try. But if you’re looking for a simple and easily solution, you can combine opendns with iptables to match the users you want content filtering on. All commands must be executed as root.
Identify the uid of the user you want to apply filtering rules on. For this example, I’ll use zia user.
id zia uid=1001(zia) gid=1001(zia) groupes=1001(zia)
Zia has user id 1001, so we want to limit filtering to the user 1001.
Redirect the DNS traffic to OpenDNS
On recent Linux distributions with systemd like this Kubuntu 22.04, the resolv.conf is a symbolic link to a dynamically generated stub-resolv.conf. That’s fine like that, for all users. But since the user we want to use filtering on will use the same file, it’s important to check the nameserver directive there to double check the IP address :
root@lisa:~# file /etc/resolv.conf /etc/resolv.conf: symbolic link to ../run/systemd/resolve/stub-resolv.conf root@lisa:~# grep nameserver /etc/resolv.conf nameserver 127.0.0.53
The name server is 127.0.0.53, so that’s the one we will filter on in our iptables rules.
You can use the below 2 iptables and sysctl rules from a root console, or place them in /etc/rc.local for execution after each reboot.
root@lisa:~# cat /etc/rc.local #!/bin/bash sysctl -w net.ipv4.conf.all.route_localnet=1 iptables -A OUTPUT -t nat --dst 127.0.0.53 -p udp --dport 53 -m owner --uid-owner 1001 -j DNAT --to-destination 208.67.222.222 iptables -t nat -A POSTROUTING -m addrtype --src-type LOCAL --dst-type UNICAST -m owner --uid-owner 1001 -j MASQUERADE exit 0
Explanations:
- Since I placed in /etc/rc.local, it’s important to finish with the exit 0 command.
- the first iptables will catch the DNS requests from the user with uid 1001 and send them to the first OpenDNS server on IP 208.67.222.222.
- the second iptable rule is also important, since the source address must also be changed from 127.0.0.1 to the external IP address of the workstation.
rc.local is deprecated (update 2024/12)
So you might prefer to find an alternative way.
Please your script for instance in /usr/local/sbin/kids-fencing.sh
instead of rc.local
Then create a systemd service with a new file in /etc/systemd/system/kids-fencing.service
[Service] Description=Kids Fencing Service Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/sbin/kids-fencing.sh [Install] WantedBy=multi-user.target [Unit] Wants=network-online.target
Then
systemctl daemon-reload systemctl enable kids-fencing --now
You can check that the iptables inserted the rule in the POSTROUTING chain:
iptables -t nat -L
Configure OpenDNS account and filtering
You must create an account, and configure OpenDNS with filtering enabled when requests are comming from your public IP address. A free account is good enough for basic filtering.
Use ddclient to update your IP address
If you have a dynamic IP address, you also must configure the ddclient
to update your public IP address when it changes. There is an example on OpenDNS documentation
Test
- First test from the user with filtering by accessing the url : https://welcome.opendns.com/
You should not have the oops, but just confirmation that you’re using the OpenDNS servers. - Then test on a banned website, depending on the settings you applied.
- Also test that the other users do not use OpenDNS, and are not filtered.
- Just a ping should show you the result. In this case, all the forbidden sites redirects to “hit-adult.opendns.com”
zia@lisa:~$ ping -c1 youtube.fr PING youtube.fr (146.112.61.106) 56(84) bytes of data. 64 bytes from hit-adult.opendns.com (146.112.61.106): icmp_seq=1 ttl=54 time=20.0 ms