diff --git a/README.md b/README.md index 558a98d..c98d1be 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ * Решение построено на стандартных системных службах и утилитах OpenWrt (nftables, dnsmasq). -* Поддерживаются L3 VPN с маршрутизацией на сетевой интерфейс (OpenVPN, Wireguard, PPTP, Sing-box в режиме tun и пр.), прозрачные прокси с перенаправлением на порт (Sing-box в режиме TProxy, Shadowsock-libev, Redsocks и пр.), Tor. +* Поддерживаются L3 VPN с маршрутизацией на сетевой интерфейс (OpenVPN, Wireguard, PPTP, Sing-box в режиме tun и пр.), прозрачные прокси с перенаправлением на порт (Sing-box в режиме TProxy, Xray, V2Ray, Shadowsock-libev, Redsocks и пр.), Tor. * Перенаправление трафика на основе доменов и IP адресов. diff --git a/autoinstall/2.x/apk/autoinstall.sh b/autoinstall/2.x/apk/autoinstall.sh new file mode 100755 index 0000000..1ef449f --- /dev/null +++ b/autoinstall/2.x/apk/autoinstall.sh @@ -0,0 +1,443 @@ +#!/bin/sh + +PREFIX="" +TOR_USER="tor" + +PROXY_MODE=1 +BLACKLIST=0 +LUA_MODULE=0 +LUCI_APP=1 +HTTPS_DNS_PROXY=1 + +OWRT_VERSION="25.12" +RUAB_VERSION="2.1.10-r1" +RUAB_MOD_LUA_VERSION="2.1.10-r1" +RUAB_LUCI_APP_VERSION="2.1.10-r2" +BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master" +PKG_DIR="/tmp" + +if [ -n "$1" ]; then + OWRT_VERSION="$1" +fi + +### URLs + +### packages +URL_RUAB_PKG="${BASE_URL}/${OWRT_VERSION}/ruantiblock-${RUAB_VERSION}.apk" +URL_MOD_LUA_PKG="${BASE_URL}/${OWRT_VERSION}/ruantiblock-mod-lua-${RUAB_MOD_LUA_VERSION}.apk" +URL_LUCI_APP_PKG="${BASE_URL}/${OWRT_VERSION}/luci-app-ruantiblock-${RUAB_LUCI_APP_VERSION}.apk" +URL_LUCI_APP_RU_PKG="${BASE_URL}/${OWRT_VERSION}/luci-i18n-ruantiblock-ru-${RUAB_LUCI_APP_VERSION}.apk" +### tor +URL_TORRC="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master/tor/etc/tor/torrc" + +### Local files + +CONFIG_DIR="${PREFIX}/etc/ruantiblock" +USER_LISTS_DIR="${CONFIG_DIR}/user_lists" +EXEC_DIR="${PREFIX}/usr/bin" +BACKUP_DIR="${CONFIG_DIR}/autoinstall.bak.$(date +%s)" +### packages +FILE_RUAB_PKG="${PKG_DIR}/ruantiblock-${RUAB_VERSION}.apk" +FILE_MOD_LUA_PKG="${PKG_DIR}/ruantiblock-mod-lua-${RUAB_MOD_LUA_VERSION}.apk" +FILE_LUCI_APP_PKG="${PKG_DIR}/luci-app-ruantiblock-${RUAB_LUCI_APP_VERSION}.apk" +FILE_LUCI_APP_RU_PKG="${PKG_DIR}/luci-i18n-ruantiblock-ru-${RUAB_LUCI_APP_VERSION}.apk" +### ruantiblock +FILE_CONFIG="${CONFIG_DIR}/ruantiblock.conf" +FILE_FQDN_FILTER="${CONFIG_DIR}/fqdn_filter" +FILE_IP_FILTER="${CONFIG_DIR}/ip_filter" +FILE_USER_ENTRIES="${CONFIG_DIR}/user_entries" +FILE_BYPASS_ENTRIES="${CONFIG_DIR}/bypass_entries" +FILE_GR_EXCLUDED_SLD="${CONFIG_DIR}/gr_excluded_sld" +FILE_GR_EXCLUDED_NETS="${CONFIG_DIR}/gr_excluded_nets" +FILE_UCI_CONFIG="${PREFIX}/etc/config/ruantiblock" +FILE_INIT_SCRIPT="${PREFIX}/etc/init.d/ruantiblock" +FILE_MAIN_SCRIPT="${EXEC_DIR}/ruantiblock" +### tor +FILE_TORRC="${PREFIX}/etc/tor/torrc" + +AWK_CMD="awk" +WGET_CMD="$(which wget)" +if [ $? -ne 0 ]; then + echo " Error! wget doesn't exists" >&2 + exit 1 +fi +WGET_PARAMS="--no-check-certificate -q -O " +APK_CMD="$(which apk)" +if [ $? -ne 0 ]; then + echo " Error! apk doesn't exists" >&2 + exit 1 +fi +UCI_CMD="$(which uci)" +if [ $? -ne 0 ]; then + echo " Error! uci doesn't exists" >&2 + exit 1 +fi + +FileExists() { + test -e "$1" +} + +MakeDir() { + [ -d "$1" ] || mkdir -p "$1" + if [ $? -ne 0 ]; then + echo "Error! Can't create directory (${1})" >&2 + exit 1 + fi +} + +ChmodExec() { + chmod 755 "$1" +} + +RemoveFile() { + if [ -e "$1" ]; then + echo "Removing ${1}" + rm -f "$1" + fi +} + +DlFile() { + local _dir _file + if [ -n "$2" ]; then + _dir=$(dirname "$2") + MakeDir "$_dir" + _file="$2" + else + _file="-" + fi + $WGET_CMD $WGET_PARAMS "$_file" "$1" + if [ $? -ne 0 ]; then + echo "Connection error (${1})" >&2 + exit 1 + fi + echo "Downloading ${1}" +} + +BackupFile() { + [ -e "$1" ] && cp -f "$1" "${1}.bak.$(date +%s)" +} + +BackupCurrentConfig() { + local _file + MakeDir "$BACKUP_DIR" + for _file in $(ls -1 "$CONFIG_DIR" | grep -v "$(basename $BACKUP_DIR)") + do + cp -af "${CONFIG_DIR}/${_file}" "${BACKUP_DIR}/${_file}" + done + for _file in "$FILE_UCI_CONFIG" "$FILE_TORRC" + do + [ -e "$_file" ] && cp -af "$_file" "${BACKUP_DIR}/$(basename ${_file})" + done +} + +RunAtStartup() { + $FILE_INIT_SCRIPT enable +} + +AppStop() { + FileExists "$FILE_MAIN_SCRIPT" && $FILE_MAIN_SCRIPT destroy +} + +AppStart() { + $FILE_INIT_SCRIPT start +} + +SetCronTask() { + echo "0 3 */3 * * ${FILE_MAIN_SCRIPT} update" >> /etc/crontabs/root + /etc/init.d/cron restart 2> /dev/null + /etc/init.d/cron enable +} + +Reboot() { + reboot +} + +UpdatePackagesList() { + $APK_CMD update +} + +InstallPackages() { + local _pkg + for _pkg in $@ + do + if [ -z "$($APK_CMD list --installed $_pkg)" ]; then + $APK_CMD add --force-overwrite $_pkg + if [ $? -ne 0 ]; then + echo "Error during installation of the package (${_pkg})" >&2 + exit 1 + fi + fi + done +} + +InstallBaseConfig() { + _return_code=1 + InstallPackages "dnsmasq-full" "kmod-nft-tproxy" + RemoveFile "$FILE_RUAB_PKG" > /dev/null + DlFile "$URL_RUAB_PKG" "$FILE_RUAB_PKG" && $APK_CMD add --allow-untrusted "$FILE_RUAB_PKG" > /dev/null + _return_code=$? + AppStop + return $_return_code +} + +EnableBlacklist() { + $UCI_CMD set ruantiblock.config.bllist_preset="ruantiblock-fqdn" + $UCI_CMD commit ruantiblock +} + +InstallVPNConfig() { + local _if_vpn + $UCI_CMD set ruantiblock.config.proxy_mode="2" + $UCI_CMD set ruantiblock.config.if_vpn="tun0" + $UCI_CMD commit ruantiblock +} + +InstallTPConfig() { + local _if_vpn + $UCI_CMD set ruantiblock.config.proxy_mode="3" + $UCI_CMD commit ruantiblock +} + +TorrcSettings() { + local _lan_ip=$($UCI_CMD get network.lan.ipaddr | $AWK_CMD -F "/" '{print $1}') + if [ -z "$_lan_ip" ]; then + _lan_ip="0.0.0.0" + fi + $AWK_CMD -v lan_ip="$_lan_ip" -v TOR_USER="$TOR_USER" '{ + if($0 ~ /^([#]?TransPort|[#]?TransListenAddress|[#]?SOCKSPort)/ && $0 !~ "127.0.0.1") sub(/([0-9]{1,3}.){3}[0-9]{1,3}/, lan_ip, $0); + else if($0 ~ /^User/) $2 = TOR_USER; + print $0; + }' "$FILE_TORRC" > "${FILE_TORRC}.tmp" && mv -f "${FILE_TORRC}.tmp" "$FILE_TORRC" +} + +InstallTorConfig() { + InstallPackages "tor" "tor-geoip" + BackupFile "$FILE_TORRC" + DlFile "$URL_TORRC" "$FILE_TORRC" + TorrcSettings + $UCI_CMD set ruantiblock.config.proxy_mode="1" + $UCI_CMD commit ruantiblock + # dnsmasq rebind protection + if $UCI_CMD get dhcp.@dnsmasq[0].rebind_domain | $AWK_CMD '{for(i=1; i<=NF; i++){if($i == "onion") exit 1}}'; then + $UCI_CMD add_list dhcp.@dnsmasq[0].rebind_domain='onion' + $UCI_CMD commit dhcp + fi +} + +InstallLuaModule() { + InstallPackages "lua" "luasocket" "luasec" "luabitop" + RemoveFile "$FILE_MOD_LUA_PKG" > /dev/null + DlFile "$URL_MOD_LUA_PKG" "$FILE_MOD_LUA_PKG" && $APK_CMD add --allow-untrusted "$FILE_MOD_LUA_PKG" + $UCI_CMD set ruantiblock.config.bllist_module="/usr/libexec/ruantiblock/ruab_parser.lua" + $UCI_CMD commit ruantiblock +} + +InstallLuciApp() { + RemoveFile "$FILE_LUCI_APP_PKG" > /dev/null + RemoveFile "$FILE_LUCI_APP_RU_PKG" > /dev/null + DlFile "$URL_LUCI_APP_PKG" "$FILE_LUCI_APP_PKG" && $APK_CMD add --allow-untrusted "$FILE_LUCI_APP_PKG" && \ + DlFile "$URL_LUCI_APP_RU_PKG" "$FILE_LUCI_APP_RU_PKG" && $APK_CMD add --allow-untrusted "$FILE_LUCI_APP_RU_PKG" + rm -f /tmp/luci-modulecache/* /tmp/luci-indexcache* + /etc/init.d/rpcd restart + /etc/init.d/uhttpd restart +} + +InstallHttpsDnsProxy() { + InstallPackages "https-dns-proxy" "luci-app-https-dns-proxy" "luci-i18n-https-dns-proxy-ru" +} + +PrintBold() { + printf "\033[1m - ${1}\033[0m\n" +} + +InputError () { + printf "\033[1;31m Wrong input! Try again...\033[m\n"; $1 +} + +ConfirmProxyMode() { + local _reply + printf " Select configuration [ 1: Tor | 2: VPN | 3: Transparent proxy ] (default: 1, quit: q) > " + read _reply + case $_reply in + 1|"") + PROXY_MODE=1 + break + ;; + 2) + PROXY_MODE=2 + break + ;; + 3) + PROXY_MODE=3 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmProxyMode + ;; + esac +} + +ConfirmBlacklist() { + local _reply + printf " Select blacklist [ 1: User entries only | 2: Full blacklist ] (default: 1, quit: q) > " + read _reply + case $_reply in + 1|"") + BLACKLIST=1 + break + ;; + 2) + BLACKLIST=2 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmBlacklist + ;; + esac +} + +ConfirmLuaModule() { + local _reply + printf " Would you like to install the lua module? [ y | n ] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + LUA_MODULE=1 + break + ;; + n|N) + LUA_MODULE=0 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmLuaModule + ;; + esac +} + +ConfirmLuciApp() { + local _reply + printf " Would you like to install the LuCI application? [ y | n ] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + LUCI_APP=1 + break + ;; + n|N) + LUCI_APP=0 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmLuciApp + ;; + esac +} + +ConfirmHttpsDnsProxy() { + local _reply + printf " Would you like to install the https-dns-proxy? [ y | n ] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + HTTPS_DNS_PROXY=1 + break + ;; + n|N) + HTTPS_DNS_PROXY=0 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmHttpsDnsProxy + ;; + esac +} + +ConfirmProcessing() { + local _reply + printf " Next, the installation will begin... Continue? [ y | n ] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + break + ;; + n|N|q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmProcessing + ;; + esac +} + +ConfirmProxyMode +ConfirmBlacklist +#ConfirmLuaModule +ConfirmLuciApp +ConfirmHttpsDnsProxy +ConfirmProcessing +AppStop +PrintBold "Updating packages list..." +UpdatePackagesList +PrintBold "Saving current configuration..." +#BackupCurrentConfig +PrintBold "Installing basic configuration..." +InstallBaseConfig +if [ $? -eq 0 ]; then + + if [ $PROXY_MODE = 2 ]; then + PrintBold "Installing VPN configuration..." + InstallVPNConfig + elif [ $PROXY_MODE = 3 ]; then + PrintBold "Installing transparent proxy configuration..." + InstallTPConfig + else + PrintBold "Installing Tor configuration..." + InstallTorConfig + if $(/etc/init.d/tor enabled); then + /etc/init.d/tor restart + fi + fi + + if [ $BLACKLIST = 2 ]; then + PrintBold "Set full blacklist..." + EnableBlacklist + fi + + if [ $LUA_MODULE = 1 ]; then + PrintBold "Installing lua module..." + InstallLuaModule + fi + + if [ $LUCI_APP = 1 ]; then + PrintBold "Installing luci app..." + InstallLuciApp + fi + + if [ $HTTPS_DNS_PROXY = 1 ]; then + PrintBold "Installing https-dns-proxy..." + InstallHttpsDnsProxy + fi + + RunAtStartup + SetCronTask +else + PrintBold "An error occurred while installing the ruantiblock package!" +fi + +exit 0 diff --git a/autoinstall/2.x/apk/uninstall.sh b/autoinstall/2.x/apk/uninstall.sh new file mode 100755 index 0000000..8ae0e0a --- /dev/null +++ b/autoinstall/2.x/apk/uninstall.sh @@ -0,0 +1,158 @@ +#!/bin/sh + +PREFIX="" + +### Local files + +CONFIG_DIR="${PREFIX}/etc/ruantiblock" +USER_LISTS_DIR="${CONFIG_DIR}/user_lists" +EXEC_DIR="${PREFIX}/usr/bin" +BACKUP_DIR="${CONFIG_DIR}/autoinstall.bak.$(date +%s)" +HTDOCS_VIEW="${PREFIX}/www/luci-static/resources/view" +HTDOCS_RUAB="${HTDOCS_VIEW}/ruantiblock" +CRONTAB_FILE="/etc/crontabs/root" +DATA_DIR="/tmp/ruantiblock" +DNSMASQ_DATA_FILE="/tmp/dnsmasq*.d/02-ruantiblock.dnsmasq" +DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp" +DNSMASQ_DATA_FILE_BYPASS="/tmp/dnsmasq*.d/00-ruantiblock_bypass.dnsmasq" +DNSMASQ_DATA_FILE_USER_INSTANCES="/tmp/dnsmasq*.d/01-ruantiblock_user_instances.dnsmasq" +SCRIPTS_DIR="/usr/share/ruantiblock" +MODULES_DIR="/usr/libexec/ruantiblock" +### ruantiblock +FILE_CONFIG="${CONFIG_DIR}/ruantiblock.conf" +FILE_FQDN_FILTER="${CONFIG_DIR}/fqdn_filter" +FILE_IP_FILTER="${CONFIG_DIR}/ip_filter" +FILE_USER_ENTRIES="${CONFIG_DIR}/user_entries" +FILE_BYPASS_ENTRIES="${CONFIG_DIR}/bypass_entries" +FILE_GR_EXCLUDED_SLD="${CONFIG_DIR}/gr_excluded_sld" +FILE_GR_EXCLUDED_NETS="${CONFIG_DIR}/gr_excluded_nets" +FILE_UCI_CONFIG="${PREFIX}/etc/config/ruantiblock" +FILE_INIT_SCRIPT="${PREFIX}/etc/init.d/ruantiblock" +FILE_MAIN_SCRIPT="${EXEC_DIR}/ruantiblock" +### tor +FILE_TORRC="${PREFIX}/etc/tor/torrc" + +AWK_CMD="awk" +APK_CMD="$(which apk)" +if [ $? -ne 0 ]; then + echo " Error! apk doesn't exists" >&2 + exit 1 +fi + +FileExists() { + test -e "$1" +} + +MakeDir() { + [ -d "$1" ] || mkdir -p "$1" + if [ $? -ne 0 ]; then + echo "Error! Can't create directory (${1})" >&2 + exit 1 + fi +} + +RemoveFile() { + if [ -e "$1" ]; then + echo "Removing ${1}" + rm -f "$1" + fi +} + +BackupCurrentConfig() { + local _file + MakeDir "$BACKUP_DIR" + for _file in $(ls -1 "$CONFIG_DIR" | grep -v "$(basename $BACKUP_DIR)") + do + cp -af "${CONFIG_DIR}/${_file}" "${BACKUP_DIR}/${_file}" + done + for _file in "$FILE_UCI_CONFIG" "$FILE_TORRC" + do + [ -e "$_file" ] && cp -af "$_file" "${BACKUP_DIR}/$(basename ${_file})" + done +} + +AppStop() { + FileExists "$FILE_MAIN_SCRIPT" && $FILE_MAIN_SCRIPT destroy +} + +DisableStartup() { + FileExists "$FILE_INIT_SCRIPT" && $FILE_INIT_SCRIPT disable +} + +RemoveCronTask() { + if [ -e "$CRONTAB_FILE" ]; then + $AWK_CMD -v FILE_MAIN_SCRIPT="$FILE_MAIN_SCRIPT" '$0 !~ FILE_MAIN_SCRIPT { + print $0; + }' "$CRONTAB_FILE" > "${CRONTAB_FILE}.tmp" && mv -f "${CRONTAB_FILE}.tmp" "$CRONTAB_FILE" + /etc/init.d/cron restart + fi +} + +RestoreTorConfig() { + [ -e "${FILE_TORRC}.bak" ] && mv -f "${FILE_TORRC}.bak" "$FILE_TORRC" + if [ -x "/etc/init.d/tor" ]; then + if $(/etc/init.d/tor enabled); then + /etc/init.d/tor restart + fi + fi +} + +RemoveAppFiles() { + RestoreTorConfig + $APK_CMD del ruantiblock-mod-py ruantiblock-mod-lua luci-i18n-ruantiblock-ru luci-app-ruantiblock ruantiblock + RemoveFile "$FILE_UCI_CONFIG" + RemoveFile "$FILE_CONFIG" + RemoveFile "$FILE_FQDN_FILTER" + RemoveFile "$FILE_IP_FILTER" + RemoveFile "$FILE_USER_ENTRIES" + RemoveFile "$FILE_BYPASS_ENTRIES" + RemoveFile "$FILE_GR_EXCLUDED_SLD" + RemoveFile "$FILE_GR_EXCLUDED_NETS" + RemoveFile "${FILE_UCI_CONFIG}.opkg" + RemoveFile "${FILE_CONFIG}.opkg" + RemoveFile "${FILE_FQDN_FILTER}.opkg" + RemoveFile "${FILE_IP_FILTER}.opkg" + RemoveFile "${FILE_USER_ENTRIES}.opkg" + RemoveFile "${FILE_BYPASS_ENTRIES}.opkg" + rm -f "$DNSMASQ_DATA_FILE" + rm -f "$DNSMASQ_DATA_FILE_BYPASS" + rm -f "$DNSMASQ_DATA_FILE_USER_INSTANCES" + rm -rf "$DATA_DIR"/* + rm -rf "$USER_LISTS_DIR" + + rmdir "$SCRIPTS_DIR" "$MODULES_DIR" 2> /dev/null + rmdir "$HTDOCS_RUAB" 2> /dev/null + rm -f /tmp/luci-modulecache/* /tmp/luci-indexcache* + /etc/init.d/rpcd restart + /etc/init.d/uhttpd restart +} + +InputError () { + printf "\033[1;31m Wrong input! Try again...\033[m\n"; $1 +} + +ConfirmRemove() { + local _reply + printf " Application will be removed... Continue? [y|n] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + break + ;; + n|N|q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmRemove + ;; + esac +} + +ConfirmRemove +AppStop +BackupCurrentConfig +DisableStartup +RemoveCronTask +RemoveAppFiles + +exit 0 diff --git a/autoinstall/2.x/autoinstall.sh b/autoinstall/2.x/autoinstall.sh index 2eca4f4..7c4079a 100755 --- a/autoinstall/2.x/autoinstall.sh +++ b/autoinstall/2.x/autoinstall.sh @@ -9,7 +9,7 @@ LUA_MODULE=0 LUCI_APP=1 HTTPS_DNS_PROXY=1 -OWRT_VERSION="current" +OWRT_VERSION="24.10" RUAB_VERSION="2.1.10-r1" RUAB_MOD_LUA_VERSION="2.1.10-r1" RUAB_LUCI_APP_VERSION="2.1.10-r2" @@ -218,8 +218,10 @@ InstallTorConfig() { $UCI_CMD set ruantiblock.config.proxy_mode="1" $UCI_CMD commit ruantiblock # dnsmasq rebind protection - $UCI_CMD add_list dhcp.@dnsmasq[0].rebind_domain='onion' - $UCI_CMD commit dhcp + if $UCI_CMD get dhcp.@dnsmasq[0].rebind_domain | $AWK_CMD '{for(i=1; i<=NF; i++){if($i == "onion") exit 1}}'; then + $UCI_CMD add_list dhcp.@dnsmasq[0].rebind_domain='onion' + $UCI_CMD commit dhcp + fi } InstallLuaModule() { diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js index 5486dfa..2539f66 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js @@ -218,6 +218,13 @@ return view.extend({ o.description = _('Reduces RAM consumption during update'); o.rmempty = false; + // ENABLE_TMP_DOWNLOADS + o = s.taboption('general_tab', form.Flag, 'enable_tmp_downloads', + _('Safe blacklist update'), + _('If update fails, the old blacklist configuration will be retained. Temporary files are used, when updating the blacklist (increases memory consumption).')); + o.rmempty = false; + o.default = 0; + // ALLOWED_HOSTS_MODE o = s.taboption('general_tab', form.ListValue, 'allowed_hosts_mode', _('Host filter')); @@ -231,13 +238,6 @@ return view.extend({ _('IP addresses for host filter')); o.datatype = 'ip4addr'; - // ENABLE_TMP_DOWNLOADS - o = s.taboption('general_tab', form.Flag, 'enable_tmp_downloads', - _('Safe blacklist update'), - _('If update fails, the old blacklist configuration will be retained. Temporary files are used, when updating the blacklist (increases memory consumption).')); - o.rmempty = false; - o.default = 0; - // BYPASS_MODE o = s.taboption('general_tab', form.Flag, 'bypass_mode', _('Enable exclusion list'), _('List of hosts that are excluded from block bypass (always available directly)'));