What's new

Tutorial Forcing SafeSearch Tutorial

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

My only concern about on-router options is the router itself. This model has a software bug affecting some user scripts and also likes to die (okay... retire) suddenly forcing the owner to perform unplanned hardware upgrades. I would replace it with something more reliable before it happens.
 
There are many approaches to this topic and RMerlin's Wiki https://github.com/RMerl/asuswrt-merlin.ng/wiki/Enforce-Safesearch
-briefly delves on the concept using dnsmasq. Instead of reinventing the wheel over and over again with this topic, below is a small script and instructions for users that wish to explore this topic.
simply copy and paste the below script into SSH terminal + Press Enter and everything is taken care of. Before testing it is important to clear/refresh any browsers and/or cache on test devices.

To reduce risk IP changes this script is adapted for using fresh IP addresses:
Code:
touch enforcesafe.sh && cat > "enforcesafe.sh" <<'EOF'
#!/bin/sh
URL="https://www.google.com/supported_domains"
FILE="/jffs/configs/dnsmasq.conf.add"

[ ! -f "$FILE" ] && touch "$FILE"

f_nslookup() {
    local DOMAIN="$1"
    nslookup "${DOMAIN}" 1.1.1.1 2>/dev/null | awk '/^Address[[:space:]][0-9]*\:[[:space:]]/{if($3 ~ /((((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)|(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:{2}(\/(1?[0-2][0-8]|[0-9][0-9]))?))/ && !/1\.1\.1\.1/)print $3}' | while read -r line; do { if [ "${line%%.*}" = "0" ] || [ -z "${line%%::*}" ]; then continue; elif [ "${line##*:}" = "${line}" ]; then printf "%s " "$line"; else printf "%s " "$line"; fi; }; done
}

{
printf "%s\n" "# Enforced Safe Search:"
DOMAINS="$(curl $URL 2>/dev/null)"
for DOMAIN in $DOMAINS; do
    DOMAIN="$(echo $DOMAIN | cut -c 2-)"
    printf "%s\n" "local=/www.${DOMAIN}/" \
              "cname=www.${DOMAIN},forcesafesearch.google.com"
done
#this version uses restrictmoderate.youtube.com
for DOMAIN in youtube; do
    printf "%s\n" "local=/www.${DOMAIN}.com/" \
              "cname=www.${DOMAIN}.com,restrictmoderate.${DOMAIN}.com" \
              "local=/m.${DOMAIN}.com/" \
              "cname=m.${DOMAIN}.com,restrictmoderate.${DOMAIN}.com" \
              "local=/${DOMAIN}i.googleapis.com/" \
              "cname=${DOMAIN}i.googleapis.com,restrictmoderate.${DOMAIN}.com" \
              "local=/${DOMAIN}.googleapis.com/" \
              "cname=${DOMAIN}.googleapis.com,restrictmoderate.${DOMAIN}.com" \
              "local=/www.${DOMAIN}-nocookie.com/" \
              "cname=www.${DOMAIN}-nocookie.com,restrictmoderate.${DOMAIN}.com"
done
for DOMAIN in bing.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},strict.${DOMAIN}"
done
for DOMAIN in pixabay.com; do
    printf "%s\n" "local=/${DOMAIN}/" \
              "cname=${DOMAIN},safesearch.${DOMAIN}"
done
for DOMAIN in duckduckgo.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},start.${DOMAIN},safe.${DOMAIN}" \
              "local=/duck.com/www.duck.com/" \
              "cname=duck.com,www.duck.com,safe.${DOMAIN}"
done
for DOMAIN in qwant.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/api.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},api.${DOMAIN},safeapi.${DOMAIN}" \
              "local=/s1.${DOMAIN}/s2.${DOMAIN}/" \
              "cname=s1.${DOMAIN},s2.${DOMAIN},safeapi.${DOMAIN}"
done
YANDEX="com ru ua by kz"
for DOMAIN in $YANDEX; do
    printf "%s\n" "local=/yandex.${DOMAIN}/www.yandex.${DOMAIN}/" \
              "cname=yandex.${DOMAIN},www.yandex.${DOMAIN},familysearch.yandex.ru"
done
for DOMAIN in forcesafesearch.google.com safe.duckduckgo.com restrictmoderate.youtube.com strict.bing.com safesearch.pixabay.com safeapi.qwant.com familysearch.yandex.ru; do
    for IPS in $(f_nslookup $DOMAIN); do
        if [ "$DOMAIN" = "forcesafesearch.google.com" ]; then
            if [ "${IPS##*:}" = "${IPS}" ]; then
                printf "%s\n" "host-record=${DOMAIN},restrict.youtube.com,${IPS},::ffff:${IPS}"
            else
                printf "%s\n" "host-record=${DOMAIN},restrict.youtube.com,${IPS}"
            fi
        else
            if [ "${IPS##*:}" = "${IPS}" ]; then
                printf "%s\n" "host-record=${DOMAIN},${IPS},::ffff:${IPS}"
            else
                printf "%s\n" "host-record=${DOMAIN},${IPS}"
            fi
        fi
    done
done
printf "%s\n" "# End of Enforced Safe Search #"
} >> "${FILE}"
service restart_dnsmasq >/dev/null 2>&1
EOF
sh enforcesafe.sh && rm -rf enforcesafe.sh
On a side note for users that want a restrict.youtube.com instead of a lower level restrictmoderate.youtube.com:
Code:
touch enforcesafe.sh && cat > "enforcesafe.sh" <<'EOF'
#!/bin/sh
URL="https://www.google.com/supported_domains"
FILE="/jffs/configs/dnsmasq.conf.add"

[ ! -f "$FILE" ] && touch "$FILE"

f_nslookup() {
    local DOMAIN="$1"
    nslookup "${DOMAIN}" 1.1.1.1 2>/dev/null | awk '/^Address[[:space:]][0-9]*\:[[:space:]]/{if($3 ~ /((((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)|(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:{2}(\/(1?[0-2][0-8]|[0-9][0-9]))?))/ && !/1\.1\.1\.1/)print $3}' | while read -r line; do { if [ "${line%%.*}" = "0" ] || [ -z "${line%%::*}" ]; then continue; elif [ "${line##*:}" = "${line}" ]; then printf "%s " "$line"; else printf "%s " "$line"; fi; }; done
}

{
printf "%s\n" "# Enforced Safe Search:"
DOMAINS="$(curl $URL 2>/dev/null)"
for DOMAIN in $DOMAINS; do
    DOMAIN="$(echo $DOMAIN | cut -c 2-)"
    printf "%s\n" "local=/www.${DOMAIN}/" \
              "cname=www.${DOMAIN},forcesafesearch.google.com"
done
#this version uses restrict.youtube.com
for DOMAIN in youtube; do
    printf "%s\n" "local=/www.${DOMAIN}.com/" \
              "cname=www.${DOMAIN}.com,restrict.${DOMAIN}.com" \
              "local=/m.${DOMAIN}.com/" \
              "cname=m.${DOMAIN}.com,restrict.${DOMAIN}.com" \
              "local=/${DOMAIN}i.googleapis.com/" \
              "cname=${DOMAIN}i.googleapis.com,restrict.${DOMAIN}.com" \
              "local=/${DOMAIN}.googleapis.com/" \
              "cname=${DOMAIN}.googleapis.com,restrict.${DOMAIN}.com" \
              "local=/www.${DOMAIN}-nocookie.com/" \
              "cname=www.${DOMAIN}-nocookie.com,restrict.${DOMAIN}.com"
done
for DOMAIN in bing.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},strict.${DOMAIN}"
done
for DOMAIN in pixabay.com; do
    printf "%s\n" "local=/${DOMAIN}/" \
              "cname=${DOMAIN},safesearch.${DOMAIN}"
done
for DOMAIN in duckduckgo.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},start.${DOMAIN},safe.${DOMAIN}" \
              "local=/duck.com/www.duck.com/" \
              "cname=duck.com,www.duck.com,safe.${DOMAIN}"
done
for DOMAIN in qwant.com; do
    printf "%s\n" "local=/${DOMAIN}/www.${DOMAIN}/api.${DOMAIN}/" \
              "cname=${DOMAIN},www.${DOMAIN},api.${DOMAIN},safeapi.${DOMAIN}" \
              "local=/s1.${DOMAIN}/s2.${DOMAIN}/" \
              "cname=s1.${DOMAIN},s2.${DOMAIN},safeapi.${DOMAIN}"
done
YANDEX="com ru ua by kz"
for DOMAIN in $YANDEX; do
    printf "%s\n" "local=/yandex.${DOMAIN}/www.yandex.${DOMAIN}/" \
              "cname=yandex.${DOMAIN},www.yandex.${DOMAIN},familysearch.yandex.ru"
done
for DOMAIN in forcesafesearch.google.com safe.duckduckgo.com restrictmoderate.youtube.com strict.bing.com safesearch.pixabay.com safeapi.qwant.com familysearch.yandex.ru; do
    for IPS in $(f_nslookup $DOMAIN); do
        if [ "$DOMAIN" = "forcesafesearch.google.com" ]; then
            if [ "${IPS##*:}" = "${IPS}" ]; then
                printf "%s\n" "host-record=${DOMAIN},restrict.youtube.com,${IPS},::ffff:${IPS}"
            else
                printf "%s\n" "host-record=${DOMAIN},restrict.youtube.com,${IPS}"
            fi
        else
            if [ "${IPS##*:}" = "${IPS}" ]; then
                printf "%s\n" "host-record=${DOMAIN},${IPS},::ffff:${IPS}"
            else
                printf "%s\n" "host-record=${DOMAIN},${IPS}"
            fi
        fi
    done
done
printf "%s\n" "# End of Enforced Safe Search #"
} >> "${FILE}"
service restart_dnsmasq >/dev/null 2>&1
EOF
sh enforcesafe.sh && rm -rf enforcesafe.sh
Results:
Code:
#########################################################
/tmp/home/root# dig www.google.com @192.168.1.1

; <<>> DiG 9.16.8 <<>> www.google.com @192.168.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26812
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1280
;; QUESTION SECTION:
;www.google.com.                        IN      A

;; ANSWER SECTION:
www.google.com.         0       IN      CNAME   forcesafesearch.google.com.
forcesafesearch.google.com. 0   IN      A       216.239.38.120

;; Query time: 1 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sun Jan 31 21:32:53 EST 2021
;; MSG SIZE  rcvd: 99
#########################################################
I just recently added improvements to the original post, similar to additions to unbound script here: https://www.snbforums.com/threads/safesearchenforcement-with-unbound.68314/, however, these additions are in line with dnsmasq syntax.
 

Latest threads

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top