2 #################################################
3 # function library used by adblock-update.sh #
4 # written by Dirk Brenken (openwrt@brenken.org) #
5 #################################################
7 #####################################
8 # f_envload: load adblock environment
12 # source in openwrt function library
14 if [ -r "/lib/functions.sh" ]
16 .
"/lib/functions.sh" 2>/dev
/null
19 f_log
"openwrt function library not found" "${rc}"
23 # source in openwrt network library
25 if [ -r "/lib/functions/network.sh" ]
27 .
"/lib/functions/network.sh" 2>/dev
/null
30 f_log
"openwrt network library not found" "${rc}"
34 # get list with all installed openwrt packages
36 pkg_list
="$(opkg list-installed 2>/dev/null)"
37 if [ -z "${pkg_list}" ]
40 f_log
"empty openwrt package list" "${rc}"
45 ######################################################
46 # f_envparse: parse adblock config and set environment
50 # set the C locale, characters are single bytes, the charset is ASCII
51 # speeds up sort, grep etc.
55 # set initial defaults,
56 # may be overwritten by setting appropriate adblock config options in global section of /etc/config/adblock
61 adb_nullipv4
="254.0.0.1"
62 adb_nullipv6
="::ffff:fe00:0001"
65 adb_blacklist
="/etc/adblock/adblock.blacklist"
66 adb_whitelist
="/etc/adblock/adblock.whitelist"
68 # function to read/set global options by callback,
69 # prepare list items and build option list for all others
75 if [ "${type}" = "adblock" ]
81 eval "${option}=\"${value}\""
88 local opt_out
="$(printf "${option}" | sed -n '/.*_ITEM[0-9]$/p; /.*_LENGTH$/p; /enabled/p' 2>/dev/null)"
89 if [ -z "${opt_out}" ]
91 all_options
="${all_options} ${option}"
98 if [ "${list}" = "adb_catlist" ]
100 adb_cat_shalla
="${adb_cat_shalla} ${value}"
106 # function to iterate through option list, read/set all options in "enabled" sections
111 config_get switch
"${config}" "enabled"
112 if [ "${switch}" = "1" ]
114 for option
in ${all_options}
116 config_get value
"${config}" "${option}"
119 local opt_src
="$(printf "${option}" | sed -n '/^adb_src_[a-z0-9]*$/p' 2>/dev/null)"
120 if [ -n "${opt_src}" ]
122 adb_sources
="${adb_sources} ${value}"
124 eval "${option}=\"${value}\""
131 # load adblock config and start parsing functions
134 config_foreach parse_config service
135 config_foreach parse_config
source
137 # set more script defaults (can't be overwritten by adblock config options)
141 adb_tmpfile
="$(mktemp -tu 2>/dev/null)"
142 adb_tmpdir
="$(mktemp -p /tmp -d 2>/dev/null)"
143 adb_dnsdir
="/tmp/dnsmasq.d"
144 adb_dnsprefix
="adb_list"
148 # set adblock source ruleset definitions
150 rset_start
="sed -r 's/[[:space:]]|[\[!#/:;_].*|[0-9\.]*localhost.*//g; s/[\^#/:;_\.\t ]*$//g'"
151 rset_end
="sed '/^[#/:;_\s]*$/d'"
152 rset_adaway
="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
153 rset_blacklist
="${rset_start} | ${rset_end}"
154 rset_disconnect
="${rset_start} | ${rset_end}"
155 rset_dshield
="${rset_start} | ${rset_end}"
156 rset_feodo
="${rset_start} | ${rset_end}"
157 rset_malware
="${rset_start} | ${rset_end}"
158 rset_malwarelist
="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
159 rset_palevo
="${rset_start} | ${rset_end}"
160 rset_shalla
="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}$//g' | ${rset_end}"
161 rset_spam404
="${rset_start} | sed 's/^\|\|//g' | ${rset_end}"
162 rset_whocares
="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
163 rset_winhelp
="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
164 rset_yoyo
="${rset_start} | sed 's/,/\n/g' | ${rset_end}"
165 rset_zeus
="${rset_start} | ${rset_end}"
167 # get logical wan update interfaces
169 network_find_wan adb_wanif4
2>/dev
/null
170 network_find_wan6 adb_wanif6
2>/dev
/null
171 if [ "${adb_wanif4}" = "${adb_lanif}" ] || [ "${adb_wanif6}" = "${adb_lanif}" ]
174 f_log
"LAN only (${adb_lanif}) network, no valid IPv4/IPv6 wan update interface found" "${rc}"
176 elif [ -z "${adb_wanif4}" ] && [ -z "${adb_wanif6}" ]
179 f_log
"no valid IPv4/IPv6 wan update interface found" "${rc}"
183 # get lan ip addresses
185 network_get_ipaddr adb_ipv4
"${adb_lanif}" 2>/dev
/null
186 network_get_ipaddr6 adb_ipv6
"${adb_lanif}" 2>/dev
/null
187 if [ -z "${adb_ipv4}" ] && [ -z "${adb_ipv6}" ]
190 f_log
"no valid IPv4/IPv6 configuration for given logical LAN interface found (${adb_lanif}), please set 'adb_lanif' manually" "${rc}"
194 # read system ntp server names
196 adb_ntpsrv
="$(uci get system.ntp.server 2>/dev/null)"
199 #################################################
200 # f_envcheck: check/set environment prerequisites
204 # check general package dependencies
208 f_depend
"kmod-ipt-nat"
210 # check ipv6 related package dependencies
212 if [ -n "${adb_wanif6}" ]
214 check
="$(printf "${pkg_list}" | grep "^ip6tables
-" 2>/dev/null)"
217 f_log
"package 'ip6tables' not found, IPv6 support wÃll be disabled"
220 check
="$(printf "${pkg_list}" | grep "^kmod-ipt-nat6
-" 2>/dev/null)"
223 f_log
"package 'kmod-ipt-nat6' not found, IPv6 support wÃll be disabled"
229 # check ca-certificates package and set wget parms accordingly
231 check
="$(printf "${pkg_list}" | grep "^ca-certificates
-" 2>/dev/null)"
234 wget_parm
="--no-config --no-check-certificate --quiet"
236 wget_parm
="--no-config --quiet"
239 # check adblock blacklist/whitelist configuration
241 if [ ! -r "${adb_blacklist}" ]
244 f_log
"adblock blacklist not found (${adb_blacklist})" "${rc}"
246 elif [ ! -r "${adb_whitelist}" ]
249 f_log
"adblock whitelist not found (${adb_whitelist})" "${rc}"
253 # check adblock temp directory
255 if [ -n "${adb_tmpdir}" ] && [ -d "${adb_tmpdir}" ]
257 f_space
"${adb_tmpdir}" "please supersize your /tmp directory"
258 if [ "${space_ok}" = "false" ]
265 f_log
"temp directory not found" "${rc}"
269 # check total and swap memory
271 mem_total
="$(grep -F "MemTotal
" "/proc
/meminfo
" 2>/dev/null | grep -o "[0-9]*" 2>/dev/null)"
272 mem_free
="$(grep -F "MemFree
" "/proc
/meminfo
" 2>/dev/null | grep -o "[0-9]*" 2>/dev/null)"
273 swap_total
="$(grep -F "SwapTotal
" "/proc
/meminfo
" 2>/dev/null | grep -o "[0-9]*" 2>/dev/null)"
274 if [ $
((mem_total
)) -le 64000 ] && [ $
((swap_total
)) -eq 0 ]
277 f_log
"overall sort/unique processing will be disabled,"
278 f_log
"please consider adding an external swap device to supersize your /tmp directory (total: ${mem_total}, free: ${mem_free}, swap: ${mem_swap})"
281 # check backup configuration
283 if [ -n "${adb_backupdir}" ] && [ -d "${adb_backupdir}" ]
285 f_space
"${adb_backupdir}" "backup/restore will be disabled"
286 if [ "${space_ok}" = "false" ]
294 f_log
"backup/restore will be disabled"
297 # check debug log configuration
299 adb_logdir
="${adb_logfile%/*}"
300 if [ -n "${adb_logdir}" ] && [ -d "${adb_logdir}" ]
302 f_space
"${adb_logdir}" "debug logging will be disabled"
303 if [ "${space_ok}" = "false" ]
311 f_log
"debug logging will be disabled"
314 # check ipv4/iptables configuration
316 if [ -n "${adb_wanif4}" ]
318 f_firewall
"IPv4" "nat" "I" "PREROUTING" "adb-nat: tcp, port 80, DNAT" "-p tcp -d ${adb_nullipv4} --dport 80 -j DNAT --to-destination ${adb_ipv4}:${adb_port}"
319 f_firewall
"IPv4" "nat" "A" "PREROUTING" "adb-dns: udp, port 53, DNAT" "-p udp --dport 53 -j DNAT --to-destination ${adb_ipv4}"
320 f_firewall
"IPv4" "nat" "A" "PREROUTING" "adb-dns: tcp, port 53, DNAT" "-p tcp --dport 53 -j DNAT --to-destination ${adb_ipv4}"
321 f_firewall
"IPv4" "filter" "I" "FORWARD" "adb-rej: all protocols, all ports, REJECT" "-d ${adb_nullipv4} -j REJECT"
324 # check ipv6/ip6tables configuration
326 if [ -n "${adb_wanif6}" ]
328 f_firewall
"IPv6" "nat" "I" "PREROUTING" "adb-nat: tcp, port 80, DNAT" "-p tcp -d ${adb_nullipv6} --dport 80 -j DNAT --to-destination [${adb_ipv6}]:${adb_port}"
329 f_firewall
"IPv6" "nat" "A" "PREROUTING" "adb-dns: udp, port 53, DNAT" "-p udp --dport 53 -j DNAT --to-destination ${adb_ipv6}"
330 f_firewall
"IPv6" "nat" "A" "PREROUTING" "adb-dns: tcp, port 53, DNAT" "-p tcp --dport 53 -j DNAT --to-destination ${adb_ipv6}"
331 f_firewall
"IPv6" "filter" "I" "FORWARD" "adb-rej: all protocols, all ports, REJECT" "-d ${adb_nullipv6} -j REJECT"
334 # check volatile adblock uhttpd instance configuration
336 rc
="$(ps | grep "[u
]httpd.
*\
-h /www
/adblock
" >/dev/null 2>&1; printf ${?})"
339 if [ -n "${adb_wanif4}" ] && [ -n "${adb_wanif6}" ]
341 uhttpd
-h "/www/adblock" -k 0 -N 100 -T 5 -D -E "/adblock.html" -p "${adb_ipv4}:${adb_port}" -p "[${adb_ipv6}]:${adb_port}">/dev
/null
2>&1
345 f_log
"created volatile uhttpd instance (${adb_ipv4}:${adb_port}, [${adb_ipv6}]:${adb_port})"
347 f_log
"failed to initialize volatile uhttpd instance (${adb_ipv4}:${adb_port}, [${adb_ipv6}]:${adb_port})" "${rc}"
350 elif [ -n "${adb_wanif4}" ]
352 uhttpd
-h "/www/adblock" -k 0 -N 100 -T 5 -D -E "/adblock.html" -p "${adb_ipv4}:${adb_port}" >/dev
/null
2>&1
356 f_log
"created volatile uhttpd instance (${adb_ipv4}:${adb_port})"
358 f_log
"failed to initialize volatile uhttpd instance (${adb_ipv4}:${adb_port})" "${rc}"
361 elif [ -n "${adb_wanif6}" ]
363 uhttpd
-h "/www/adblock" -k 0 -N 100 -T 5 -D -E "/adblock.html" -p "[${adb_ipv6}]:${adb_port}" >/dev
/null
2>&1
367 f_log
"created volatile uhttpd instance ([${adb_ipv6}]:${adb_port})"
369 f_log
"failed to initialize volatile uhttpd instance ([${adb_ipv6}]:${adb_port})" "${rc}"
375 # wait for active wan update interface
378 while [ $
((cnt
)) -le $
((adb_maxloop
)) ]
380 for interface
in ${adb_wanif}
382 network_get_device adb_wandev
"${interface}" 2>/dev
/null
383 if [ -z "${adb_wandev}" ] ||
[ ! -d "/sys/class/net/${adb_wandev}" ]
385 if [ -n "${adb_wanif4}" ]
387 network_get_device adb_wandev
"${adb_wanif4}" 2>/dev
/null
389 network_get_device adb_wandev
"${adb_wanif6}" 2>/dev
/null
391 if [ -z "${adb_wandev}" ] ||
[ ! -d "/sys/class/net/${adb_wandev}" ]
394 f_log
"no valid network device for given logical WAN interface found, please set 'adb_wanif' manually" "${rc}"
398 check
="$(cat /sys/class/net/${adb_wandev}/operstate 2>/dev/null)"
399 if [ "${check}" = "up" ]
401 f_log
"get active wan update interface/device (${adb_wanif}/${adb_wandev}) after ${cnt} loops"
403 elif [ $
((cnt
)) -eq $
((adb_maxloop
)) ]
406 f_log
"wan update interface/device not running (${adb_wanif}/${adb_wandev}) after ${cnt} loops" "${rc}"
416 if [ -n "${adb_ntpsrv}" ]
420 for srv
in ${adb_ntpsrv}
422 ntp_pool
="${ntp_pool} -p ${srv}"
424 /usr
/sbin
/ntpd
-nq ${ntp_pool} >/dev
/null
2>&1
429 f_log
"get ntp time sync"
433 f_log
"ntp time sync failed"
437 # set dnsmasq defaults
439 if [ -n "${adb_wanif4}" ] && [ -n "${adb_wanif6}" ]
441 adb_dnsformat
="awk -v ipv4="${adb_nullipv4}" -v ipv6="${adb_nullipv6}" '{print \"address=/\"\$0\"/\"ipv4\"\n\"\"address=/\"\$0\"/\"ipv6}'"
442 elif [ -n "${adb_wanif4}" ]
444 adb_dnsformat="awk -v ipv4="${adb_nullipv4}" '{print
\"address
=/\"\
$0\"/\"ipv4
}'"
445 elif [ -n "${adb_wanif6}" ]
447 adb_dnsformat="awk -v ipv6="${adb_nullipv6}" '{print
\"address
=/\"\
$0\"/\"ipv6
}'"
450 # remove no longer used opkg package list
455 ######################################
456 # f_depend: check package dependencies
463 check="$(printf "${pkg_list}" | grep "^${package} -" 2>/dev/null)"
467 f_log "package '${package}' not found" "${rc_func}"
472 ##############################################
473 # f_firewall: set iptables rules for ipv4/ipv6
479 local iptv4="/usr/sbin/iptables"
480 local iptv6="/usr/sbin/ip6tables"
488 # select appropriate iptables executable
490 if [ "${proto}" = "IPv4" ]
497 # check whether iptables rule already applied and proceed accordingly
499 rc_func="$("${ipt}" -w -t "${table}" -C "${chain}" -m comment --comment "${notes}" ${rules} >/dev/null 2>&1; printf ${?})"
500 if [ $((rc_func)) -ne 0 ]
502 "${ipt}" -w -t "${table}" -"${ctype}" "${chain}" -m comment --comment "${notes}" ${rules} >/dev/null 2>&1
504 if [ $((rc_func)) -eq 0 ]
506 f_log "created volatile ${proto} firewall rule in '${chain}' chain (${notes})"
508 f_log "failed to initialize volatile ${proto} firewall rule in '${chain}' chain (${notes})" "${rc_func}"
514 ###################################################
515 # f_log: log messages to stdout, syslog and logfile
523 # log to different output devices, set log class accordingly
525 if [ -n "${log_msg}" ]
527 if [ $((log_rc)) -ne 0 ]
530 log_rc=", rc: ${log_rc}"
531 log_msg="${log_msg}${log_rc}"
533 /usr/bin/logger -s -t "adblock[${pid}] ${class}" "${log_msg}"
534 if [ "${log_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
536 printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") adblock[${pid}] ${class}: ${log_msg}" >> "${adb_logfile}"
541 ################################################
542 # f_space: check mount points/space requirements
550 # check relevant mount points in a subshell
554 df "${mp}" 2>/dev/null |\
555 tail -n1 2>/dev/null |\
556 while read filesystem overall used available scrap
558 av_space="${available}"
559 if [ $((av_space)) -eq 0 ]
562 f_log "no space left on device/not mounted (${mp}), ${notes}"
564 elif [ $((av_space)) -lt $((adb_minspace)) ]
567 f_log "not enough space left on device (${mp}), ${notes}"
572 # subshell return code handling, set space trigger accordingly
575 if [ $((rc_func)) -ne 0 ]
582 ##################################################################
583 # f_restore: restore last adblock list backups and restart dnsmasq
591 # remove bogus adblock lists
593 if [ -n "${adb_revsrclist}" ]
595 find "${adb_dnsdir}" -maxdepth 1 -type f \( ${adb_revsrcfind} \) -exec rm -f "{}" \; 2>/dev/null
597 if [ $((rc_func)) -ne 0 ]
599 f_log "error during removal of bogus adblock lists" "${rc_func}"
603 f_log "all bogus adblock lists removed"
609 if [ "${backup_ok}" = "true" ] && [ -d "${adb_backupdir}" ] && [ "$(printf "${adb_backupdir}/${adb_dnsprefix}."*)" != "${adb_backupdir}/${adb_dnsprefix}.*" ]
611 for file in ${adb_backupdir}/${adb_dnsprefix}.*
613 filename="${file##*/}"
614 cp -pf "${file}" "${adb_dnsdir}" 2>/dev/null
616 if [ $((rc_func)) -ne 0 ]
618 f_log "error during restore of adblock list (${filename})" "${rc_func}"
623 f_log "all available backups restored"
625 f_log "no backups found, nothing to restore"
628 # (re-)try dnsmasq restart without bogus adblock lists / with backups
630 if [ "${restore_done}" = "true" ] || [ "${removal_done}" = "true" ]
632 /etc/init.d/dnsmasq restart >/dev/null 2>&1
634 dns_status="$(ps 2>/dev/null | grep "[d]nsmasq" 2>/dev/null)"
635 if [ -n "${dns_status}" ]
640 f_log "dnsmasq restart failed, please check 'logread
' output" "${rc}"
647 ###################################
648 # f_exit: delete (temporary) files,
649 # generate statistics and exit
658 # delete temporary files & directories
660 if [ -f "${adb_tmpfile}" ]
662 rm -f "${adb_tmpfile}" >/dev/null 2>&1
664 if [ -d "${adb_tmpdir}" ]
666 rm -rf "${adb_tmpdir}" >/dev/null 2>&1
669 # final log message and iptables statistics
673 if [ -n "${adb_wanif4}" ] && [ -n "${adb_wanif6}" ]
675 ipv4_nat="$(iptables -t nat -vnL | grep -F "adb-nat" | grep -Eo "[0-9]+" | head -n1)"
676 ipv4_rej="$(iptables -vnL | grep -F "adb-rej" | grep -Eo "[0-9]+" | head -n1)"
677 ipv6_nat="$(ip6tables -t nat -vnL | grep -F "adb-nat" | grep -Eo "[0-9]+" | head -n1)"
678 ipv6_rej="$(ip6tables -vnL | grep -F "adb-rej" | grep -Eo "[0-9]+" | head -n1)"
679 f_log "adblock firewall statistics (IPv4/IPv6): ${ipv4_nat}/${ipv6_nat} packets redirected in PREROUTING chain, ${ipv4_rej}/${ipv6_rej} packets rejected in FORWARD chain"
680 elif [ -n "${adb_wanif4}" ]
682 ipv4_nat="$(iptables -t nat -vnL | grep -F "adb-nat" | grep -Eo "[0-9]+" | head -n1)"
683 ipv4_rej="$(iptables -vnL | grep -F "adb-rej" | grep -Eo "[0-9]+" | head -n1)"
684 f_log "adblock firewall statistics (IPv4): ${ipv4_nat} packets redirected in PREROUTING chain, ${ipv4_rej} packets rejected in FORWARD chain"
685 elif [ -n "${adb_wanif6}" ]
687 ipv6_nat="$(ip6tables -t nat -vnL | grep -F "adb-nat" | grep -Eo "[0-9]+" | head -n1)"
688 ipv6_rej="$(ip6tables -vnL | grep -F "adb-rej" | grep -Eo "[0-9]+" | head -n1)"
689 f_log "adblock firewall statistics (IPv6): ${ipv6_nat} packets redirected in PREROUTING chain, ${ipv6_rej} packets rejected in FORWARD chain"
691 f_log "domain adblock processing finished successfully (${adb_version}, ${openwrt_version}, $(/bin/date "+%d.%m.%Y %H:%M:%S"))"
693 f_log "domain adblock processing failed (${adb_version}, ${openwrt_version}, $(/bin/date "+%d.%m.%Y %H:%M:%S"))"