2 # dns based ad/abuse domain blocking
3 # written by Dirk Brenken (dev@brenken.org)
5 # This is free software, licensed under the GNU General Public License v3.
6 # You should have received a copy of the GNU General Public License
7 # along with this program. If not, see <http://www.gnu.org/licenses/>.
12 PATH
="/usr/sbin:/usr/bin:/sbin:/bin"
16 adb_whitelist
="/etc/adblock/adblock.whitelist"
17 adb_whitelist_rset
="\$1 ~/^([A-Za-z0-9_-]+\.){1,}[A-Za-z]+/{print tolower(\"^\"\$1\"\\\|[.]\"\$1)}"
19 adb_dnsdir
="/tmp/dnsmasq.d"
20 adb_dnshidedir
="${adb_dnsdir}/.adb_hidden"
21 adb_dnsprefix
="adb_list"
22 adb_dnsformat
="awk '{print \"local=/\"\$0\"/\"}'"
23 adb_fetch
="/usr/bin/wget"
24 adb_fetchparm
="--no-config --quiet --tries=1 --no-cache --no-cookies --max-redirect=0 --timeout=5 --no-check-certificate -O"
26 # f_envload: load adblock environment
30 # source in system library
32 if [ -r "/lib/functions.sh" ]
36 f_log
"error" "status ::: system library not found"
39 # parse global section by callback
44 if [ "${type}" = "adblock" ]
50 eval "${option}=\"${value}\""
57 # parse 'service' and 'source' sections
61 local value opt section
="${1}" options
="enabled adb_dir adb_src adb_src_rset adb_src_cat"
62 if [ "${section}" != "backup" ]
64 eval "adb_sources=\"${adb_sources} ${section}\""
68 config_get value
"${section}" "${opt}"
71 eval "${opt}_${section}=\"${value}\""
79 config_foreach parse_config service
80 config_foreach parse_config
source
83 # f_envcheck: check/set environment prerequisites
87 # check 'enabled' option
89 if [ "${adb_enabled}" != "1" ]
91 if [ "$(ls -dA "${adb_dnsdir}/${adb_dnsprefix}"* >/dev/null 2>&1)" ]
96 f_log
"info " "status ::: adblock is currently disabled, please set adb_enabled to '1' to use this service"
100 # check fetch utility
102 if [ -z "${adb_fetch}" ] ||
[ ! -f "${adb_fetch}" ]
104 f_log
"error" "status ::: no download utility with ssl support found/configured"
107 # create dns hideout directory
109 if [ ! -d "${adb_dnshidedir}" ]
111 mkdir
-p -m 660 "${adb_dnshidedir}"
113 rm -f "${adb_dnshidedir}/${adb_dnsprefix}"*
116 # create adblock temp file/directory
118 adb_tmpload
="$(mktemp -tu)"
119 adb_tmpfile
="$(mktemp -tu)"
120 adb_tmpdir
="$(mktemp -p /tmp -d)"
122 # prepare whitelist entries
124 if [ -s "${adb_whitelist}" ]
126 awk "${adb_whitelist_rset}" "${adb_whitelist}" > "${adb_tmpdir}/tmp.whitelist"
129 # get system information
131 adb_sysver
="$(ubus -S call system board | jsonfilter -e '@.release.description')"
134 # f_rmtemp: remove temporary files & directories
138 rm -f "${adb_tmpload}"
139 rm -f "${adb_tmpfile}"
140 rm -rf "${adb_tmpdir}"
143 # f_rmdns: remove dns related files & directories
147 rm -f "${adb_dnsdir}/${adb_dnsprefix}"*
148 rm -f "${adb_dir_backup}/${adb_dnsprefix}"*.gz
149 rm -rf "${adb_dnshidedir}"
150 ubus call service delete
"{\"name\":\"adblock_stats\",\"instances\":\"stats\"}" 2>/dev
/null
153 # f_dnsrestart: restart the dns server
161 killall
-q -TERM "${adb_dns}"
162 while [ ${cnt} -le 10 ]
164 dns_running
="$(ubus -S call service list '{"name
":"dnsmasq
"}' | jsonfilter -l 1 -e '@.dnsmasq.instances.*.running')"
165 if [ "${dns_running}" = "true" ]
172 /etc
/init.d
/"${adb_dns}" restart
176 # f_list: backup/restore/remove block lists
182 if [ "${enabled_backup}" = "1" ] && [ -d "${adb_dir_backup}" ]
186 gzip -cf "${adb_tmpfile}" > "${adb_dir_backup}/${adb_dnsprefix}.${src_name}.gz"
189 rm -f "${adb_dnsdir}/${adb_dnsprefix}.${src_name}"
190 if [ -f "${adb_dir_backup}/${adb_dnsprefix}.${src_name}.gz" ]
192 gunzip
-cf "${adb_dir_backup}/${adb_dnsprefix}.${src_name}.gz" > "${adb_tmpfile}"
196 rm -f "${adb_dnsdir}/${adb_dnsprefix}.${src_name}"
197 if [ -f "${adb_dir_backup}/${adb_dnsprefix}.${src_name}.gz" ]
199 rm -f "${adb_dir_backup}/${adb_dnsprefix}.${src_name}.gz"
206 # f_switch: suspend/resume adblock processing
210 if [ -d "${adb_dnshidedir}" ]
212 local source target status mode
="${1}"
213 local dns_active
="$(find "${adb_dnsdir}" -maxdepth 1 -type f -name "${adb_dnsprefix}*" -print)"
214 local dns_passive
="$(find "${adb_dnshidedir}" -maxdepth 1 -type f -name "${adb_dnsprefix}*" -print)"
216 if [ -n "${dns_active}" ] && [ "${mode}" = "suspend" ]
218 source="${adb_dnsdir}/${adb_dnsprefix}"
219 target
="${adb_dnshidedir}"
221 elif [ -n "${dns_passive}" ] && [ "${mode}" = "resume" ]
223 source="${adb_dnshidedir}/${adb_dnsprefix}"
224 target
="${adb_dnsdir}"
227 if [ -n "${status}" ]
229 mv -f "${source}"* "${target}"
231 f_log
"info " "status ::: adblock processing ${status}"
236 # f_query: query block lists for certain (sub-)domains
240 local search result cnt
242 local tld
="${domain#*.}"
243 local dns_active
="$(find "${adb_dnsdir}" -maxdepth 1 -type f -name "${adb_dnsprefix}*" -print)"
245 if [ -z "${dns_active}" ]
247 printf "%s\n" ":: no active block lists found, please start adblock first"
248 elif [ -z "${domain}" ] || [ "${domain}" = "${tld}" ]
250 printf "%s\n" ":: invalid domain input, please submit a specific (sub-)domain, i.e. 'www.abc.xyz'"
252 while [ "${domain}" != "${tld}" ]
254 search
="${domain//./\.}"
255 result
="$(grep -Hm 1 "[/\.
]${search}/" "${adb_dnsdir}/${adb_dnsprefix}"* | awk -F ':|/' '{print " "$4"\t: "$6}')"
256 cnt="$(grep -hc "[/\.]${search}/" "${adb_dnsdir}/${adb_dnsprefix}"* | awk '{sum += $1} END {printf sum}')"
257 printf "%s
\n" ":: distinct results
for domain
'${domain}' (overall
${cnt})"
258 if [ -z "${result}" ]
260 printf "%s
\n" " no matches
in active block lists
"
262 printf "%s
\n" "${result}"
270 # f_log: write to syslog, exit on error
277 if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || [ ${adb_debug} -eq 1 ])
279 logger
-t "adblock-[${adb_ver}] ${class}" "${log_msg}"
280 if [ "${class}" = "error" ]
291 # f_debug: gather memory & space information
294 local mem_total
=0 mem_free
=0 mem_swap
=0 tmp_space
=0 backup_space
=0
296 if [ ${adb_debug} -eq 1 ]
298 mem_total
="$(awk '$1 ~ /^MemTotal/ {printf $2}' "/proc
/meminfo
")"
299 mem_free
="$(awk '$1 ~ /^MemFree/ {printf $2}' "/proc
/meminfo
")"
300 mem_swap
="$(awk '$1 ~ /^SwapTotal/ {printf $2}' "/proc
/meminfo
")"
301 f_log
"debug" "memory ::: total: ${mem_total}, free: ${mem_free}, swap: ${mem_swap}"
303 if [ -d "${adb_tmpdir}" ]
305 tmp_space
="$(df "${adb_tmpdir}" 2>/dev/null | tail -n1 | awk '{printf $4}')"
307 if [ -d "${adb_dir_backup}" ]
309 backup_space
="$(df "${adb_dir_backup}" 2>/dev/null | tail -n1 | awk '{printf $4}')"
311 f_log
"debug" "space ::: tmp_dir: ${adb_tmpdir}, tmp_kb: ${tmp_space}, backup: ${enabled_backup}, backup_dir: ${adb_dir_backup}, backup_kb: ${backup_space}"
315 # main function for block list processing
319 local enabled url rc cnt sum_cnt
=0
320 local src_name src_rset shalla_file shalla_archive
323 f_log
"debug" "main ::: tool: ${adb_fetch}, parm: ${adb_fetchparm}"
324 for src_name
in ${adb_sources}
326 eval "enabled=\"\${enabled_${src_name}}\""
327 eval "url=\"\${adb_src_${src_name}}\""
328 eval "src_rset=\"\${adb_src_rset_${src_name}}\""
329 adb_dnsfile
="${adb_dnsdir}/${adb_dnsprefix}.${src_name}"
335 if [ "${enabled}" = "0" ] || [ -z "${url}" ] || [ -z "${src_rset}" ]
341 # download block list
343 f_log
"debug" "loop ::: name: ${src_name}, enabled: ${enabled}, dnsfile: ${adb_dnsfile}"
344 if [ "${src_name}" = "blacklist" ]
346 cat "${url}" > "${adb_tmpload}"
348 elif [ "${src_name}" = "shalla" ]
350 shalla_archive
="${adb_tmpdir}/shallalist.tar.gz"
351 shalla_file
="${adb_tmpdir}/shallalist.txt"
352 "${adb_fetch}" ${adb_fetchparm} "${shalla_archive}" "${url}"
357 for category
in ${adb_src_cat_shalla}
359 tar -xOzf "${shalla_archive}" BL/${category}/domains >> "${shalla_file}"
366 cat "${shalla_file}" > "${adb_tmpload}"
367 rm -f "${shalla_file}"
369 rm -f "${shalla_archive}"
370 rm -rf "${adb_tmpdir}/BL"
372 "${adb_fetch}" ${adb_fetchparm} "${adb_tmpload}" "${url}"
376 # check download result and prepare domain output (incl. list backup/restore)
378 f_log
"debug" "loop ::: name: ${src_name}, load-rc: ${rc}"
379 if [ ${rc} -eq 0 ] && [ -s "${adb_tmpload}" ]
381 awk "${src_rset}" "${adb_tmpload}" > "${adb_tmpfile}"
382 if [ -s "${adb_tmpfile}" ]
392 # remove whitelist domains, sort and make them unique, final list preparation
394 if [ -s "${adb_tmpfile}" ]
396 if [ -s "${adb_tmpdir}/tmp.whitelist" ]
398 grep -vf "${adb_tmpdir}/tmp.whitelist" "${adb_tmpfile}" | sort -u | eval "${adb_dnsformat}" > "${adb_dnsfile}"
400 sort -u "${adb_tmpfile}" | eval "${adb_dnsformat}" > "${adb_dnsfile}"
408 f_log
"debug" "loop ::: name: ${src_name}, list-rc: ${rc}"
411 # make overall sort, restart & check dns server
413 for src_name
in $
(ls -dASr "${adb_dnsdir}/${adb_dnsprefix}"* 2>/dev
/null
)
415 if [ -s "${adb_tmpdir}/blocklist.overall" ]
417 sort "${adb_tmpdir}/blocklist.overall" "${adb_tmpdir}/blocklist.overall" "${src_name}" | uniq -u > "${adb_tmpdir}/tmp.blocklist"
418 cat "${adb_tmpdir}/tmp.blocklist" > "${src_name}"
420 cat "${src_name}" >> "${adb_tmpdir}/blocklist.overall"
421 cnt
="$(wc -l < "${src_name}")"
422 sum_cnt
=$
((sum_cnt
+ cnt
))
423 list
="${src_name/*./}"
424 if [ -z "${sum_list}" ]
426 sum_list
="\"${list}\":\"${cnt}\""
428 sum_list
="${sum_list},\"${list}\":\"${cnt}\""
432 if [ "${dns_running}" = "true" ]
436 f_log
"info " "status ::: block lists with overall ${sum_cnt} domains loaded (${adb_sysver})"
437 ubus call service add
"{\"name\":\"adblock_stats\",
438 \"instances\":{\"stats\":{\"command\":[\"\"],
439 \"data\":{\"blocked_domains\":\"${sum_cnt}\",
440 \"last_rundate\":\"$(/bin/date "+%d.
%m.
%Y
%H
:%M
:%S
")\",
441 \"active_lists\":[{${sum_list}}]}}}}"
444 f_log
"error" "status ::: dns server restart with active block lists failed"
447 # handle different adblock actions
449 if [ "${adb_procd}" = "true" ]