-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathad-blocker.sh
executable file
·209 lines (177 loc) · 6.59 KB
/
ad-blocker.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/bin/sh
###########################
# (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 ! hash "$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 the blocklist from yoyo.org and update the path element
# for each entry to comply with the Synology setup
fetch_blocklist () {
BlocklistURL="http://pgl.yoyo.org/as/serverlist.php?hostformat=bindconfig&showintro=0&mimetype=plaintext"
# 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
wget -O- "$BlocklistURL" | \
sed -e 's/null.zone.file/\/etc\/zone\/master\/null.zone.file/g' > "/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 [ ! -z "$Found" ]; then
continue;
fi
# domain not found, so append it to the list
echo "zone \"$Domain\" { type master; notify no; file \"/etc/zone/master/null.zone.file\"; };" >> "$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"
}
# make sure the include statement is added to the ZoneDataFile
update_zone_data () {
ZoneDataFile="${ZoneDataDir}/null.zone.file"
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"
# safety check: make sure both files exist before proceeding
# check for the include statement in the ZoneDataFile
# if it is present do nothing, else append the include statement to the ZoneDataFile
if [ -f "$ZoneDataDB" ] && [ -f "$ZoneDataFile" ]; then
Matches=$(grep 'include "/etc/zone/data/ad-blocker.db";' "$ZoneDataFile")
if [ -z "$Matches" ]; then
echo '' >> "$ZoneDataFile"
echo 'include "/etc/zone/data/ad-blocker.db";' >> "$ZoneDataFile"
fi
fi
}
# 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
{ 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 ' IN NS ns.null.zone.file.';
echo ' IN A 127.0.0.1';
echo '* IN A 127.0.0.1'; } > "$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_zone_data
update_zone_master
exit 0