|A RaspberryPi computer
My first thought was that we'd maintain a list of "bad" sites we don't want him visiting, and filter these out. It quickly became apparent this solution was not scalable because there is an unlimited list of sites not suitable for children.
It was clear we'd need to go the opposite direction: maintain a small list of "safe" sites he could use. It would include things like Khan Academy and Google Classroom. This is referred to as a "whitelist" in technology jargon.
Some quick research showed that the widely-available package dnsmasq was suitable for the job. dnsmasq is a popular system for resolving DNS names and for assigning IP addresses to devices on your network. It's probably most often used for the latter purpose, but we really needed its DNS capabilities.
DNS provides the name-to-number mapping that lets you simply type "blog.dammitly.net" instead of a long string of numbers when browsing. By listening for DNS traffic, I could tell if someone on my network was trying to visit a site I consider unsafe.
dnsmasq's whitelisting feature comes from its ability to redirect searches for a name to an alternate DNS server. That server can then be set to not resolve the name, resulting in the inability to visit the site using a name. Someone could still access the site if they could find the IP address some other way, but we'll worry about that later.
Using this feature, I set up a dnsmasq server on my local network, running on a RaspberryPi (pictured). The Pi is a cheap Linux machine available online for as little as $35.
I set my son's computer to use this dnsmasq server to resolve all DNS queries. Within dnsmasq's configuration, I identified the list of appropriate sites and set them to resolve normally using Google's public DNS (220.127.116.11). Here is the configuration:
# List of "safe" websites
I will go through the list of options, explaining what each one means.
domain-needed: Do not forward DNS lookups that don't include a full domain with dots.
bogus-priv: Do not forward private IP space reverse address lookups.
log-queries and log-facility: Log all queries to the specified log file. This lets you see what sites a network client is trying to visit.
no-resolv: Do not resolve any DNS lookups. This makes the DNS server not resolve host names as its default behavior. In other words, it won't resolve a name unless it's in the whitelist.
no-dhcp-interface: Don't serve IP addresses to clients. I used this because I already have a DHCP server on my network.
interface=eth0: This is the network interface you want dnsmasq to listen on. If omitted, it will use all available interfaces.
server=/google.com/18.104.22.168: This tells dnsmasq to send lookups for google.com to Google's public DNS server, 22.214.171.124. Google's DNS will resolve the name and make it so the DNS search succeeds. Only add the sites you want to enable here.
And that's it. Restart dnsmasq and be sure to point the client computer (or phone) DNS to the address of the host running dnsmasq. You should see that non-whitelisted sites will fail to load, while the safe ones will load.
Is this a complete, bulletproof solution? No. There are ways for an advanced user to get around this. DNS over https would allow the user to funnel DNS queries through an encrypted connection to the outside world, if they had that outside server's IP address.
The user could also simply look up the unsafe site's IP address using Google, or change the DNS server used inside their operating system.
To further secure the system I set up firewall rules on my Linux firewall to intercept DNS queries to the outside world. These iptables rules will redirect all port 53 DNS queries to the localhost:
iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 127.0.0.1:53
iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 127.0.0.1:53
This would prevent users from attempting to use another DNS server by intercepting their queries, as long as the queries go out on the standard port 53. Again, this would not prevent users from simply entering the site's numeric IP address if they happened to know it.
To summarize, this is not a full solution to the problem of restricting internet usage. There are many ways to get around these measures, as I detailed above. This will stop most novice users, and users who do not have administrative access to their machines.