Created
June 16, 2021 18:09
-
-
Save drizzt/f4fa8e7e1aca434d9d5a7a3bbf9b6245 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
########################### | |
# (C) 2021 Timothy Redaelli | |
# Based on work by: | |
# (C) 2017 Steven Black | |
########################### | |
# | |
# 2017-04-17 - 1.0.0 Initial release | |
# 2017-04-18 - 1.1.0 Improved modularization; added functionality for white & black lists | |
# 2017-04-25 - 1.1.1 Relocated conf dir to /usr/local/etc | |
# 2017-04-25 - 1.1.2 Relocate script dir; update checks to create conf templates | |
# 2017-05-17 - 1.1.3 Remove local declarations for improved compatibility | |
# 2017-05-17 - 1.1.4 Cleanup syntax as per shellcheck.net suggestions | |
# | |
########################### | |
# routine for ensuring all necessary dependencies are found | |
check_deps () { | |
Deps="date grep mv rm sed wget whoami su" | |
MissingDeps=0 | |
for NeededDep in $Deps; do | |
if ! command -v "$NeededDep" > /dev/null 2>&1; then | |
printf "Command not found in PATH: %s\n" "$NeededDep" >&2 | |
MissingDeps=$((MissingDeps+1)) | |
fi | |
done | |
if [ $MissingDeps -gt 0 ]; then | |
printf "%d commands not found in PATH; aborting\n" "$MissingDeps" >&2 | |
exit 1 | |
fi | |
} | |
# check for whitelist/blacklist configuration files & create templates if not present | |
check_conf () { | |
WhiteList="${ConfDir}/ad-blocker-wl.conf" | |
BlackList="${ConfDir}/ad-blocker-bl.conf" | |
# if no white list found, then create a template & instructions | |
if [ ! -f "$WhiteList" ]; then | |
echo "No white list found; creating template" >&2 | |
{ echo "# White list of domains to remain unblocked for ad-blocker.sh"; | |
echo "# Add one fully-qualified domain name per line"; | |
echo "# Comments are indicated by a '#' as the first character"; | |
echo "# example:"; | |
echo "# ad.example.com"; } > "$WhiteList" | |
fi | |
# if no black list found, then create a template & instructions | |
if [ ! -f "$BlackList" ]; then | |
echo "No black list found; creating template" >&2 | |
{ echo "# Black list of additional domains for ad-blocker.sh"; | |
echo "# Add one fully-qualified domain name per line"; | |
echo "# Comments are indicted by a '#' as the first character"; | |
echo "# example:"; | |
echo "# ad.example.com"; } > "$BlackList" | |
fi | |
} | |
# verify running as proper user | |
# if not, attempt to switch and abort if cannot | |
check_user () { | |
User=$(whoami) | |
if [ "$User" != "DNSServer" ]; then | |
echo "Running as $User; switching to DNSServer" >&2 | |
su -m DNSServer "$0" "$@" || exit 1 | |
exit 0 | |
fi | |
} | |
fetch_blocklist () { | |
BlocklistURLs="https://rpz.oisd.nl/ https://rpz.oisd.nl/extra/" | |
# the "-O-" tells wget to send the file to standard out instead of a real file | |
# this makes it suitable for piping and eliminates need for another temp file | |
# shellcheck disable=SC2086 | |
wget -O- $BlocklistURLs | \ | |
sed -ne 's/^\(\S*\) CNAME \.$/\1 A 0.0.0.0\n\1 AAAA ::/p' > "/tmp/ad-blocker.new" | |
} | |
# user-specified list of domains to be blocked in addition to those from yoyo.org | |
apply_blacklist () { | |
BlackList="${ConfDir}/ad-blocker-bl.conf" | |
BlockList="/tmp/ad-blocker.new" | |
# skip if the config doesn't exist | |
if [ ! -f "$BlackList" ]; then | |
return 0; | |
fi | |
# process the blacklist skipping over any comment lines | |
while read -r Line | |
do | |
# strip the line if it starts with a '#' | |
# if the line was stripped, then continue on to the next line | |
Domain=$(echo "$Line" | grep -v "^[[:space:]*\#]") | |
if [ -z "$Domain" ]; then | |
continue; | |
fi | |
# if domain already listed then skip it and continue on to the next line | |
# make sure you don't get a false positive with a partial match | |
# by using the "-w" option on grep | |
Found=$(grep -w "$Domain" "$BlockList") | |
if [ -n "$Found" ]; then | |
continue | |
fi | |
# domain not found, so append it to the list | |
echo "$Domain A 0.0.0.0" >> "$BlockList" | |
echo "$Domain AAAA ::" >> "$BlockList" | |
done < "$BlackList" | |
} | |
# user-specified list of domains to remain unblocked | |
apply_whitelist () { | |
WhiteList="${ConfDir}/ad-blocker-wl.conf" | |
BlockList="/tmp/ad-blocker.new" | |
BlockListTmp="/tmp/ad-blocker.tmp" | |
# skip if the config doesn't exist | |
if [ ! -f "$WhiteList" ]; then | |
return 0 | |
fi | |
# process the whitelist skipping over any comment lines | |
while read -r Line | |
do | |
# strip the line if it starts with a '#' | |
# if the line was stripped, then continue on to the next line | |
Domain=$(echo "$Line" | grep -v "^[[:space:]*\#]") | |
if [ -z "$Domain" ]; then | |
continue; | |
fi | |
# copy every line in the blocklist *except* those matching the whitelisted domain | |
# into a temp file and then copy the temp file back over the original source | |
grep -w -v "$Domain" "$BlockList" > "$BlockListTmp" | |
mv "$BlockListTmp" "$BlockList" | |
done < "$WhiteList" | |
} | |
update_named_options () { | |
OptionsFile="${RootDir}/named/etc/conf/named.options.user.conf" | |
if ! grep -Fqx 'response-policy { zone "null.zone.file"; };' "$OptionsFile"; then | |
echo 'response-policy { zone "null.zone.file"; };' >> "$OptionsFile" | |
fi | |
} | |
# make sure the include statement is added to the ZoneDataFile | |
update_zone_data () { | |
ZoneDataDB="${ZoneDataDir}/ad-blocker.db" | |
BlockList="/tmp/ad-blocker.new" | |
# move the final version of the block list to the final location | |
mv "$BlockList" "$ZoneDataDB" | |
} | |
# update the ZoneMasterFile with an new serial number | |
update_zone_master () { | |
Now=$(date +"%Y%m%d") | |
ZoneMasterFile="${ZoneMasterDir}/null.zone.file" | |
if [ -f "$ZoneMasterFile" ]; then | |
rm -f "$ZoneMasterFile" | |
fi | |
# rebuild the zone master file with the updated serial number | |
# shellcheck disable=SC2016 | |
{ echo '$TTL 86400 ; one day'; | |
echo '@ IN SOA ns.null.zone.file. mail.null.zone.file. ('; | |
echo ' '"${Now}"'00 ; serial number YYYYMMDDNN'; | |
echo ' 86400 ; refresh 1 day'; | |
echo ' 7200 ; retry 2 hours'; | |
echo ' 864000 ; expire 10 days'; | |
echo ' 86400 ) ; min ttl 1 day'; | |
echo ' NS localhost.'; | |
echo '$INCLUDE "/etc/zone/data/ad-blocker.db";'; } > "$ZoneMasterFile" | |
# reload the server config to pick up the changes | |
"${RootDir}"/script/reload.sh | |
} | |
# Global vars for common paths | |
ConfDir="/usr/local/etc" | |
RootDir="/var/packages/DNSServer/target" | |
ZoneDir="${RootDir}/named/etc/zone" | |
ZoneDataDir="${ZoneDir}/data" | |
ZoneMasterDir="${ZoneDir}/master" | |
# Main Routine | |
check_deps | |
check_conf | |
check_user "$@" | |
fetch_blocklist | |
apply_blacklist | |
apply_whitelist | |
update_named_options | |
update_zone_data | |
update_zone_master | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment