-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathadblocker.sh
executable file
·143 lines (111 loc) · 4.52 KB
/
adblocker.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
#!/bin/sh
# adblocker.sh - by Todd Stein (toddbstein@gmail.com), Saturday, October 25, 2014
# for use on routers running OpenWRT firmware
# updated Monday, August 14, 2017
# Periodically download lists of known ad and malware servers, and prevents traffic from being sent to them.
# This is a complete rewrite of a script originally written by teffalump (https://gist.github.com/teffalump/7227752).
HOST_LISTS="
http://www.malwaredomainlist.com/hostslist/hosts.txt
http://winhelp2002.mvps.org/hosts.txt
http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&startdate%5Bday%5D=&startdate%5Bmonth%5D=&star
"
BLOCKLIST=/tmp/adblocker_hostlist
BLACKLIST=/etc/adblocker_blacklist
WHITELIST=/etc/adblocker_whitelist
LOCKFILE=/tmp/adblocker.lock
# ensure this is the only instance running
if ! ln -s $$ "$LOCKFILE" 2>/dev/null; then
# if the old instance is still running, exit
former_pid=$(readlink "$LOCKFILE")
if [ -e "/proc/$former_pid" ]; then
exit
else
# otherwise, update the symlink
ln -sf $$ "$LOCKFILE"
fi
fi
# get script's absolute path and quote spaces for safety
cd "${0%/*}"
SCRIPT_NAME="$PWD/${0##*/}"
SCRIPT_NAME="${SCRIPT_NAME// /' '}"
cd "$OLDPWD"
# await internet connectivity before proceeding (in case rc.local executes this script before connectivity is achieved)
until ping -c1 -w3 google.com || ping -c1 -w3 yahoo.com; do
sleep 5
done &>/dev/null
# grab list of bad domains from the internet - written with the intent of using the least memory possible
IP_REGEX='([0-9]{1,3}\.){3}[0-9]{1,3}'
temp_file1=/tmp/adblocker.tmp1
temp_file2=/tmp/adblocker.tmp2
>"$temp_file1"
# download host lists individually so the rest can still be grabbed if one goes offline
for i in $HOST_LISTS; do
# download and immediately sanitize to prevent possibility of redirection attack
wget -qO- $i | awk "/^$IP_REGEX\W/"'{ print "0.0.0.0",$2 }' >>"$temp_file1"
done
# sort by domain
sort -uk2 "$temp_file1" >"$temp_file2"
rm -f "$temp_file1"
# if the download succeeded, overwrite blocklist
if [ -s "$temp_file2" ]; then
mv -f "$temp_file2" "$BLOCKLIST"
else
rm -f "$temp_file2"
fi
# add blacklisted domains if any have been specified, ensuring no duplicates are added
if [ -s "$BLACKLIST" ]; then
# create a pipe-delimited list of all non-commented words in blacklist and remove them from the block list
black_listed_regex='\W('"$(grep -o '^[^#]\+' "$BLACKLIST" | xargs | tr ' ' '|')"')$'
sed -ri "/${black_listed_regex//./\.}/d" "$BLOCKLIST"
# add blacklisted domains to block list
awk '/^[^#]/ { print "0.0.0.0",$1 }' "$BLACKLIST" >>"$BLOCKLIST"
fi
if [ -s "$BLOCKLIST" ]; then
# remove any private net IP addresses (just in case)
# this variable contains a regex which will be used to prevent the blocking of hosts on 192.168.0.0 and 10.0.0.0 networks
PROTECTED_RANGES='\W(192\.168(\.[0-9]{1,3}){2}|10(\.[0-9]{1,3}){3})$'
sed -ri "/$PROTECTED_RANGES/d" "$BLOCKLIST"
# remove any whitelisted domains from the block list
if [ -s "$WHITELIST" ]; then
# create a pipe-delimited list of all non-commented words in whitelist and remove them from the block list
white_listed_regex='\W('"$(grep -Eo '^[^#]+' "$WHITELIST" | xargs | tr ' ' '|')"')$'
sed -ri "/${white_listed_regex//./\.}/d" "$BLOCKLIST"
fi
# add block list to dnsmasq config if it's not already there
if ! uci -q get dhcp.@dnsmasq[0].addnhosts | grep -q "$BLOCKLIST"; then
uci add_list dhcp.@dnsmasq[0].addnhosts="$BLOCKLIST" && uci commit
fi
# restart dnsmasq service
/etc/init.d/dnsmasq restart
fi
# carefully add script to /etc/rc.local if it's not already there
if ! grep -Fq "$SCRIPT_NAME" /etc/rc.local; then
# using awk and cat ensures that no symlinks (if any exist) are clobbered by BusyBox's feature-poor sed.
awk -v command="$SCRIPT_NAME" '
! /^exit( 0)?$/ {
print $0
}
/^exit( 0)?$/ {
print command "\n" $0
entry_added=1
}
END {
if (entry_added != 1) {
print command
}
}' /etc/rc.local >/tmp/rc.local.new
cat /tmp/rc.local.new >/etc/rc.local
rm -f /tmp/rc.local.new
fi
# add script to root's crontab if it's not already there
if ! grep -Fq "$SCRIPT_NAME" /etc/crontabs/root 2>/dev/null; then
# adds 30 minutes of jitter to prevent undue load on the webservers hosting the lists we pull each week
# unfortunately, there's no $RANDOM in this shell, so:
DELAY=$(head /dev/urandom | wc -c | /usr/bin/awk "{ print \$0 % 30 }")
cat >>/etc/crontabs/root <<-:EOF:
# Download updated ad and malware server lists every Tuesday at 3:$(printf "%02d" "$DELAY") AM
$DELAY 3 * * 2 $SCRIPT_NAME
:EOF:
fi
# clean up
rm -f "$LOCKFILE"