#!/bin/sh #bof # Diversion is free to use under the GNU General Public License version 3 (GPL-3.0) # https://opensource.org/licenses/GPL-3.0 # Proudly coded by thelonelycoder # Copyright (c) 2016-2066 thelonelycoder - All Rights Reserved # https://www.snbforums.com/members/thelonelycoder.25480/ # https://diversion.ch # Workaround for Entware ELF binaries compiled with RUNPATH, thanks @Martinski # unset LD_LIBRARY_PATH VERSION=6.1.1 RELEASED="August 30 2026" SELF=diversion NAME=Diversion TITLE="$NAME - the Router Ad-Blocker" DIVERSION_DIR=/opt/share/diversion LOG_DIR=/opt/var/log AMTM_DIR=/jffs/addons/amtm SWL_DIR=/jffs/addons/shared-whitelists EMAIL_DIR="${AMTM_DIR}"/mail [ -f "${AMTM_DIR}/amtmBranch" ] && . "${AMTM_DIR}/amtmBranch" case "${amtmBranch:-}" in LOCAL) https=http;tld=test;dBrTxt=$amtmBranch;; *) https=https;tld=ch;dBrTxt=;; esac DIVERSION_URL="$https://diversion.$tld/diversion_adblocking" ascii_logo(){ echo " ____ _ _ " echo " | _ \(_)_ _____ _ __ ___(_) ___ _ __ " echo " | | | | \ \ / / _ \ '__/ __| |/ _ \| '_ \ " echo " | |_| | |\ V / __/ | \__ \ | (_) | | | |" echo " |____/|_| \_/ \___|_| |___/_|\___/|_| |_|" echo echo " $1" if [ "$1" = 'Rebooting...' ]; then printf " $NAME reboots this router now\\n\\n" sleep 5 [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock service reboot >/dev/null 2>&1 & exit 0 elif [ "$1" = "Goodbye" ]; then echo [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock if [ -s "${DIVERSION_DIR}"/.conf/diversion.conf ]; then . "${DIVERSION_DIR}"/.conf/diversion.conf [ "$webUi" = enabled ] && [ "$(webui_get Diversion_lock)" ] && webui_del Diversion_lock fi exit 0 elif [ "$1" = "Welcome" ]; then printf " This is $NAME $VERSION\\n\\n" fi } state_check(){ STATE=1 if [ -s "${DIVERSION_DIR}/.conf/diversion.conf" ]; then . "${DIVERSION_DIR}/.conf/diversion.conf" STATE=5 if [ -z "$action" ]; then auto_reinstall_guard="/tmp/diversion-auto-reinstall" reqscripts='/jffs/scripts/dnsmasq.postconf /jffs/scripts/post-mount /jffs/scripts/services-stop' missingscripts= secondary_dnsmasq_repair= if [ "$webUi" = enabled ]; then webui_hook=/jffs/scripts/service-event webui_command="${DIVERSION_DIR}/webui/process.div" if [ ! -s "$webui_hook" ] || ! grep -Fq "$webui_command" "$webui_hook" then echo " - Diversion WebUI service-event hook missing" STATE=2 missingscripts=1 fi fi # Missing required Diversion hooks trigger a complete re-install. for file in $reqscripts; do if [ ! -s "$file" ]; then echo " - $file missing" STATE=2 missingscripts=1 fi done # Start no more than one automatic re-install attempt. if [ "$missingscripts" = 1 ]; then if [ -f "$auto_reinstall_guard" ]; then echo echo "${NOK} Automatic re-install already failed once" echo "${SPACE} Refusing to start another automatic re-install" echo "${SPACE} during this invocation." rm -f "$auto_reinstall_guard" unset auto_reinstall_guard exit 1 fi if ! : >"$auto_reinstall_guard"; then echo echo "${NOK} Unable to create automatic re-install guard" unset auto_reinstall_guard exit 1 fi action=re-install else # Core hooks are present, so a previous repair attempt # either succeeded or this is a stale guard. rm -f "$auto_reinstall_guard" fi # Preserve the existing version and action handling. if ! cmp -s "$0" "/opt/bin/$SELF" || [ "$VERSION" != "$thisVERSION" ] then STATE=3 elif [ "$0" != "/opt/bin/$SELF" ]; then rm -f "$0" reload_SELF fi # Secondary Dnsmasq files are conditional integration files. # Check them only when normal Diversion startup will continue. if [ "$STATE" = 5 ] && secondary_dnsmasq_feature_installed && ! secondary_dnsmasq_integration_valid then secondary_dnsmasq_repair=yes fi unset auto_reinstall_guard fi # Actions such as remove, update and re-install are written to # diversion.conf before reload_SELF. Process them immediately # after the refreshed main script loads. [ -n "$action" ] && STATE=2 fi [ "$STATE" != 5 ] && set -- [ -z "$THEME" ] && THEME=local theme_$THEME [ "$STATE" -gt 1 ] && get_file helper.div include >/dev/null if [ "$STATE" = 5 ] && [ "$secondary_dnsmasq_repair" = yes ] then echo echo "${ATTN} Secondary Dnsmasq integration is incomplete" echo "${INFO} Attempting one targeted repair" if ensure_secondary_dnsmasq_integration; then echo "${OK} Secondary Dnsmasq integration repaired" else echo "${NOK} Secondary Dnsmasq integration could not be repaired" echo "${SPACE} Core Diversion remains installed." echo "${SPACE} Secondary DNS features will remain unavailable" echo "${SPACE} until the controller can be downloaded." fi unset secondary_dnsmasq_repair fi case "$STATE" in 1) if [ ! -f /opt/bin/opkg ]; then printf "\\n Diversion requires the Entware repository installed.\\n\\n Open amtm by entering 'amtm' into the terminal (without the quotes)\\n" printf " and first install Entware with the ep command.\\n After this, you can again attempt to install Diversion.\\n\\n See you later\\n\\n" rm -f $0 ascii_logo Goodbye elif [ -f /usr/sbin/curl ] && [ -f /usr/bin/tee ]; then # Prompt install clear ascii_logo " " printf "%-34s%s\\n" " This is $NAME $VERSION " "by thelonelycoder" print_red_line echo " Welcome to $TITLE" print_red_line show_message while true; do printf " Install $NAME now? [1=Yes e=Exit] ";read -r selection case "$selection" in 1) if [ "$(nvram get ntp_ready)" = 0 ]; then echo echo " NTP not ready, check that this routers time is synced." echo " $NAME cannot be installed at this time." rm -f $0 ascii_logo Goodbye else print_red_line action=install d_function fi break;; [Ee]) clear [ "$(cd "$(dirname "$0")"; pwd -P)/$SELF" != "/opt/bin/$SELF" ] && rm -f "$(cd "$(dirname "$0")"; pwd -P)/$SELF" ascii_logo Goodbye;break;; *) printf "\\n input is not an option\\n\\n";; esac done else echo echo " Sorry, wrong platform." echo " $NAME cannot be installed on this device." rm -f $0 ascii_logo Goodbye fi ;; 2) # Run action set before last restart # The persisted action is a double handoff. Consume it before # running so a failed action cannot reload itself indefinitely. # Keep the in-memory action for this invocation, but prevent later # write_conf_file calls during install from persisting it again. # The actionHandoff max count is 2. actionHandoff=$((actionHandoff+1)) div_conf_del action if [ "$missingscripts" ]; then printf "\\n${NOK} Required $NAME /jffs file(s)\\n${SPACE} missing, running checks now!\\n" missingscripts= fi [ "$action" != "amtm-update" ] && printf "${INFO} Running function $action\\n" d_function ;; 3) # Run auto-update if [ "$missingscripts" ]; then printf "\\n${NOK} Required $NAME /jffs file(s)\\n${SPACE} missing, running checks now!\\n" missingscripts= fi action=auto-update echo echo "${ATTN} $NAME update detected" printf "\\n${INFO} Running function $action now\\n" d_function ;; 5) trap - 1 2 3 6 15 if [ "$#" = "0" ]; then echo "${NC}" # to reset colors . "${DIVERSION_DIR}"/.conf/diversion.conf [ "$webUi" = enabled ] && [ "$(webui_get Diversion_lock)" ] && webui_del Diversion_lock menuActive=yes show_menu else # Show basic menu case "${@}" in "sh-"* | *" sh" ) bm=ios ;; *) bm=ssh ;; esac case "${@}" in "h"|"help"|"f"|"follow"|"temp_disable") ;; *) diversion_lock "basic-menu option ${@}" ;; esac infotext="${INFO} Enter '$SELF help' for more options" case "${1}" in "h" | "help" ) clear ascii_logo Welcome diversion_help;; "a" | "adblocking" ) clear ascii_logo Welcome echo "$infotext" echo a_function;; "sh-a" ) a_function;; "l" | "logging" ) clear ascii_logo Welcome echo "$infotext" echo l_function;; "sh-l" ) l_function;; "enable" ) clear ascii_logo Welcome echo "$infotext" echo on_off_diversion "$@";; "sh-enable" ) on_off_diversion enable;; "disable" ) clear ascii_logo Welcome echo "$infotext" echo on_off_diversion "$@";; "sh-disable" ) on_off_diversion disable;; "restart" ) clear ascii_logo Welcome echo "$infotext" echo on_off_diversion "$@";; "sh-restart" ) on_off_diversion restart;; "temp_disable" ) clear ascii_logo Welcome echo "$infotext" echo on_off_diversion "$@";; "f" | "follow" ) clear ascii_logo Welcome echo "$infotext" echo follow_dnsmasq;; "ac" | "count_ads" ) ac_function "$@";; "fs" ) clear ascii_logo Welcome echo "$infotext" echo fs_function "$@";; "sh-fs" ) fs_function "$@";; "sh-state" ) state_function "$@";; "bu" | "bl-update" ) clear ascii_logo Welcome echo "$infotext" echo update_blockinglist;; "sh-bl-update" ) update_blockinglist;; "sh-hl-process" ) get_file functions.div include >/dev/null process_hosted_lists exit 0;; "amtmupdate" ) set -e if [ -z "$2" ]; then actionHandoff= action=amtmupdate rm -rf /tmp/diversion.lock write_conf_file diversion elif [ "$2" = "check" ]; then exit 0 fi ;; * ) if [ "$bm" = ssh ]; then clear ascii_logo Welcome echo "${NOK} Unknown command: ${@}" echo diversion_help else echo "Unknown command: ${@}" fi;; esac echo [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock exit 0 fi ;; esac } show_message(){ [ -f /tmp/divmessage ] && . /tmp/divmessage if [ "$lastAction" ]; then printf "${DONE}${GREEN}$lastAction${NC}\\n\\n" lastAction= fi if [ "$lastError" ]; then printf "${ERR}${RED}$lastError${NC}\\n\\n" lastError= fi [ -f /tmp/divmessage ] && rm /tmp/divmessage } show_menu(){ case "$adsCounter" in on) if [ -z "$acOff" ] && [ "$logging" = on ] && [ "$adblocking" = on ] && [ "$DIVERSION_STATUS" = enabled ]; then printf "${INFO} Updating ads counter...\\n\\n" ac_function fi acOff=;; esac clear case "$DIVERSION_STATUS" in enabled ) divColor="${GREEN}" adColor="${GREEN}" logColor="${GREEN}" bfColor="${GREEN}" dsColor="${GREEN}" wlColor="${GREEN_BG}" blColor="${ERR_BG}";; disabled) divColor="${RED}" adColor="${RED}" logColor="${RED}" bfColor="${RED}" dsColor="${RED}" wlColor="${RED}" blColor="${RED}";; esac case "$blUpdateErr" in on) bluColor="${GREEN}";; *) bluColor="${NC}";; esac case "$dsSetting" in on) dsColor="${GREEN}";; *) dsColor="${NC}";; esac case "$backup" in on) buColor="${GREEN}" [ "$DIVERSION_STATUS" = disabled ] && buColor="${RED}";; *) buColor="${NC}";; esac case "$weeklyStats" in on) wsColor="${GREEN}" [ "$logging" = off ] && wsColor="${RED}" [ "$DIVERSION_STATUS" = disabled ] && wsColor="${RED}";; *) wsColor="${NC}";; esac case "$adsCounter" in on) adsColor="${GREEN}" [ "$DIVERSION_STATUS" = disabled ] && adsColor="${RED}";; *) adsColor="${NC}";; esac case "$logging" in off) logColor="${RED}" logtext=$logging logtextAlt=$logging adsColor="${RED}";; *) [ -s "${LOG_DIR}/dnsmasq.log" ] && logtext="dnsmasq.log ${NC}$(du -h "${LOG_DIR}/dnsmasq.log" | awk '{print $1}')" || logtext="dnsmasq.log" if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then [ -s "${LOG_DIR}/dnsmasq.log3" ] && logtextAlt="dnsmasq.log3 ${NC}$(du -h "${LOG_DIR}/dnsmasq.log3" | awk '{print $1}')" || logtextAlt="dnsmasq.log3" fi;; esac case "$adblocking" in off) adColor="${RED}" bfColor="${RED}" adbtext=$adblocking adsColor="${RED}" wlColor="${RED}" blColor="${RED}";; *) adbtext="Dnsmasq NXDOMAIN";; esac HL=hostslist case "$bfFs" in on) case "$bfTypeFs" in Minimal|Small|Standard|Medium|Large|Custom);; *) if [ -f "${DIVERSION_DIR}/list/hostslist_fs" ] && [ "$(/opt/bin/grep "^[^#]" "${DIVERSION_DIR}/list/hostslist_fs" | wc -l)" -ge "1" ]; then bfTypeFs=Custom write_conf_file lastError=" Unknown secondary blocking list type set\\n to Custom" else bfFs=off bfTypeFs= if [ "$bfTypeinUse" = "secondary" ]; then bfinUse=$bfType bfTypeinUse=primary fi write_conf_file restart_DNSMASQ lastError=" Unknown secondary blocking type, ${NC}${RED_BG} sf ${NC}\\n${RED} has been disabled" reload_menu fi;; esac [ "$bfTypeinUse" = "primary" ] && bfinUse=$bfType || bfinUse=$bfTypeFs FS="${RED_BG} fs ${NC}" case "$bfTypeinUse" in primary) large_number "$blockedDomains";bd=$num;; secondary) large_number "$blockedDomainsFs";bd=$num HL=hostslist_fs;; esac ;; *) bfinUse=$bfType FS=" " large_number "$blockedDomains";bd=$num ;; esac large_number "$adsBlocked";adsBlockedHuman=$num large_number "$adsWeek";adsWeekHuman=$num large_number "$adsNew";adsNewHuman=$num lc=$(/opt/bin/grep "^[^#]" "${DIVERSION_DIR}/list/$HL" | wc -l) [ "$lc" -gt 1 ] && pl=s || pl= wlc=$(/opt/bin/grep "^[^#]" "${DIVERSION_DIR}/list/allowlist" | wc -l) blc=$(/opt/bin/grep "^[^#]" "${DIVERSION_DIR}/list/denylist" | wc -l) if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then lca=$(/opt/bin/grep "^[^#]" "${DIVERSION_DIR}/list/hostslist_fs" | wc -l) [ "$lca" -gt 1 ] && pla=s || pla= large_number "$blockedDomainsFs";bda=$num large_number "$adsBlockedAlt";adsBlockedAltHuman=$num large_number "$adsWeekAlt";adsWeekAltHuman=$num large_number "$adsNewAlt";adsNewAltHuman=$num large_number "$((adsBlocked+adsBlockedAlt))";adsBlockedAltHumanT=$num large_number "$((adsWeek+adsWeekAlt))";adsWeekAltHumanT=$num large_number "$((adsNew+adsNewAlt))";adsNewAltHumanT=$num fi printf "%-${DCORR}s%s\\n\\n" "${RED_BG} $NAME $VERSION $dBrTxt" "by thelonelycoder ${NC}" [ -z "$(nvram get odmpid)" ] && routerModel=$(nvram get productid) || routerModel=$(nvram get odmpid) extendno=$(nvram get extendno) [ "$(echo $extendno | wc -c)" -gt 6 ] && extendno="$(echo $extendno | cut -b 1-3).." [ "$extendno" = 0 ] && extendno= || extendno=_$extendno awmBuildno="$(nvram get buildno)" [ "$(version_check $awmBuildno)" -ge "$(version_check 388)" -o "$(version_check $(nvram get firmver))" -ge "$(version_check 3.0.0.6)" ] && fwVersion=$(nvram get firmver | sed 's/\.//g').$awmBuildno$extendno || fwVersion=$awmBuildno$extendno echo " $routerModel ($(uname -m)) FW-$fwVersion @ $(nvram get lan_ipaddr)" if [ "$DIVERSION_STATUS" = enabled ]; then echo if [ "$logging" = on ] && [ "$adblocking" = on ]; then [ "$bfUpdateLastRun" = "$bfUpdatePrevRun" ] && echo "${RED} Domain count off until blocking list update is run${NC}" [ "$bfFs" = on ] && [ "$alternateBF" = on ] && echo " Primary ad-blocking" echo "${ERR_BG} $bd ${NC} blocked domains by ${ERR_BG} $lc ${NC} file$pl" [ "$lc" -eq 0 ] && echo "${RED} list empty, blocking list update will not run${NC}" [ "$lc" -gt 0 ] && [ "$blockedDomains" -lt 200 ] && echo "${RED} blocking list less than 200 domains, investigate${NC}" echo "${GREEN_BG} $adsBlockedHuman t${NC} ${GREEN_BG} $adsWeekHuman w${NC} ${GREEN_BG} $adsNewHuman n${NC} ads since $adsPrevCount" if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then echo " Alternate ad-blocking" echo "${ERR_BG} $bda ${NC} blocked domains by ${ERR_BG} $lca ${NC} file$pla" [ "$lca" -eq 0 ] && echo "${RED} list empty, blocking list update will not run${NC}" [ "$lca" -gt 0 ] && [ "$blockedDomainsFs" -lt 200 ] && echo "${RED} blocking list less than 200 domains, investigate${NC}" echo "${GREEN_BG} $adsBlockedAltHuman t${NC} ${GREEN_BG} $adsWeekAltHuman w${NC} ${GREEN_BG} $adsNewAltHuman n${NC}" echo " Combined ad-blocking totals" echo "${GREEN_BG} $adsBlockedAltHumanT t${NC} ${GREEN_BG} $adsWeekAltHumanT w${NC} ${GREEN_BG} $adsNewAltHumanT n${NC}" fi elif [ "$logging" = on ] && [ "$adblocking" = off ]; then echo "ad-blocking off, stats not available" elif [ "$logging" = off ] && [ "$adblocking" = on ]; then [ "$bfUpdateLastRun" = "$bfUpdatePrevRun" ] && echo "${RED} Domain count off until blocking list update is run${NC}" [ "$bfFs" = on ] && [ "$alternateBF" = on ] && echo " Primary ad-blocking" echo "${ERR_BG} $bd ${NC} blocked domains by ${ERR_BG} $lc ${NC} file$pl)" [ "$lc" -eq 0 ] && echo "${RED} list empty, blocking list update will not run${NC}" [ "$lc" -gt 0 ] && [ "$blockedDomains" -lt 200 ] && echo "${RED} blocking list less than 200 domains, investigate${NC}" if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then echo " Alternate ad-blocking" echo "${ERR_BG} $bda ${NC} blocked domains by ${ERR_BG} $lca ${NC} file$pla" [ "$lca" -eq 0 ] && echo "${RED} list empty, blocking list update will not run${NC}" [ "$lca" -gt 0 ] && [ "$blockedDomainsFs" -lt 200 ] && echo "${RED} blocking list less than 200 domains, investigate${NC}" fi echo "logging off, no stats available" else echo "ad-blocking and logging off, stats not available" fi fi printf "\\n${RED_BG}%-51s ${NC}\\n\\n" " $TITLE" printf "${RED_BG} d ${NC} %-21s%s\\n" "$NAME" "$divColor$DIVERSION_STATUS${NC}" if [ "$DIVERSION_STATUS" = enabled ]; then printf "${RED_BG} c ${NC} %-21s%s\\n" "communication" "${wsColor}stats${NC} ${buColor}backup${NC} ${bluColor}BL${NC}" echo printf "${RED_BG} a ${NC} %-21s%s\\n" "ad-blocking" "$adColor$adbtext${NC}" printf "${RED_BG} l ${NC} %-21s%s\\n" "logging" "$logColor$logtext${NC}" [ "$bfFs" = on ] && [ "$alternateBF" = on ] && printf "${RED_BG} ${NC} %-21s%s\\n" "alternate logfile" "$logColor$logtextAlt${NC}" echo [ "$bfUpdateDOW" = "dly" ] && bfUpdateWeekday=Daily || bfUpdateWeekday=$(echo $bfUpdateDOW | sed 's/,/, /') printf "${RED_BG} b ${NC} blocking list $FS $bfColor$bfinUse${NC} $bfUpdateWeekday @ ${bfUpdateHour}:10\\n" [ "$bfFs" = on ] && [ "$alternateBF" = on ] && printf "${RED_BG} ${NC} %-21s%s\\n" "alternate BL" "$bfColor$bfTypeFs${NC} $bfUpdateWeekday @ ${bfUpdateHour}:10" printf "${RED_BG} el ${NC} %-21s%s\\n" "edit lists" "$wlColor $wlc allowed${NC} $blColor $blc denied${NC}" echo echo "${RED_BG} f ${NC} follow Dnsmasq log" fi options_menu(){ echo if [ "$DIVERSION_STATUS" = enabled ]; then printf "${RED_BG} ac ${NC} %-21s%s\\n" "update ads counter" "Auto-update ${RED_BG} au ${NC} ${adsColor}$adsCounter${NC}" printf "${RED_BG} ds ${NC} %-21s%s\\n" "dnsmasq settings" "${dsColor}$dsSetting${NC}" fi echo printf "${RED_BG} sf ${NC} %-21s\\n" "show file content" } [ "$uiOptions" ] && more=$uiOptions [ -z "$more" ] && more=more [ "$more" = "less" ] && options_menu echo echo "${RED_BG} e ${NC} exit ${RED_BG} u ${NC} update ${RED_BG} t ${NC} theme ${RED_BG} o ${NC} $more options" print_red_line show_message while true; do printf "${RED_BG} Enter $NAME option ${NC} ";read -r selection read_conf_file case "$selection" in [Dd] ) # Diversion options diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line d_function;break;; [Cc] ) # Communication settings diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null c_function reload_menu;break;; [Aa] ) # Enable/disable ad-blocking diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line a_function reload_menu;break;; [Ll] ) # Enable/disable Logging diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line l_function reload_menu;break;; [Ee][Pp]) # Manage Entware lastError=" Entware operations have been moved to amtm.\\n${SPACE} Use amtm command 'ep' from now on." reload_menu;break;; [Bb] ) # blocking list operations diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null b_function reload_menu;break;; [Bb][Uu]) # blocking list update shortcut (runs in background) update_blockinglist reload_menu;break;; [Ff][Ss]) # blocking list fast switch diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line fs_function reload_menu;break;; [Ee][Ll]) # edit the allowlist or denylist files diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null el_function reload_menu;break;; [Ff] ) # follow the dnsmasq.log print_red_line get_file functions.div include >/dev/null f_function reload_menu;break;; [Oo] ) # show options menu [ "$more" = "more" ] && more=less || more=more if [ "$uiOptions" ]; then diversion_lock "option ${RED_BG} $selection ${NC}" uiOptions=$more;write_conf_file fi reload_menu;break;; [Aa][Cc]) # Count ads diversion_lock "option ${RED_BG} $selection ${NC}" ac_function show reload_menu;break;; [Aa][Uu]) # Auto-count ads when opening UL diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null au_function reload_menu;break;; [Tt] ) # Change theme diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line ct_function;write_conf_file reload_menu;break;; [Dd][Ss]) # Dnsmasq settings diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null ds_function reload_menu;break;; [Ss][Ff]) # show file print_red_line get_file functions.div include >/dev/null sf_function reload_menu;break;; [Uu] ) # check for update actionHandoff= check_ntp diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line get_file functions.div include >/dev/null check_for_update printf "\\n${INFO} Downloading latest main file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')\\n" if [ "$webUi" = enabled ]; then webui_del Diversion_update webui_del Diversion_S_VERSION fi get_self new;d_function;break;; [Uu][Uu]) # force update actionHandoff= check_ntp diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line action=update printf "\\n${INFO} Force updating $NAME now\\n\\n${INFO} Downloading latest main file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')\\n" if [ "$webUi" = enabled ]; then webui_del Diversion_update webui_del Diversion_S_VERSION fi get_self new;d_function;break;; 1233 ) # hidden, get latest diversion script and files without prompt run1233(){ actionHandoff= diversion_lock "option ${RED_BG} $selection ${NC}" printf "\\n${INFO} Downloading latest main file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')\\n" if [ "$webUi" = enabled ]; then webui_del Diversion_update webui_del Diversion_S_VERSION am_settings_del Diversion_ webui_del_wc Diversion_lists_ fi action=get-latest-files get_self new } if [ "$dBrTxt" ]; then run1233 else print_red_line printf "${INFO} This option retrieves active $NAME\\n files from the server and should only be run\\n when instructed by thelonelycoder.\\n\\n This is not a proper update function.\\n" printf "\\n Exit now and use ${RED_BG} u ${NC} instead to check for updates.\\n" continue_dialog run1233 fi;break;; diversion|amtm) print_red_line printf "\\n${NOK} Gotcha!${INFO}${QUESTION}${ATTN}${OK}\\n" sleep 3 d_show_info;reload_menu;break;; reboot ) # hidden, reboot router diversion_lock "option ${RED_BG} $selection ${NC}" print_red_line printf " OK then,\\n do you want to reboot this router now?\\n" continue_dialog clear ascii_logo 'Rebooting...';break;; [Ee] ) clear ascii_logo Goodbye;break;; * ) printf "\\n input is not an option\\n\\n";; esac [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock done } d_function(){ if [ "$STATE" = "5" ] && [ -z "$action" ]; then printf " $NAME options\\n\\n" if [ "$DIVERSION_STATUS" = enabled ]; then echo " 0. ${GREEN}Restart${NC} $NAME" echo " 1. ${RED}Disable${NC} $NAME" state=disable echo " 2. Re-install $NAME" echo " 3. Update $NAME ${RED_BG} u ${NC} force upd ${RED_BG} uu ${NC}" else echo "${GRAY} 0. Restart $NAME${NC}" echo " 1. ${GREEN}Enable${NC} $NAME" state=enable echo "${GRAY} 2. Re-install $NAME${NC}" echo "${GRAY} 3. Update $NAME${NC}" fi echo " 5. Info/About $NAME" echo " 6. ${RED}Remove${NC} $NAME" if [ "$DIVERSION_STATUS" = enabled ]; then echo " 7. Reset $NAME ads counter or logs" [ "$localBackup" ] && lbtext="${GREEN}$lBuFrequency${NC}" || lbtext=options echo " 8. Open $NAME local backup $lbtext" else echo "${GRAY} 7. Reset $NAME ads counter or logs${NC}" echo "${GRAY} 8. Open $NAME local backup${NC}" fi if [ "$uiOptions" ]; then echo " 9. ${RED}Forget${NC} $NAME UI last options view ${RED_BG} o ${NC}" else echo " 9. ${GREEN}Remember${NC} $NAME UI last options view ${RED_BG} o ${NC}" fi [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ] && pageloc="Addons / $NAME" || pageloc="LAN / $NAME" if [ "$webUi" = enabled ]; then echo " 10. ${GREEN}Open${NC} $NAME WebUI options" else echo " 10. ${GREEN}Enable${NC} $NAME WebUI" fi check_diversion_status(){ if [ "$DIVERSION_STATUS" = disabled ]; then lastError=" $NAME is disabled, enable it first" reload_menu fi } d_loop(){ action= while true; do printf "\\n Enter selection [0-10 e=Exit] ";read -r continue case "$continue" in 0) if [ "$DIVERSION_STATUS" = enabled ]; then on_off_diversion restart;reload_menu else lastError=" $NAME is disabled, enable it first" reload_menu fi;break;; 1) if [ "$DIVERSION_STATUS" = enabled ]; then tmp_disable_diversion(){ if [ ! -f /opt/bin/date ]; then echo "${INFO} Installing required Entware package: date" echo "${GRAY}" opkg install coreutils-date echo "${NC}" fi cru a Diversion_temp_disable "$(/opt/bin/date -d "today + $tmpDisable minutes" +'%M') $(/opt/bin/date -d "today + $tmpDisable minutes" +'%H') * * * /bin/sh /opt/bin/diversion enable" on_off_diversion temp_disable;reload_menu } print_red_line printf " $NAME disable options\\n\\n" printf " 1. Disable now without time limit\\n 2. Disable now for 10 minutes\\n 3. Disable now for 20 minutes\\n" printf " 4. Disable now for 30 minutes\\n 5. Disable now for 45 minutes\\n 6. Disable now for 1 hour\\n" while true; do printf "\\n Enter selection [1-5 e=Exit] ";read -r continue case "$continue" in 1) on_off_diversion "$state";reload_menu;break;; 2) tmpDisable=10 tmp_disable_diversion;break;; 3) tmpDisable=20 tmp_disable_diversion;break;; 4) tmpDisable=30 tmp_disable_diversion;break;; 5) tmpDisable=45 tmp_disable_diversion;break;; 6) tmpDisable=60 tmp_disable_diversion;break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n\\n";; esac done else on_off_diversion "$state";reload_menu fi;break;; 2) check_ntp;check_diversion_status;action=re-install;break;; 3) check_ntp;check_diversion_status;print_red_line get_file functions.div include >/dev/null check_for_update;break;; 5) d_show_info;reload_menu;break;; 6) print_red_line printf "${ATTN} This removes $NAME from this router.\\n\\n" printf "${INFO} To save essential $NAME files for\\n${SPACE} re-installing, use ${RED_BG} d ${NC} option 8 to create a\\n${SPACE} local backup before removing.\\n" localDivBackup=$(find /jffs/${NAME}_local_backup*.tar.gz 2> /dev/null) if [ "$localDivBackup" ]; then localRestoreDate=$(echo $localDivBackup | cut -d _ -f 5-7 | sed "s~.tar.gz~~;s~_~ ~g;s~\.~:~g") printf "\\n${INFO} Last $NAME local backup in /jffs/\\n${SPACE} is from ${GREEN}$localRestoreDate${NC}\\n" fi while true; do printf "\\n Remove $NAME now? [1=Yes e=Exit] ";read -r continue case "$continue" in 1) break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n\\n";; esac done action=remove;break;; 7) check_diversion_status;print_red_line get_file functions.div include >/dev/null d_reset;break;; 8) check_diversion_status;get_file functions.div include >/dev/null local_backup;break;; 9) if [ "$uiOptions" ]; then uiOptions= more=more lastAction=" Remember last options view disabled" else uiOptions=$more lastAction=" Remember last options view enabled.\\n Set preferred view by entering ${NC}${RED_BG} o ${NC}" fi write_conf_file;reload_menu;break;; 10) if [ "$webUi" = enabled ]; then print_red_line printf " $NAME WebUI options\\n\\n" echo " 1. ${RED}Disable${NC} $NAME WebUI in $pageloc" echo " 2. Remove $NAME WebUI files" while true; do printf "\\n Enter selection [1-2 e=Exit] ";read -r continue case "$continue" in 1) on_off_webui disable;break;; 2) on_off_webui remove;break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n";; esac done else if [ "$(nvram get rc_support | grep am_addons)" ]; then on_off_webui check else webUi=na lastError=" This firmware does not support WebUI addons" fi fi write_conf_file;reload_menu;break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n" d_loop;return 1;; esac done if [ "$max" = "3" ] && [ "$continue" = "4" ]; then printf "\\n input is not an option\\n" action= d_loop;return 1 fi } d_loop echo if [ "$action" = re-install ]; then printf "${INFO} Checking $SELF file\\n" get_self check else printf "${INFO} Downloading latest main file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')\\n" get_self new fi fi trap action_aborted 1 2 3 6 15 action_aborted(){ printf "\\n\\n${NOK} Abort signal detected\\n" printf "${SPACE} Aborting $action, cleaning up temp files...\\n" [ "$0" != "/opt/bin/$SELF" ] && rm -f "$0" rm -rf /tmp/diversion trap - 1 2 3 6 15 reload_d_menu } reload_d_menu(){ [ -f "${DIVERSION_DIR}/log/${NAME}-${action}.log" ] && printf "\\n $NAME $action exited or aborted\\n" >>"${DIVERSION_DIR}/log/${NAME}-${action}.log" if [ "$action" = web-update ]; then webui_set Diversion_update failed am_settings_set _Diversion_page home fi unset action actionHandoff [ -f "${DIVERSION_DIR}"/.conf/diversion.conf ] && write_conf_file write_message exit 1 } if [ "$action" = install ]; then rm -rf /tmp/diversion mkdir /tmp/diversion echo amtmTheme=$(find /jffs/ -name .amtm_theme) if [ -f "$amtmTheme" ]; then . "$amtmTheme" THEME=$theme fi [ -z "$THEME" ] && THEME=local theme_$THEME [ "$THEME" != local ] && printf "${OK} Using theme set in amtm ($THEME)\\n\\n" echo "${INFO} Downloading latest installer file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')" get_file install.div new /tmp/diversion . /tmp/diversion/install.div echo echo "$NAME $action log $(date -R)" >/tmp/diversion/install.log "$(echo print_red_line)" >>/tmp/diversion/install.log install_diversion | tee -a /tmp/diversion/install.log [ -f /tmp/diversion/action ] && . /tmp/diversion/action if [ -d "${DIVERSION_DIR}/log" ]; then mv /tmp/diversion/install.log "${DIVERSION_DIR}/log/${NAME}-${action}.log" fi [ -d /tmp/diversion ] && rm -rf /tmp/diversion if [ -f "/opt/bin/$SELF" ]; then reload_SELF else /bin/sh "$(cd "$(dirname "$0")"; pwd -P)/$SELF" rm -f "$(cd "$(dirname "$0")"; pwd -P)/$SELF" fi elif [ "$action" = get-latest-files ]; then get_latest_files new div_conf_del action action= [ "$webUi" = enabled ] && on_off_webui remount reload_menu elif [ "$action" = remove ]; then get_file functions.div include remove_diversion elif [ "$action" = do-web-update ]; then if [ "$(webui_get Diversion_S_VERSION)" ]; then S_VERSION=$(webui_get Diversion_S_VERSION) VERSION=$S_VERSION webui_del Diversion_S_VERSION fi am_settings_set _Diversion_page update action=web-update webui_set Diversion_update 4% get_self new elif [ "$action" = amtmupdate ]; then action=amtm-update get_self new else if [ "$webUi" = enabled ]; then am_settings_set _Diversion_page home am_settings_del Diversion_ webui_del_wc Diversion_lists_ fi echo "$NAME $action log $(date -R)" >"${DIVERSION_DIR}/log/${NAME}-${action}.log" "$(echo print_red_line)" >>"${DIVERSION_DIR}/log/${NAME}-${action}.log" if [ "$action" = re-install ]; then rm -rf /tmp/diversion mkdir /tmp/diversion get_file install.div include reinstall_status="/tmp/diversion-reinstall-status.$$" rm -f "$reinstall_status" ( install_diversion printf '%s\n' "$?" >"$reinstall_status" ) | tee -a "${DIVERSION_DIR}/log/${NAME}-${action}.log" reinstall_rc="$(cat "$reinstall_status" 2>/dev/null)" rm -f "$reinstall_status" [ -d /tmp/diversion ] && rm -rf /tmp/diversion case "$reinstall_rc" in 0) ;; *) lastError=" $NAME re-install failed.\n Review the re-install log for details." unset reinstall_rc reinstall_status reload_d_menu ;; esac unset reinstall_rc reinstall_status elif [ "$action" = web-update ]; then get_file install.div new get_file install.div include am_settings_set _Diversion_page update webui_set Diversion_update 15% update_diversion >> "${DIVERSION_DIR}/log/${NAME}-${action}.log" exit 0 elif [ "$action" = amtm-update ]; then get_file install.div new get_file install.div include >/dev/null update_diversion >> "${DIVERSION_DIR}/log/${NAME}-${action}.log" printf "${OK} $NAME $VERSION amtmupdate complete\\n" exit 0 else echo "${INFO} Downloading latest installer file from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')" get_file install.div new get_file install.div include update_diversion | tee -a "${DIVERSION_DIR}/log/${NAME}-${action}.log" fi reload_SELF fi } d_show_info(){ print_red_line echo " $TITLE Version $VERSION, released on $RELEASED $NAME is a DNS-based network-wide ad-blocker for wireless routers running Asuswrt-Merlin based firmware. Installation location is within the Entware environment at ${GREEN}$DIVERSION_DIR${NC} For updates and discussion visit this thread: https://www.snbforums.com/forums/asuswrt-merlin-addons.60/?prefix_id=10&starter_id=25480 Proudly coded by thelonelycoder: Copyright (c) 2016-2066 thelonelycoder - All Rights Reserved https://www.snbforums.com/members/thelonelycoder.25480 https://diversion.ch $NAME License: $NAME is free to use under the GNU General Public License version 3 (GPL-3.0) https://opensource.org/licenses/GPL-3.0" press_enter_to "return to Menu" } secondary_dnsmasq_feature_installed(){ # A configured feature may be enabled or temporarily disabled. # Do not use marker IPs because they are assigned before setup completes. [ -n "${alternateBF:-}" ] || [ -n "${exclDevices:-}" ] || [ -n "${restrictedDevices:-}" ] } secondary_dnsmasq_controller_valid(){ controller="${DIVERSION_DIR}/file/dnsmasq-instances.div" [ -s "$controller" ] && /bin/sh -n "$controller" controller_rc=$? unset controller return "$controller_rc" } secondary_dnsmasq_integration_valid(){ secondary_dnsmasq_controller_valid || return 1 [ -s /jffs/scripts/services-start ] && grep -q '/dnsmasq-instances\.div[[:space:]]\+startup' \ /jffs/scripts/services-start || return 1 [ -s /jffs/scripts/service-event-end ] && grep -q '/dnsmasq-instances\.div[[:space:]]\+ensure' \ /jffs/scripts/service-event-end || return 1 [ -s /jffs/scripts/nat-start ] && grep -q '/dnsmasq-instances\.div[[:space:]]\+nat-firewall' \ /jffs/scripts/nat-start || return 1 [ -s /jffs/scripts/firewall-start ] && grep -q '/dnsmasq-instances\.div[[:space:]]\+input-firewall' \ /jffs/scripts/firewall-start || return 1 [ -s /jffs/scripts/services-stop ] && grep -q '/dnsmasq-instances\.div[[:space:]]\+stop' \ /jffs/scripts/services-stop || return 1 return 0 } ensure_hook_script(){ hook_file="$1" if [ ! -f "$hook_file" ]; then printf '%s\n' '#!/bin/sh' >"$hook_file" elif ! head -1 "$hook_file" | grep -q '^#!'; then sed -i '1i#!/bin/sh' "$hook_file" fi } remove_marked_secondary_dnsmasq_block(){ hook_file="$1" [ -f "$hook_file" ] || return 0 hook_tmp="${hook_file}.diversion.$$" awk ' /^# BEGIN Diversion secondary dnsmasq$/ { skip=1; next } /^# END Diversion secondary dnsmasq$/ { skip=0; next } !skip { print } ' "$hook_file" >"$hook_tmp" && cat "$hook_tmp" >"$hook_file" rm -f "$hook_tmp" } remove_orphaned_secondary_dnsmasq_case(){ hook_file="$1" [ -f "$hook_file" ] || return 0 hook_tmp="${hook_file}.diversion.$$" awk ' { line[++n]=$0 if (n < 4) next if (line[1] ~ /^[[:space:]]*case[[:space:]]+"\$1:\$2"[[:space:]]+in[[:space:]]*$/ && line[2] ~ /^[[:space:]]*start:dnsmasq\|restart:dnsmasq\|start:dnsfilter\|restart:dnsfilter[[:space:]]*\)[[:space:]]*$/ && line[3] ~ /^[[:space:]]*;;[[:space:]]*$/ && line[4] ~ /^[[:space:]]*esac([[:space:]]*#.*)?[[:space:]]*$/) { n=0 next } print line[1] line[1]=line[2] line[2]=line[3] line[3]=line[4] n=3 } END { for (i=1; i<=n; i++) print line[i] } ' "$hook_file" >"$hook_tmp" && cat "$hook_tmp" >"$hook_file" rm -f "$hook_tmp" } remove_secondary_dnsmasq_hooks(){ for hook in service-event-end services-start nat-start firewall-start services-stop; do hook_file="/jffs/scripts/$hook" [ -f "$hook_file" ] || continue remove_marked_secondary_dnsmasq_block "$hook_file" case "$hook" in service-event-end|services-start) sed -i '/exclude-devices\.div.*\(start\|ensure\|firewall\)/d; /dnsmasq-instances\.div/d' "$hook_file" >/dev/null ;; services-stop) sed -i '/exclude-devices\.div.*\(stop\|stop-all\)/d; /dnsmasq-instances\.div/d' "$hook_file" >/dev/null ;; *) sed -i '/dnsmasq-instances\.div/d' "$hook_file" >/dev/null ;; esac [ "$hook" = service-event-end ] && remove_orphaned_secondary_dnsmasq_case "$hook_file" remove_when_empty "$hook_file" || true done } write_secondary_dnsmasq_hooks(){ # Remove only the obsolete Entware startup command. # Do not delete unrelated rc.unslung commands owned by other add-ons. if [ -f /jffs/scripts/services-start ]; then services_start_tmp="/jffs/scripts/services-start.diversion.$$" if awk ' /^[[:space:]]*\/opt\/etc\/init\.d\/rc\.unslung[[:space:]]+start([[:space:]]+"\$0")?[[:space:]]*(#.*)?[[:space:]]*$/ { next } { print } ' /jffs/scripts/services-start >"$services_start_tmp" then cat "$services_start_tmp" >/jffs/scripts/services-start fi rm -f "$services_start_tmp" remove_when_empty /jffs/scripts/services-start || true unset services_start_tmp fi services_stop_has_entware=no if [ -f /jffs/scripts/services-stop ] && grep -q '/opt/etc/init.d/rc\.unslung stop.*# Added by Diversion' /jffs/scripts/services-stop then services_stop_has_entware=yes fi remove_secondary_dnsmasq_hooks ensure_hook_script /jffs/scripts/service-event-end check_nl /jffs/scripts/service-event-end cat <<'EOF' >>/jffs/scripts/service-event-end # BEGIN Diversion secondary dnsmasq case "$1:$2" in start:dnsmasq|restart:dnsmasq|start:dnsfilter|restart:dnsfilter) [ -s /opt/share/diversion/file/dnsmasq-instances.div ] && /bin/sh /opt/share/diversion/file/dnsmasq-instances.div ensure ;; esac # END Diversion secondary dnsmasq EOF ensure_hook_script /jffs/scripts/nat-start check_nl /jffs/scripts/nat-start echo '[ -s /opt/share/diversion/file/dnsmasq-instances.div ] && /bin/sh /opt/share/diversion/file/dnsmasq-instances.div nat-firewall # Added by Diversion' >>/jffs/scripts/nat-start ensure_hook_script /jffs/scripts/firewall-start check_nl /jffs/scripts/firewall-start echo '[ -s /opt/share/diversion/file/dnsmasq-instances.div ] && /bin/sh /opt/share/diversion/file/dnsmasq-instances.div input-firewall # Added by Diversion' >>/jffs/scripts/firewall-start ensure_hook_script /jffs/scripts/services-start check_nl /jffs/scripts/services-start echo '[ -s /opt/share/diversion/file/dnsmasq-instances.div ] && /bin/sh /opt/share/diversion/file/dnsmasq-instances.div startup & # Added by Diversion' >>/jffs/scripts/services-start ensure_hook_script /jffs/scripts/services-stop if [ "$services_stop_has_entware" = yes ]; then sed -i '/\/opt\/etc\/init\.d\/rc\.unslung stop.*# Added by Diversion/d' /jffs/scripts/services-stop fi check_nl /jffs/scripts/services-stop echo '[ -s /opt/share/diversion/file/dnsmasq-instances.div ] && /bin/sh /opt/share/diversion/file/dnsmasq-instances.div stop # Added by Diversion' >>/jffs/scripts/services-stop if [ "$services_stop_has_entware" = yes ]; then echo "/opt/etc/init.d/rc.unslung stop # Added by $NAME" >>/jffs/scripts/services-stop fi for hook in service-event-end services-start nat-start firewall-start services-stop; do [ -f "/jffs/scripts/$hook" ] && chmod 0755 "/jffs/scripts/$hook" done unset services_stop_has_entware } download_secondary_dnsmasq_controller(){ controller="${DIVERSION_DIR}/file/dnsmasq-instances.div" controller_tmp="${controller}.new.$$" rm -f "$controller_tmp" if ! c_url "${DIVERSION_URL}/file/dnsmasq-instances.div" \ -o "$controller_tmp" then rm -f "$controller_tmp" lastError=" Secondary Dnsmasq controller download failed" unset controller controller_tmp return 1 fi if [ ! -s "$controller_tmp" ] || ! grep -q '^#bof$' "$controller_tmp" || ! grep -q '^#eof$' "$controller_tmp" || ! /bin/sh -n "$controller_tmp" then rm -f "$controller_tmp" lastError=" Downloaded secondary Dnsmasq controller is invalid" unset controller controller_tmp return 1 fi if ! mv -f "$controller_tmp" "$controller"; then rm -f "$controller_tmp" lastError=" Could not install secondary Dnsmasq controller" unset controller controller_tmp return 1 fi chmod 0755 "$controller" echo "${OK} dnsmasq-instances.div integrated" unset controller controller_tmp return 0 } ensure_secondary_dnsmasq_integration(){ [ "${1:-}" = force ] || secondary_dnsmasq_feature_installed || return 0 if ! secondary_dnsmasq_controller_valid; then echo "${INFO} Repairing secondary Dnsmasq controller" if ! download_secondary_dnsmasq_controller; then echo "${NOK} Secondary Dnsmasq controller repair failed" return 1 fi fi if ! write_secondary_dnsmasq_hooks; then lastError=" Secondary Dnsmasq hook setup failed" return 1 fi if ! secondary_dnsmasq_integration_valid; then lastError=" Secondary Dnsmasq integration validation failed" return 1 fi return 0 } cleanup_secondary_dnsmasq_firewall(){ for dns_proto in udp tcp; do while iptables -t nat -C PREROUTING \ -i br+ \ -p "$dns_proto" \ --dport 53 \ -j DIVERSION_DNSMASQ 2>/dev/null do iptables -t nat -D PREROUTING \ -i br+ \ -p "$dns_proto" \ --dport 53 \ -j DIVERSION_DNSMASQ 2>/dev/null done done # Flush the parent before deleting the mapping chains # referenced by the parent. iptables -t nat -F DIVERSION_DNSMASQ \ 2>/dev/null || true for dns_chain in \ DIVERSION_DNS_MAP_A \ DIVERSION_DNS_MAP_B do iptables -t nat -F "$dns_chain" \ 2>/dev/null || true iptables -t nat -X "$dns_chain" \ 2>/dev/null || true done iptables -t nat -X DIVERSION_DNSMASQ \ 2>/dev/null || true # dnsmasq-instances.div normally removes its filter/INPUT integration # during stop. Keep a fallback here so uninstall/repair cannot leave a # stale INPUT jump or V3/V4 filter chain behind if the controller is # missing, damaged, or exits before cleanup completes. dns_input_hook_lines="/tmp/diversion-dns-input-cleanup.$$" if iptables -t filter -S INPUT 2>/dev/null | awk ' $1 == "-A" && $2 == "INPUT" { rule_number++ for (i=3; i<=NF; i++) { if ($i == "-j" && i < NF && $(i+1) == "DIVERSION_DNS_IN") { print rule_number break } if ($i ~ /^--jump=/) { target=$i sub(/^--jump=/, "", target) if (target == "DIVERSION_DNS_IN") { print rule_number break } } } } ' | sort -rn >"$dns_input_hook_lines" then while IFS= read -r dns_input_hook_line; do [ -n "$dns_input_hook_line" ] || continue iptables -t filter -D INPUT "$dns_input_hook_line" 2>/dev/null || true done <"$dns_input_hook_lines" fi rm -f "$dns_input_hook_lines" # Flush the parent before the V4 A/B children. This also cleans the V3 # layout, where DIVERSION_DNS_IN contained the ACCEPT rules directly. iptables -t filter -F DIVERSION_DNS_IN 2>/dev/null || true for dns_input_chain in DIVERSION_DNS_IN_A DIVERSION_DNS_IN_B; do iptables -t filter -F "$dns_input_chain" 2>/dev/null || true iptables -t filter -X "$dns_input_chain" 2>/dev/null || true done iptables -t filter -X DIVERSION_DNS_IN 2>/dev/null || true unset dns_input_hook_lines dns_input_hook_line dns_input_chain return 0 } remove_secondary_dnsmasq_integration(){ if [ -s "${DIVERSION_DIR}/file/dnsmasq-instances.div" ]; then /bin/sh "${DIVERSION_DIR}/file/dnsmasq-instances.div" stop >/dev/null 2>&1 || true fi cleanup_secondary_dnsmasq_firewall for marker_ip in "${aBFIP:-}" "${exclIP:-}" "${restrictedIP:-}"; do [ -n "$marker_ip" ] || continue ip addr del "$marker_ip/32" dev br0 2>/dev/null || true ip addr del "$marker_ip/24" dev br0 2>/dev/null || true done ifconfig br0:alternate_bf down 2>/dev/null || true ifconfig br0:ad_blocking_excl down 2>/dev/null || true ifconfig br0:restricted_devices down 2>/dev/null || true remove_secondary_dnsmasq_hooks rm -f "${DIVERSION_DIR}/file/dnsmasq-instances.div" \ "${DIVERSION_DIR}/.conf/alternate-bf.conf" \ "${DIVERSION_DIR}/.conf/ad_blocking_excl.conf" \ "${DIVERSION_DIR}/.conf/restricted_devices.conf" \ /var/run/alternate_bf_dnsmasq.pid \ /var/run/ad_blocking_excl_dnsmasq.pid \ /var/run/restricted_devices_dnsmasq.pid rm -rf /tmp/diversion-dnsmasq-instances.lock } cleanup_secondary_dnsmasq_if_unused(){ secondary_dnsmasq_feature_installed && return 0 remove_secondary_dnsmasq_integration } sync_secondary_dnsmasq_integration(){ if secondary_dnsmasq_feature_installed; then get_file dnsmasq-instances.div "$1" ensure_secondary_dnsmasq_integration || return 1 else remove_secondary_dnsmasq_integration fi return 0 } c_url(){ [ -f /opt/bin/curl ] && curlv=/opt/bin/curl || curlv=/usr/sbin/curl;$curlv -sL --connect-timeout 10 --retry 3 "$@";} check_nl(){ [ -n "$(tail -c2 "$1")" ] && echo >> "$1";} check_ntp(){ if [ "$(nvram get ntp_ready)" = 0 ]; then lastError=" NTP not ready, check that this routers time\\n is synced in Administration / System";reload_menu;fi;} dos_to_unix(){ dos2unix < $1 | cmp -s - $1;[ "$?" = "1" ] && dos2unix $1;} exit_message(){ lastAction=" Option Exit selected";} human_number(){ sed -re " :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart ";} large_number(){ [ "$1" -lt "1000000" ] && num="$(echo "$1" | human_number)" || num="$(awk -v sum="$1" 'BEGIN{{sum};hum[1000**3]="B";hum[1000**2]="M";hum[1000]="K"; for (x=1000**3; x>=1000; x/=1000){if (sum>=x) { printf "%.3f%s\n",sum/x,hum[x];break }}}')";} press_enter_to(){ printf "\\n${ATTN} Press Enter to $1 ";read -r;echo;} print_red_line(){ echo "${RED_LINE}____________________________________________________${NC}";echo;} read_conf_file(){ . "${DIVERSION_DIR}"/.conf/diversion.conf;} reload_SELF(){ [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock;exec "/opt/bin/$SELF";} reload_menu(){ [ "$rmdiversionlock" = yes ] && rm -rf /tmp/diversion.lock;acOff=1;state_check;show_menu;} remove_when_empty(){ [ "$(sed '/^[[:space:]]*$/d; /#!\/bin\/sh/d' "$1" | wc -c)" = 0 ] && rm "$1";} restart_DNSMASQ(){ service restart_dnsmasq >/dev/null;} theme_local(){ RED_LINE='';NC='';OK=" [✓]";NOK=" [X]";INFO=" [i]";QUESTION=" [?]";ATTN=" [!]";DONE=" [Done]";ERR=" [Error]";SPACE=" ";} theme_standard(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${RED_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=39;} theme_green(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${ERR_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=39;} theme_blue(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${ERR_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=39;} theme_blue_on_white(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${ERR_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=40;} theme_solarized(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${ERR_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=51;} theme_high_contrast(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=39;} theme_reduced(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=40;} theme_reduced_w(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=42;} theme_reduced_cw(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=42;} theme_reduced_b(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=40;} theme_reduced_cb(){ RED='';RED_LINE='';RED_BG='';ERR_BG='';GREEN='';GREEN_BG='';WHITE_BOLD='';YELLOW='';BLUE='';GRAY='';NC='';OK=" ${GREEN_BG}${WHITE_BOLD} ✓ ${NC}";NOK=" ${RED_BG}${WHITE_BOLD} X ${NC}";INFO=" ${GREEN_BG}${WHITE_BOLD} i ${NC}";QUESTION=" ${GREEN_BG}${WHITE_BOLD} ? ${NC}";ATTN=" ${GREEN_BG}${WHITE_BOLD} ! ${NC}";DONE="${GREEN_BG}${WHITE_BOLD} Done ${NC}";ERR="${ERR_BG}${WHITE_BOLD} Error ${NC}";SPACE=" ";DCORR=40;} theme_basic(){ RED=;RED_LINE='';RED_BG=;ERR_BG=;GREEN=;GREEN_BG=;YELLOW=;BLUE=;GRAY='';NC='';OK=" [✓]";NOK=" [X]";INFO=" [i]";QUESTION=" [?]";ATTN=" [!]";DONE=" [Done]";ERR=" [Error]";SPACE=" ";DCORR=34;} trim_large_file(){ sed -i '/^[[:space:]]*$/d' "$1"; sed -i '4001,$ d' "$1"; [ -n "$(tail -c1 "$1")" ] && echo >> "$1";} version_check(){ echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';} webFiles="index.asp process.div diversion/diversion.css diversion/home.html diversion/lists.html diversion/diversion-txt.png diversion/diversion-logo.png" write_conf_file(){ get_file write-config.div include;write_conf;} write_message(){ echo "lastAction=\"$lastAction\"" >/tmp/divmessage;echo "lastError=\"$lastError\"" >>/tmp/divmessage;} a_function(){ read_conf_file if [ "$adblocking" = on ]; then adblocking=off write_conf_file restart_DNSMASQ lastAction=" ad-blocking disabled" elif [ -z "$adblocking" ] || [ "$adblocking" = off ]; then adblocking=on write_conf_file restart_DNSMASQ lastAction=" ad-blocking enabled" fi [ "$bm" = ssh ] && echo "${OK}$lastAction" [ "$bm" = ios ] && echo "✓$lastAction" } ac_function(){ if /opt/bin/grep -wq "log-facility" /etc/dnsmasq.conf; then if [ -f "${LOG_DIR}/dnsmasq.log" ]; then if [ -f "/tmp/div_lock_ac" ]; then sleep 4 echo "$$" > "/tmp/div_lock_ac" for process in $(ps -T | grep 'diversion ac\|diversion count_ads' | grep -v 'grep ' | awk '{print $1}'); do [ "$process" != "$(sed -n '1p' /tmp/div_lock_ac)" ] && kill "$process" 2> /dev/null done else echo "$$" > "/tmp/div_lock_ac" fi read_conf_file [ "$adsCountLM" = '' ] && adsCountLM=diversion-ads-counter if /opt/bin/grep -P -q -m1 "$adsCountLM" ${LOG_DIR}/dnsmasq.log; then adsNew=$(sed -n "/$adsCountLM/,\$p" ${LOG_DIR}/dnsmasq.log | /opt/bin/grep -c ' config .* is NXDOMAIN') else adsNew=$(/opt/bin/grep -c ' config .* is NXDOMAIN' ${LOG_DIR}/dnsmasq.log) fi adsCountLM=$(tail -1 /opt/var/log/dnsmasq.log | sed -e 's~\/~\\/~g;s/\]/\\]/g;s/\[/\\[/g') adsBlocked=$((adsNew+adsBlocked)) adsWeek=$((adsNew+adsWeek)) if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then [ "$adsCountAltLM" = '' ] && adsCountAltLM=diversion-ads-counter if /opt/bin/grep -q -m1 "$adsCountAltLM" ${LOG_DIR}/dnsmasq.log3; then adsNewAlt=$(sed -n "/$adsCountAltLM/,\$p" ${LOG_DIR}/dnsmasq.log3 | /opt/bin/grep -c ' config .* is NXDOMAIN') else adsNewAlt=$(/opt/bin/grep -c ' config .* is NXDOMAIN' ${LOG_DIR}/dnsmasq.log3) fi adsCountAltLM=$(tail -1 /opt/var/log/dnsmasq.log3 | sed -e 's~\/~\\/~g;s/\]/\\]/g;s/\[/\\[/g') adsBlockedAlt=$((adsNewAlt+adsBlockedAlt)) adsWeekAlt=$((adsNewAlt+adsWeekAlt)) fi [ -z "$adsPrevCount" ] && adsPrevCount=$(date +"%b %d %R") || adsPrevCount=$adsLastCount adsLastCount=$(date +"%b %d %R") # Positional parameters: 1: show in UI, 2: reset weekly counter if [ "$1" = "show" ]; then if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then lastAction=" updated ads counter, Primary ad-blocking:" lastAction="$lastAction\\n $(echo $adsBlocked | human_number) total, $(echo $adsWeek | human_number) this week, $(echo $adsNew | human_number) new" lastAction="$lastAction\\n Alternate ad-blocking:" lastAction="$lastAction\\n $(echo $adsBlockedAlt | human_number) total, $(echo $adsWeekAlt | human_number) this week, $(echo $adsNewAlt | human_number) new" else lastAction=" updated ads counter: $(echo $adsBlocked | human_number) total," lastAction="$lastAction\\n $(echo $adsWeek | human_number) this week, $(echo $adsNew | human_number) new since last count" fi elif [ "$2" = "sh" ]; then if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then printf "Primary ad-blocking\\ntotal ads blocked: $(echo $adsBlocked | human_number)\\nthis week: $(echo $adsWeek | human_number)\\nnew since last count: $(echo $adsNew | human_number)" printf "\\n\\nAlternate ad-blocking\\ntotal ads blocked: $(echo $adsBlockedAlt | human_number)\\nthis week: $(echo $adsWeekAlt | human_number)\\nnew since last count: $(echo $adsNewAlt | human_number)" else printf "Total ads blocked: $(echo $adsBlocked | human_number)\\nThis week: $(echo $adsWeek | human_number)\\nNew since last count: $(echo $adsNew | human_number)" fi elif [ "$2" = "reset" ]; then if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then logger -t Diversion "updated and reset weekly ads counter: $(echo $((adsBlocked+adsBlockedAlt)) | human_number) total, $(echo $((adsWeek+adsWeekAlt)) | human_number) this week, $(echo $((adsNew+adsNewAlt)) | human_number) new since last count" adsWeek=0 adsWeekAlt=0 else logger -t Diversion "updated and reset weekly ads counter: $(echo $adsBlocked | human_number) total, $(echo $adsWeek | human_number) this week, $(echo $adsNew | human_number) new since last count" adsWeek=0 fi elif [ "$2" = "count" ]; then if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then logger -t Diversion "updated ads counter: $(echo $((adsBlocked+adsBlockedAlt)) | human_number) total, $(echo $((adsWeek+adsWeekAlt)) | human_number) this week, $(echo $((adsNew+adsNewAlt)) | human_number) new since last count" else logger -t Diversion "updated ads counter: $(echo $adsBlocked | human_number) total, $(echo $adsWeek | human_number) this week, $(echo $adsNew | human_number) new since last count" fi fi write_conf_file rm -f "/tmp/div_lock_ac" else lastError=" dnsmasq.log not found, cannot count ads" logger -t Diversion "dnsmasq.log not found, cannot count ads" fi else [ "$2" = "sh" ] && printf "Logging is off, no stats available" lastError=" logging is disabled, cannot count ads" logger -t Diversion "logging is disabled, cannot count ads" fi } continue_dialog(){ while true; do printf "\\n Continue? [1=Yes e=Exit] ";read -r continue case "$continue" in 1) break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n\\n";; esac done } ct_function(){ print_the_line(){ echo "${RED_LINE}____________________________________________________${NC}";} if [ -z "$1" ]; then printf " This changes the $NAME theme.\\n All used colors are shown in the themes below.\\n" printf "\\n Your current theme is: ${RED_BG} $THEME ${NC}\\n\\n" else print_red_line printf "${QUESTION} Select a theme that works best in your\\n${SPACE} SSH client. All colors in use are shown.\\n\\n" fi themes='standard green blue blue_on_white solarized high_contrast reduced reduced_w reduced_cw reduced_b reduced_cb' i=1 for theme in $themes; do ncorr=' ' case $theme in blue) corr5=+1;corr6=+1;; blue_on_white) corr3=-1;corr2=-1;corr4=-1;; solarized) corr6=-9;corr4=-12;; reduced) corr3=-1;corr2=-1;corr4=-1;; reduced_w) corr3=-3;corr2=-3;corr4=-3;; reduced_cw) corr3=-3;corr2=-3;corr4=-3;; reduced_b) corr3=+5;corr2=+5;corr4=-1;; reduced_cb) ncorr=;corr2=-1;corr5=+2;corr3=+5;corr6=+2;corr4=-1;; esac theme_$theme printf "%-$((DCORR-16$corr1))s %-$((DCORR-15$corr2))s %-$((DCORR-6))s\\n" "${RED_BG}$ncorr$i. $theme" "${NC} ${RED} $theme" "${NC}${OK}${NOK}${DONE}" printf " %-$((DCORR-19$corr5))s %-$((DCORR-15$corr3))s %-s\\n" "${ERR_BG} $theme" "${NC} ${GREEN} $theme" "${NC}${INFO}${QUESTION}${ERR}" printf " %-$((DCORR-19$corr6))s %-$((DCORR-14$corr4))s %-s\\n" "${GREEN_BG} $theme" "${NC} ${YELLOW} $theme" "${NC}${BLUE}$theme${NC}" print_red_line i=$((i+1)) unset corr1 corr2 corr3 corr4 corr5 corr6 ncorr done theme_basic printf "${RED_BG}12. basic ${NC}${RED} basic ${NC}${OK}${NOK}${DONE}\\n" printf " ${ERR_BG} basic ${NC}${GREEN} basic ${NC}${INFO}${QUESTION}${ERR}\\n" print_the_line printf "\\n The basic and reduced themes use no or fewer\\n" printf " colors, service states may not be visible.\\n" theme_standard while true;do if [ -z "$1" ]; then printf "\\n Set new theme: [1-12 e=Exit] ";read -r continue else printf "\\n Select $NAME theme: [1-12] ";read -r continue fi case "$continue" in 1) THEME=standard;break;; 2) THEME=green;break;; 3) THEME=blue;break;; 4) THEME=blue_on_white;break;; 5) THEME=solarized;break;; 6) THEME=high_contrast;break;; 7) THEME=reduced;break;; 8) THEME=reduced_w;break;; 9) THEME=reduced_cw;break;; 10) THEME=reduced_b;break;; 11) THEME=reduced_cb;break;; 12) THEME=basic;break;; [Ee]) if [ -z "$1" ]; then exit_message;reload_menu else printf "\\n input is not an option\\n" fi ;; *) printf "\\n input is not an option\\n";; esac done if [ -z "$1" ]; then lastAction=" changed theme to $THEME" write_conf_file else theme_$THEME echo fi } diversion_help(){ echo " Usage: diversion [option] Example: 'diversion disable' Example: 'diversion' (no option) opens full SSH UI a or adblocking disables/enables ad-blocking. ac or count_ads counts newly blocked ads. bu updates the blocking list. disable disables all $NAME services. temp_disable disables all $NAME services until router reboots. enable enables active $NAME services, overrides temp_disable setting. f or follow tails (follows) the Dnsmasq log file. fs fast switches between blocking lists. h or help opens this help menu. l or logging disables/enables logging. restart restarts all active $NAME services. "; } diversion_unlock(){ if [ -f /tmp/diversion.lock ] && [ -d "/proc/$(sed -n '2p' /tmp/diversion.lock)" ]; then logger -st Diversion "Killing locked $NAME processes ($(sed -n '1p' /tmp/diversion.lock)) (pid=$(sed -n '2p' /tmp/diversion.lock))" logger -st Diversion "$(ps | awk -v pid="$(sed -n '2p' /tmp/diversion.lock)" '$1 == pid')" kill "$(sed -n '2p' /tmp/diversion.lock)" rm -rf /tmp/diversion.lock echo fi } diversion_lock(){ if [ -f /tmp/diversion.lock ] && [ -d "/proc/$(sed -n '2p' /tmp/diversion.lock)" ] && [ "$(sed -n '2p' /tmp/diversion.lock)" != "$$" ]; then if [ "$(($(date +%s)-$(sed -n '3p' /tmp/diversion.lock)))" -gt "1800" ]; then diversion_unlock elif [ "$menuActive" = yes ]; then lastError=" lock file found, ${NC}$(sed -n '1p' /tmp/diversion.lock) active" rmdiversionlock=no reload_menu else [ "$bm" = ssh ] && printf "\\n${NOK} lock file found, $(sed -n '1p' /tmp/diversion.lock) active\\n\\n" [ "$bm" = ios ] && echo "X lock file found, $(sed -n '1p' /tmp/diversion.lock | cut -f 1,3 -d ' ') active" exit 1 fi fi echo "$@" > /tmp/diversion.lock echo "$$" >> /tmp/diversion.lock date +%s >> /tmp/diversion.lock rmdiversionlock=yes } tail_logfile_colors(){ [ "$RED_NXDOMAIN" = '' ] && RED_NX=${RED} || RED_NX=${RED_NXDOMAIN} [ "$GRAY_reply" = '' ] && GRAY_RY=${GRAY} || GRAY_RY=${GRAY_reply} [ "$YELLOW_forwarded" = '' ] && YELLOW_FW=${YELLOW} || YELLOW_FW=${YELLOW_forwarded} [ "$GREEN_query" = '' ] && GREEN_QY=${GREEN} || GREEN_QY=${GREEN_query} [ "$BLUE_cached" = '' ] && BLUE_CD=${BLUE} || BLUE_CD=${BLUE_cached} } follow_dnsmasq(){ if ! /opt/bin/grep -wq "log-facility" /etc/dnsmasq.conf; then printf "${NOK} Logging is disabled\\n\\n" exit 0 fi tail_logfile_colors follow_dnsmasq_alternate_bl printf "${INFO} Press Ctrl+C to exit\\n\\n" tail -F "${LOG_DIR}/dnsmasq.$log" | sed -E \ -e "s,($(date +'%b %d ')| dnsmasq[.*[0-9]]),,g" \ -e "s, config .* is NXDOMAIN,${RED_NX}&${NC}," \ -e "s,.*(query\\[A|DHCP).*,${NC}&${NC}," \ -e "s,.*,${GRAY_RY}&${NC}," } follow_dnsmasq_alternate_bl(){ log=log if [ "$bfFs" = on ] && [ "$alternateBF" = on ]; then printf "${ATTN} Alternate blocking list is active.\\n\\n" printf " 1. Follow standard blocking list\\n" printf " 2. Follow alternate blocking list\\n" while true; do printf "\\n Enter selection [1-2 e=Exit] ";read -r continue case "$continue" in 1) break;; 2) log=log3;break;; [Ee]) exit_message;reload_menu;break;; *) printf "\\n input is not an option\\n\\n";; esac done printf "\\n Following ${LOG_DIR}/dnsmasq.$log\\n\\n" fi } fs_function(){ if [ "$bfFs" = on ]; then read_conf_file if [ "$bfTypeinUse" = "primary" ]; then bfTypeinUse=secondary lastAction=" Secondary blocking list ($bfTypeFs) active" elif [ "$bfTypeinUse" = "secondary" ]; then bfTypeinUse=primary lastAction=" Primary blocking list ($bfType) active" fi [ "$bm" = ssh ] && echo "${OK}$lastAction" [ "$bm" = ios ] && echo "✓$lastAction" logger -t Diversion "$bfTypeinUse blocking list is now active" write_conf_file restart_DNSMASQ if [ "$SkynetFs" = on ]; then if [ -f "/jffs/scripts/firewall" ] && /opt/bin/grep -q "sh /jffs/scripts/firewall" /jffs/scripts/firewall-start 2> /dev/null; then skynetcfg="$(grep -ow "skynetloc=.* # Skynet" /jffs/scripts/firewall-start 2>/dev/null | grep -vE "^#" | awk '{print $1}' | cut -c 11-)/skynet.cfg" grep "customlist2url" "$skynetcfg" >/tmp/diversion-skynet grep "fastswitch" "$skynetcfg" >>/tmp/diversion-skynet . /tmp/diversion-skynet if [ "$customlist2url" ]; then if [ -f /tmp/diversion.lock ]; then lastAction="${lastAction}.\\nSkynet lock file found, no fast switch change" [ "$bm" = ssh ] && echo "${NOK} Skynet lock file found, no fast switch change" else if [ "$bfTypeinUse" = "primary" ] && [ "$fastswitch" = enabled ]; then /bin/sh /jffs/scripts/firewall fs >/dev/null & text="Skynet fast switch has been disabled" lastAction="${lastAction}.\\n$text" [ "$bm" = ssh ] && echo "${OK} $text" logger -t Diversion "$text" elif [ "$bfTypeinUse" = "secondary" ] && [ "$fastswitch" = disabled ]; then /bin/sh /jffs/scripts/firewall fs >/dev/null & text="Skynet fast switch has been enabled" lastAction="${lastAction}.\\n$text" [ "$bm" = ssh ] && echo "${OK} $text" logger -t Diversion "$text" else lastAction="${lastAction}.\\nSkynet fast switch already in $fastswitch mode" [ "$bm" = ssh ] && echo "${OK} Skynet fast switch already in $fastswitch mode" fi fi else lastAction="${lastAction}.\\nSkynet fast switch not configured" [ "$bm" = ssh ] && echo "${NOK} Skynet fast switch not configured" fi rm -f /tmp/diversion-skynet fi fi else lastError=" blocking list fast switch is not enabled" [ "$bm" = ssh ] && echo "${NOK}$lastError" [ "$bm" = ios ] && echo "X$lastError" fi } get_file(){ [ -z "$3" ] && set -- "$1" "$2" "${DIVERSION_DIR}/file" "$4" "$5" [ -z "$4" ] && set -- "$1" "$2" "$3" "/file/" "$5" # Positional parameters: 1: File, 2: Action, 3: Save to, 4: Get from, 5: Copy to faok= if [ "$2" = new ]; then c_url "${DIVERSION_URL}$4$1" -o "$3/${1}.new" if [ -s "$3/${1}.new" ]; then if grep -wq '^#bof\|^#eof' "$3/${1}.new"; then mv -f "$3/${1}.new" "$3/$1" if [ "$5" ] && [ -d "$5" ]; then cp "$3/$1" "$5/$1" fi [ "$action" != "amtm-update" ] && printf "${OK} %-20s%s\\n" "$1 " "integrated" faok=ok elif [ -f "$3/$1" ]; then rm -f "$3/${1}.new" if [ "$5" ] && [ -d "$5" ]; then cp "$3/$1" "$5/$1" fi if [ "$action" = "update" ]; then echo "${NOK} $1 is not a $NAME file" lastError=" $1 is not a $NAME file,\\n Run $action again." action= write_conf_file reload_menu else echo "${NOK} $1 is not a $NAME file," echo "${SPACE} using existing file" lastError=" $1 is not a $NAME file,\\n using existing file" fi else rm -f "$3/${1}.new" echo "${NOK} $1 is not a $NAME file" faok=nok lastError=" $1 is not a $NAME file,\\n Run function again." action= write_conf_file reload_menu fi elif [ -f "$3/$1" ]; then rm -f "$3/${1}.new" if [ "$5" ] && [ -d "$5" ]; then cp "$3/$1" "$5/$1" fi if [ "$action" = "update" ]; then echo "${NOK} $1 download failed" lastError=" $1 download failed,\\n Run $action again." action= write_conf_file reload_menu else echo "${NOK} $1 download failed," echo "${SPACE} using existing file" lastError=" $1 download failed,\\n using existing file" fi else rm -f "$3/${1}.new" echo "${NOK} $1 download failed" faok=nok lastError=" $1 download failed,\\n Run function again." action= write_conf_file reload_menu fi fi if [ "$2" = zip ]; then if [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ]; then c_url "${DIVERSION_URL}/file/webui_LTS.zip" -o "$3/${1}" else c_url "${DIVERSION_URL}$4$1" -o "$3/${1}" fi if [ -f "$3/${1}" ]; then printf "${OK} %-20s%s\\n" "$1 " "downloaded" mkdir -p "${DIVERSION_DIR}/webuitmp" unzip -oq "$3/${1}" -d "${DIVERSION_DIR}/webuitmp" dlwf=ok for file in $webFiles; do if [ ! -f "${DIVERSION_DIR}/webuitmp/$file" ]; then dlwf=nok fi done if [ "$dlwf" = ok ]; then faok=ok printf "${OK} %-20s%s\\n" "$1 " "extracted" rm -rf "${DIVERSION_DIR}/webui" mv "${DIVERSION_DIR}/webuitmp" "${DIVERSION_DIR}/webui" else rm -f "$3/${1}" rm -rf "${DIVERSION_DIR}/webuitmp" echo "${NOK} $1 extraction failed" faok=nok lastError=" $1 extraction failed,\\n Run function again." action= fi else rm -f "$3/${1}" echo "${NOK} $1 download failed" faok=nok lastError=" $1 download failed,\\n Run function again." action= fi fi if [ "$2" = check ]; then if [ -f "$3/$1" ]; then if ! grep -wq '^#bof\|^#eof' "$3/$1"; then get_file "$1" new "$3" "$4" "$5" fi if [ "$5" ] && [ -d "$5" ]; then cp "$3/$1" "$5/$1" fi [ "$fa" = "check" ] && echo "${OK} $1" faok=ok else get_file "$1" new "$3" "$4" "$5" fi fi if [ "$2" = include ]; then if [ -f "$3/$1" ]; then . "$3/$1" else get_file "$1" new "$3" "$4" "$5" . "$3/$1" fi fi case "$1" in alternate-bf.div|exclude-devices.div|restricted-devices.div|dnsmasq-instances.div) [ -f "$3/$1" ] && chmod 0755 "$3/$1" ;; esac } get_latest_files(){ if [ "$fa" = "check" ]; then printf "\\n${INFO} Checking $NAME files\\n" else printf "\\n${INFO} Downloading $NAME from $(echo "$DIVERSION_URL" | awk -F[/:] '{print $4}')\\n" fi if [ "$alternateBF" = on ] || [ -f "${DIVERSION_DIR}/file/alternate-bf.div" ]; then get_file alternate-bf.div "$1" fi [ "$backup" = on ] || [ -f "${DIVERSION_DIR}/file/backup.div" ] && get_file backup.div "$1" sync_secondary_dnsmasq_integration "$1" || return 1 if [ "$exclDevices" = on ] || [ -f "${DIVERSION_DIR}/file/exclude-devices.div" ]; then get_file exclude-devices.div "$1" fi get_file functions.div "$1" get_file helper.div "$1" [ "$action" != "update" ] && get_file install.div "$1" [ ! -f "${AMTM_DIR}"/mount-entware.mod ] && get_file mount-entware.mod "$1" "${DIVERSION_DIR}/file" /file/ "${AMTM_DIR}" get_file post-conf.div "$1" if [ -n "$restrictedDevices" ] || [ -f "${DIVERSION_DIR}/file/restricted-devices.div" ]; then get_file restricted-devices.div "$1" fi get_file rotate-logs.div "$1" [ "$weeklyStats" = on ] || [ -f "${DIVERSION_DIR}/file/stats.div" ] && get_file stats.div "$1" get_file update-bl.div "$1" [ "$webUi" = enabled ] && get_file webui.zip zip get_file write-config.div "$1" set_file_permissions } get_self(){ get_file "$SELF" "$1" "/opt/bin" "/" if [ "$action" = web-update ]; then if [ "$faok" = ok ]; then set_file_permissions action=web-update write_conf_file webui_set Diversion_update 10% reload_SELF else action= write_conf_file webui_set Diversion_update failed exit 1 fi elif [ "$action" = amtm-update ]; then if [ "$faok" = ok ]; then set_file_permissions write_conf_file reload_SELF else action= write_conf_file exit 1 fi else if [ "$faok" = ok ]; then [ "$1" = "check" ] && echo "${OK} $SELF" set_file_permissions write_conf_file reload_SELF else reload_menu fi fi } l_function(){ read_conf_file if [ "$logging" = on ]; then logging=off lastAction=" logging disabled" elif [ -z "$logging" ] || [ "$logging" = off ]; then read_conf_file logging=on lastAction=" logging enabled" fi [ "$bm" = ssh ] && echo "${OK}$lastAction" [ "$bm" = ios ] && echo "✓$lastAction" write_conf_file restart_DNSMASQ } on_off_diversion(){ read_conf_file if [ "$DIVERSION_STATUS" = enabled ] && [ "$1" = "disable" ]; then stop_secondary_dnsmasq_instances DIVERSION_STATUS=disabled write_conf_file restart_DNSMASQ lastAction=" $NAME services disabled" elif [ "$DIVERSION_STATUS" = enabled ] && [ "$1" = "temp_disable" ]; then touch /tmp/diversion-temp_disable stop_secondary_dnsmasq_instances DIVERSION_STATUS=disabled DISABLE_STATUS=temp write_conf_file restart_DNSMASQ if [ -z "$tmpDisable" ]; then lastAction=" $NAME services disabled until reboot" else lastAction=" $NAME services disabled for $tmpDisable minutes\\n or until next reboot" tmpDisable= fi elif [ "$DIVERSION_STATUS" = enabled ] && [ "$1" = "restart" ]; then stop_secondary_dnsmasq_instances write_conf_file restart_DNSMASQ lastAction=" $NAME services restarted" elif [ "$DIVERSION_STATUS" = disabled ] && [ "$1" = "enable" ]; then rm -f /tmp/diversion-temp_disable DIVERSION_STATUS=enabled DISABLE_STATUS= cru d Diversion_temp_disable write_conf_file restart_DNSMASQ lastAction=" $NAME services enabled" else lastAction=" No change: $NAME is $DIVERSION_STATUS" fi [ "$bm" = ssh ] && echo "${OK}$lastAction" [ "$bm" = ios ] && echo "✓$lastAction" } stop_secondary_dnsmasq_instances(){ if [ -s "${DIVERSION_DIR}/file/dnsmasq-instances.div" ] && /bin/sh "${DIVERSION_DIR}/file/dnsmasq-instances.div" stop then logger -t "$NAME" "stopped secondary dnsmasq instances" return 0 fi logger -t "$NAME" "controller stop unavailable or failed; removing legacy aliases" ifconfig br0:alternate_bf down 2>/dev/null || true ifconfig br0:ad_blocking_excl down 2>/dev/null || true ifconfig br0:restricted_devices down 2>/dev/null || true return 0 } on_off_webui(){ LOCKFILE=/tmp/addonwebui.lock FD=386 if [ "$1" = check ]; then mkdir -p "${DIVERSION_DIR}/webui/" dlwf=ok for file in $webFiles; do if [ ! -f "${DIVERSION_DIR}/webui/$file" ]; then dlwf=nok fi done if [ "$dlwf" = ok ]; then webUi=enabled else echo printf "\\n${INFO} Downloading $NAME WebUI files from $(echo $DIVERSION_URL | awk -F[/:] '{print $4}')\\n" get_file webui.zip zip if [ "$dlwf" = ok ]; then webUi=enabled else webUi=disabled lastError=" WebUI not enabled, files extraction failed" fi fi if [ "$webUi" = enabled ]; then if [ ! -f "/jffs/scripts/service-event" ]; then echo "#!/bin/sh" >/jffs/scripts/service-event elif [ -f "/jffs/scripts/service-event" ] && ! head -1 /jffs/scripts/service-event | grep -qE "^#!/bin/sh"; then sed -i '1s~^~#!/bin/sh\n~' /jffs/scripts/service-event fi if ! grep -q '^\[ "$2" = diversion \] && /opt/share/diversion/webui' /jffs/scripts/service-event; then sed -i '/process.div/d' /jffs/scripts/service-event >/dev/null check_nl /jffs/scripts/service-event echo "[ \"\$2\" = diversion ] && ${DIVERSION_DIR}/webui/process.div \"\$1\" & # Added by $NAME" >>/jffs/scripts/service-event fi set_file_permissions "${DIVERSION_DIR}"/webui/process.div mount lastAction=" $NAME WebUI enabled in $pageloc" fi elif [ "$1" = remount ]; then if [ "$(am_settings_get _Diversion_uiPage)" ]; then webUiPage=$(am_settings_get _Diversion_uiPage) ln -sf "${DIVERSION_DIR}"/webui/diversion /www/user ln -sf "${DIVERSION_DIR}"/.conf/webui-vars.js "${DIVERSION_DIR}"/webui/diversion if [ "$(version_check $(nvram get firmver))" -ge "$(version_check 3.0.0.6)" ]; then cp -f "${DIVERSION_DIR}"/webui/index3006.asp /www/user/$webUiPage else cp -f "${DIVERSION_DIR}"/webui/index.asp /www/user/$webUiPage fi sed -i "s/MyPage.asp/$webUiPage/g" /www/user/$webUiPage if [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ]; then sed -i "s/LAN -/Addons -/g; s~/js/jquery.js~/jquery.js~g" /www/user/$webUiPage fi printf "${OK} %-20s%s\\n" "WebUI " "remounted" else on_off_webui check fi elif [ "$1" = unmount ]; then eval exec "$FD>$LOCKFILE" /usr/bin/flock -x "$FD" webUiPage=$(am_settings_get _Diversion_uiPage) webui_del_wc Diversion_lists_ rm -f /www/user/$webUiPage if [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ]; then rm -f "/www/user/$(echo $webUiPage | sed 's/.asp//').title" else sed -i '/tabName: "Diversion"/d' /tmp/menuTree.js >/dev/null umount /www/require/modules/menuTree.js 2>/dev/null if diff /tmp/menuTree.js /www/require/modules/menuTree.js >/dev/null; then rm /tmp/menuTree.js else mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js fi fi /usr/bin/flock -u "$FD" rm -rf /www/user/diversion service restart_httpd >/dev/null 2>&1 elif [ "$1" = disable ]; then eval exec "$FD>$LOCKFILE" /usr/bin/flock -x "$FD" webUiPage=$(am_settings_get _Diversion_uiPage) webUi=disabled webui_del_wc Diversion_lists_ rm -f /www/user/$webUiPage if [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ]; then rm -f "/www/user/$(echo $webUiPage | sed 's/.asp//').title" else sed -i '/tabName: "Diversion"/d' /tmp/menuTree.js >/dev/null umount /www/require/modules/menuTree.js 2>/dev/null if diff /tmp/menuTree.js /www/require/modules/menuTree.js >/dev/null; then rm /tmp/menuTree.js else mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js fi fi /usr/bin/flock -u "$FD" rm -rf /www/user/diversion sed -i '/process.div/d' /jffs/scripts/service-event >/dev/null remove_when_empty /jffs/scripts/service-event am_settings_del Diversion am_settings_del _Diversion lastAction=" $NAME WebUI disabled" service restart_httpd >/dev/null 2>&1 elif [ "$1" = remove ]; then eval exec "$FD>$LOCKFILE" /usr/bin/flock -x "$FD" webUiPage=$(am_settings_get _Diversion_uiPage) webUi=disabled rm -f /www/user/$webUiPage if [ "$(/bin/uname -o | grep -iw Merlin-LTS)" ]; then rm -f "/www/user/$(echo $webUiPage | sed 's/.asp//').title" else sed -i '/tabName: "Diversion"/d' /tmp/menuTree.js >/dev/null umount /www/require/modules/menuTree.js 2>/dev/null if diff /tmp/menuTree.js /www/require/modules/menuTree.js >/dev/null; then rm /tmp/menuTree.js else mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js fi fi /usr/bin/flock -u "$FD" rm -rf /www/user/diversion sed -i '/process.div/d' /jffs/scripts/service-event >/dev/null remove_when_empty /jffs/scripts/service-event am_settings_del Diversion am_settings_del _Diversion rm -rf "${DIVERSION_DIR}/webui/"* rm -f "${DIVERSION_DIR}/file/webui.zip" rm -f "${DIVERSION_DIR}"/.conf/webui-vars.js lastAction=" $NAME WebUI files removed" service restart_httpd >/dev/null 2>&1 fi } set_file_permissions(){ [ -f "/opt/bin/$SELF" ] && [ ! -x "/opt/bin/$SELF" ] && chmod 0755 "/opt/bin/$SELF" if [ -d "${DIVERSION_DIR}" ]; then [ -f "${EMAIL_DIR}/email.conf" ] && chmod 0640 "${EMAIL_DIR}/email.conf" [ -f "${EMAIL_DIR}/emailpw.enc" ] && chmod 0640 "${EMAIL_DIR}/emailpw.enc" for file in "${DIVERSION_DIR}/file/"*; do [ -f "$file" ] && [ ! -w "$file" ] && chmod 0666 "$file" done if [ "$webUi" = enabled ]; then for file in "${DIVERSION_DIR}/webui/"*; do [ -f "$file" ] && [ ! -w "$file" ] && chmod 0666 "$file" done fi fi divScripts="/jffs/scripts/dnsmasq.postconf /jffs/scripts/post-mount /jffs/scripts/services-start /jffs/scripts/service-event-end /jffs/scripts/nat-start /jffs/scripts/service-event /jffs/scripts/services-stop ${DIVERSION_DIR}/webui/process.div" for script in $divScripts; do if [ -f "$script" ]; then dos_to_unix "$script" [ ! -x "$script" ] && chmod 0755 "$script" fi done } state_function(){ read_conf_file if [ "$bfFs" = on ]; then [ "$bfTypeinUse" = "primary" ] && bfinUse=$bfType || bfinUse=$bfTypeFs if [ "$bfTypeinUse" = "primary" ]; then large_number "$blockedDomains";bd=$num elif [ "$bfTypeinUse" = "secondary" ]; then large_number "$blockedDomainsFs";bd=$num fi else bfinUse=$bfType large_number "$blockedDomains";bd=$num fi grep -q "Diversion directives" /etc/dnsmasq.conf && Dactive='and active' || Dactive='but services are dead' if [ "$adblocking" = on ]; then grep -q "conf-file=" /etc/dnsmasq.conf && Aactive='and active' || Aactive='but service is dead' fi if [ "$logging" = on ]; then grep -q "log-facility" /etc/dnsmasq.conf && Lactive='and active' || Lactive='but service is dead' fi [ -z "$(nvram get odmpid)" ] && routerModel=$(nvram get productid) || routerModel=$(nvram get odmpid) extendno=$(nvram get extendno) [ "$extendno" = 0 ] && extendno= || extendno=_$extendno [ "$(version_check $(nvram get buildno))" -ge "$(version_check 388)" ] && fwVersion=$(nvram get firmver | sed 's/\.//g').$(nvram get buildno)$extendno || fwVersion=$(nvram get buildno)$extendno printf "$routerModel on firmware $fwVersion @ $(nvram get lan_ipaddr)\\n$NAME $VERSION is $DIVERSION_STATUS $Dactive\\n\\nAd-blocking is $adblocking $Aactive\\nLogging is $logging $Lactive\\n\\nBlocking list <$bfinUse> in use, blocking $bd domains\\nLast updated on $bfUpdateLastRun" } update_blockinglist(){ if [ "$(ps | grep -v grep | grep update-bl.div)" ]; then lastError=" Blocking list update already runs" [ "$bm" = ssh ] && printf "${NOK}$lastError in the background\\n\\n" [ "$bm" = ios ] && echo "X$lastError" else read_conf_file edited_allowlist= edited_denylist= write_conf_file [ "$webUi" = enabled ] && webui_set Diversion_blUpd 1% /bin/sh "${DIVERSION_DIR}/file/update-bl.div" >/dev/null 2>&1 & lastAction=" The blocking list is being updated now." [ "$bm" = ssh ] && printf "${OK}$lastAction\\n\\n" [ "$bm" = ios ] && echo "✓$lastAction" fi } state_check "$@" #eof