#!/bin/sh ################################################################################################################### # █████╗ ███████╗██╗ ██╗███████╗██╗ ██╗██████╗ ████████╗ ███╗ ███╗███████╗██████╗ ██╗ ██╗███╗ ██╗# #██╔══██╗██╔════╝██║ ██║██╔════╝██║ ██║██╔══██╗╚══██╔══╝ ████╗ ████║██╔════╝██╔══██╗██║ ██║████╗ ██║# #███████║███████╗██║ ██║███████╗██║ █╗ ██║██████╔╝ ██║ █████╗ ██╔████╔██║█████╗ ██████╔╝██║ ██║██╔██╗ ██║# #██╔══██║╚════██║██║ ██║╚════██║██║███╗██║██╔══██╗ ██║ ╚════╝ ██║╚██╔╝██║██╔══╝ ██╔══██╗██║ ██║██║╚██╗██║# #██║ ██║███████║╚██████╔╝███████║╚███╔███╔╝██║ ██║ ██║ ██║ ╚═╝ ██║███████╗██║ ██║███████╗██║██║ ╚████║# #╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═══╝# #██████╗ ███╗ ██╗███████╗ ██████╗██████╗ ██╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗██╗ ██╗# #██╔══██╗████╗ ██║██╔════╝██╔════╝██╔══██╗╚██╗ ██╔╝██╔══██╗╚══██╔══╝ ██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝# #██║ ██║██╔██╗ ██║███████╗██║ ██████╔╝ ╚████╔╝ ██████╔╝ ██║█████╗██████╔╝██████╔╝██║ ██║ ╚███╔╝ ╚████╔╝ # #██║ ██║██║╚██╗██║╚════██║██║ ██╔══██╗ ╚██╔╝ ██╔═══╝ ██║╚════╝██╔═══╝ ██╔══██╗██║ ██║ ██╔██╗ ╚██╔╝ # #██████╔╝██║ ╚████║███████║╚██████╗██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗ ██║ # #╚═════╝ ╚═╝ ╚═══╝╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ # #██╗███╗ ██╗███████╗████████╗ █████╗ ██╗ ██╗ ███████╗██████╗ Original Author: # #██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗██║ ██║ ██╔════╝██╔══██╗ bigeyes0x0 # #██║██╔██╗ ██║███████╗ ██║ ███████║██║ ██║ █████╗ ██████╔╝ Current Maintainer: # #██║██║╚██╗██║╚════██║ ██║ ██╔══██║██║ ██║ ██╔══╝ ██╔══██╗ SomeWhereOverTheRainBow # #██║██║ ╚████║███████║ ██║ ██║ ██║███████╗███████╗███████╗██║ ██║ v2.8.5 # #╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ # ################################################################################################################### export LC_ALL=C export PATH="/sbin:/bin:/usr/sbin:/usr/bin:${PATH}" DI_VERSION="v2.8.5" export DI_VERSION readonly API_FILE="/tmp/DI_GIT_API_$$.json" readonly API_HEADERS="/tmp/DI_GIT_API_$$_headers.out" readonly DNSCRYPT_REPO_URL="https://github.com/DNSCrypt/dnscrypt-proxy" readonly LATEST_URL="https://api.github.com/repos/jedisct1/dnscrypt-proxy/releases/latest" readonly LATEST_RELEASE_URL="${DNSCRYPT_REPO_URL}/releases/latest" readonly RELEASES_ATOM_URL="${DNSCRYPT_REPO_URL}/releases.atom" readonly DNSCRYPT_NIGHTLY_VER="nightly" readonly DNSCRYPT_WAIT_TIMEOUT="60" readonly DNSCRYPT_READY_TIMEOUT="180" readonly BASE_DIR="/jffs" readonly TARG_DIR="${BASE_DIR}/dnscrypt" readonly CONF_FILE="${TARG_DIR}/.config" readonly TOML_FILE="${TARG_DIR}/dnscrypt-proxy.toml" readonly TOML_BAK="${TARG_DIR}/dnscrypt-proxy.toml.bak" readonly TOML_ERR="${TARG_DIR}/dnscrypt-proxy.toml.err" readonly TOML_ORI="${TARG_DIR}/example-dnscrypt-proxy.toml" SCRIPT_LOC="$(readlink -f "$0")" || true readonly SCRIPT_LOC BOLD="$(printf "\033[1m")" || true readonly BOLD NORM="$(printf "\033[0m")" || true readonly NORM INFO="$(printf "%s" "${BOLD} Info: ${NORM}")" || true readonly INFO ERROR="$(printf "%s" "${BOLD} *** Error: ${NORM}")" || true readonly ERROR WARNING="$(printf "%s" "${BOLD} * Warning: ${NORM}")" || true readonly WARNING INPUT="$(printf "%s" "${BOLD} => ${NORM}")" || true readonly INPUT # API and command helpers cleanup_api_files() { rm -f "${API_FILE}" "${API_HEADERS}" } on_installer_exit() { cleanup_api_files # Restore pre-check DNS settings only when exiting without a local dnscrypt installation. if [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; then check_dns_environment 1 fi } di_have_cmd() { which "$1" >/dev/null 2>&1 } # cURL option helpers curl_common_args() { if [ -z "${CURL_COMMON_ARGS_SET:-}" ]; then CURL_COMMON_ARGS="-f -sL" curl_has_option '--retry ' && CURL_COMMON_ARGS="${CURL_COMMON_ARGS} --retry 5" curl_has_option '--connect-timeout' && CURL_COMMON_ARGS="${CURL_COMMON_ARGS} --connect-timeout 25" curl_has_option '--retry-delay' && CURL_COMMON_ARGS="${CURL_COMMON_ARGS} --retry-delay 5" curl_has_option '--max-time' && CURL_COMMON_ARGS="${CURL_COMMON_ARGS} --max-time $((5 * 25))" curl_has_option '--retry-connrefused' && CURL_COMMON_ARGS="${CURL_COMMON_ARGS} --retry-connrefused" CURL_COMMON_ARGS_SET="1" fi PTXT -n "${CURL_COMMON_ARGS}" } curl_has_option() { curl_help | grep -q -e "$1" } curl_help() { if [ -z "${CURL_HELP_CACHE_SET:-}" ]; then CURL_HELP_CACHE="$( curl --help all 2>&1 curl --help 2>&1 )" CURL_HELP_CACHE_SET="1" fi PTXT "${CURL_HELP_CACHE}" } curl_insecure_arg() { if [ -z "${CURL_INSECURE_ARG_SET:-}" ]; then CURL_INSECURE_ARG="" curl_has_option '--insecure' && CURL_INSECURE_ARG=" -k" CURL_INSECURE_ARG_SET="1" fi PTXT -n "${CURL_INSECURE_ARG}" } # HTTP transfer helpers http_get_file() { local URL OUT HEADERS INSECURE CURL_ARGS WGET_ARGS URL="$1" OUT="$2" HEADERS="${3:-}" INSECURE="${4:-}" if di_have_cmd curl; then CURL_ARGS="$(curl_common_args)" [ "${INSECURE}" = "insecure" ] && CURL_ARGS="${CURL_ARGS}$(curl_insecure_arg)" if [ -n "${HEADERS}" ]; then curl -D "${HEADERS}" ${CURL_ARGS} "${URL}" -o "${OUT}" else curl ${CURL_ARGS} "${URL}" -o "${OUT}" fi elif di_have_cmd wget; then WGET_ARGS="$(wget_common_args)" [ "${INSECURE}" = "insecure" ] && WGET_ARGS="${WGET_ARGS}$(wget_insecure_arg)" if [ -n "${HEADERS}" ] && wget_has_option '--server-response'; then wget ${WGET_ARGS} --server-response -q -O "${OUT}" "${URL}" 2>"${HEADERS}" else [ -n "${HEADERS}" ] && : >"${HEADERS}" wget ${WGET_ARGS} -q -O "${OUT}" "${URL}" fi else return 127 fi } http_get_stdout() { local URL INSECURE CURL_ARGS WGET_ARGS URL="$1" INSECURE="${2:-}" if di_have_cmd curl; then CURL_ARGS="$(curl_common_args)" [ "${INSECURE}" = "insecure" ] && CURL_ARGS="${CURL_ARGS}$(curl_insecure_arg)" curl ${CURL_ARGS} "${URL}" elif di_have_cmd wget; then WGET_ARGS="$(wget_common_args)" [ "${INSECURE}" = "insecure" ] && WGET_ARGS="${WGET_ARGS}$(wget_insecure_arg)" wget ${WGET_ARGS} -q -O - "${URL}" else return 127 fi } http_get_effective_url() { local URL CURL_ARGS URL="$1" if di_have_cmd curl; then CURL_ARGS="$(curl_common_args)" curl_has_option '--write-out' || return 1 curl ${CURL_ARGS} -o /dev/null -w '%{url_effective}\n' "${URL}" else return 127 fi } dnscrypt_release_version_is_valid() { case "$1" in "" | *[!A-Za-z0-9._-]*) return 1 ;; esac PTXT "$1" | grep -q '[0-9]' } dnscrypt_release_version_is_stable() { dnscrypt_release_version_is_valid "$1" || return 1 case "$1" in *[A-Za-z]*) return 1 ;; esac } normalize_dnscrypt_release_version() { PTXT "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s#^.*/tag/##; s#[/?#].*$##' } get_dnscrypt_release_version_api() { rm -f "${API_FILE}" "${API_HEADERS}" if http_get_file "${LATEST_URL}" "${API_FILE}" "${API_HEADERS}" && [ -s "${API_FILE}" ]; then normalize_dnscrypt_release_version "$(awk -F'"' '/tag_name/ { print $4; exit }' "${API_FILE}")" else return 1 fi } get_dnscrypt_release_version_redirect() { normalize_dnscrypt_release_version "$(http_get_effective_url "${LATEST_RELEASE_URL}")" } get_dnscrypt_release_version_atom() { local CANDIDATE http_get_stdout "${RELEASES_ATOM_URL}" | sed -n 's#.*\([^<]*\).*#\1#p' | while IFS= read -r CANDIDATE; do CANDIDATE="$(normalize_dnscrypt_release_version "${CANDIDATE}")" if dnscrypt_release_version_is_stable "${CANDIDATE}"; then PTXT "${CANDIDATE}" break fi done } choose_dnscrypt_release_version() { local CANDIDATE SOURCE DNSCRYPT_VER="" DNSCRYPT_VER_SOURCE="" for SOURCE in api redirect atom; do case "${SOURCE}" in api) CANDIDATE="${DNSCRYPT_VER_API}" ;; redirect) CANDIDATE="${DNSCRYPT_VER_REDIRECT}" ;; atom) CANDIDATE="${DNSCRYPT_VER_ATOM}" ;; esac if dnscrypt_release_version_is_valid "${CANDIDATE}"; then DNSCRYPT_VER="${CANDIDATE}" DNSCRYPT_VER_SOURCE="${SOURCE}" break fi done if [ -n "${DNSCRYPT_VER}" ]; then for CANDIDATE in "${DNSCRYPT_VER_API}" "${DNSCRYPT_VER_REDIRECT}" "${DNSCRYPT_VER_ATOM}"; do if dnscrypt_release_version_is_valid "${CANDIDATE}" && [ "${CANDIDATE}" != "${DNSCRYPT_VER}" ]; then PTXT "${WARNING} dnscrypt-proxy release metadata sources disagree; using ${DNSCRYPT_VER} from ${DNSCRYPT_VER_SOURCE}." break fi done fi } collect_dnscrypt_release_metadata() { DNSCRYPT_VER_API="$(get_dnscrypt_release_version_api 2>/dev/null || true)" DNSCRYPT_VER_REDIRECT="" DNSCRYPT_VER_ATOM="" if dnscrypt_release_version_is_valid "${DNSCRYPT_VER_API}"; then choose_dnscrypt_release_version return fi DNSCRYPT_VER_REDIRECT="$(get_dnscrypt_release_version_redirect 2>/dev/null || true)" if dnscrypt_release_version_is_valid "${DNSCRYPT_VER_REDIRECT}"; then choose_dnscrypt_release_version return fi DNSCRYPT_VER_ATOM="$(get_dnscrypt_release_version_atom 2>/dev/null || true)" choose_dnscrypt_release_version } prepare_dnscrypt_download_vars() { DNSCRYPT_NIGHTLY_TAR="dnscrypt-proxy-${DNSCRYPT_ARCH}-${DNSCRYPT_NIGHTLY_VER}.tar.gz" DNSCRYPT_NIGHTLY_PACKAGE_URL="${URL_ARCH}/${DNSCRYPT_NIGHTLY_TAR}" DNSCRYPT_NIGHTLY_MINISIG_URL="${DNSCRYPT_NIGHTLY_PACKAGE_URL}.minisig" DNSCRYPT_RELEASE_TAR="" DNSCRYPT_RELEASE_PACKAGE_URL="" if [ -n "${DNSCRYPT_VER}" ]; then DNSCRYPT_RELEASE_TAR="dnscrypt-proxy-${DNSCRYPT_ARCH}-${DNSCRYPT_VER}.tar.gz" DNSCRYPT_RELEASE_PACKAGE_URL="${DNSCRYPT_REPO_URL}/releases/download/${DNSCRYPT_VER}/${DNSCRYPT_RELEASE_TAR}" fi } http_probe() { local URL CURL_ARGS WGET_ARGS maxwait URL="$1" maxwait="${2:-}" if di_have_cmd curl; then CURL_ARGS="$(curl_common_args)" if [ -n "${maxwait}" ]; then curl_has_option '--retry ' && CURL_ARGS="${CURL_ARGS} --retry 0" curl_has_option '--connect-timeout' && CURL_ARGS="${CURL_ARGS} --connect-timeout ${maxwait}" curl_has_option '--max-time' && CURL_ARGS="${CURL_ARGS} --max-time ${maxwait}" fi curl ${CURL_ARGS} -I -o /dev/null "${URL}" elif di_have_cmd wget; then WGET_ARGS="$(wget_common_args)" if [ -n "${maxwait}" ]; then wget_has_option '--tries' && WGET_ARGS="${WGET_ARGS} --tries=1" wget_has_option '--timeout' && WGET_ARGS="${WGET_ARGS} --timeout=${maxwait}" fi if wget_has_option '--spider'; then wget ${WGET_ARGS} -q --spider "${URL}" else wget ${WGET_ARGS} -q -O /dev/null "${URL}" fi else return 127 fi } # wget option helpers wget_common_args() { if [ -z "${WGET_COMMON_ARGS_SET:-}" ]; then WGET_COMMON_ARGS="" wget_has_option '--no-cache' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --no-cache" wget_has_option '--no-cookies' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --no-cookies" wget_has_option '--tries' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --tries=5" wget_has_option '--timeout' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --timeout=25" wget_has_option '--waitretry' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --waitretry=5" wget_has_option '--retry-connrefused' && WGET_COMMON_ARGS="${WGET_COMMON_ARGS} --retry-connrefused" WGET_COMMON_ARGS_SET="1" fi PTXT -n "${WGET_COMMON_ARGS}" } wget_has_option() { wget_help | grep -q -e "$1" } wget_help() { if [ -z "${WGET_HELP_CACHE_SET:-}" ]; then WGET_HELP_CACHE="$(wget --help 2>&1)" WGET_HELP_CACHE_SET="1" fi PTXT "${WGET_HELP_CACHE}" } wget_insecure_arg() { if [ -z "${WGET_INSECURE_ARG_SET:-}" ]; then WGET_INSECURE_ARG="" wget_has_option '--no-check-certificate' && WGET_INSECURE_ARG=" --no-check-certificate" WGET_INSECURE_ARG_SET="1" fi PTXT -n "${WGET_INSECURE_ARG}" } # Output helpers _quote() { PTXT "$1" | sed 's/[]\/()$*.^|[]/\\&/g' } PTXT() { case "$1" in -n) shift while [ $# -gt 0 ]; do printf "%s" "$1" shift done ;; *) while [ $# -gt 0 ]; do printf "%s\n" "$1" shift done ;; esac } # Configuration and file helpers backup_restore() { if [ "$1" = "BACKUP" ] && [ -d "${TARG_DIR}" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ]; then if [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then PTXT "${INFO} There is an old backup detected." local USE_OLD if read_yesno "Do you want to continue?(this will remove the old backup)"; then USE_OLD="NO"; else USE_OLD="YES"; fi if [ "${USE_OLD}" = "YES" ]; then PTXT "${INFO} Leaving Old Backup." end_op_message 1 elif [ "${USE_OLD}" = "NO" ]; then PTXT "${INFO} Removing Old Backup." rm -rf "${BASE_DIR}/backup_dnscrypt.tar.gz" fi fi PTXT "${INFO} This operation will backup dnscrypt-proxy(<4MB)to jffs partition." \ "${INFO} Please wait a moment." tar -czvf "${BASE_DIR}/backup_dnscrypt.tar.gz" -C "${TARG_DIR}" ../dnscrypt/ >/dev/null 2>&1 PTXT "${INFO} Backup complete" [ -z "$2" ] && end_op_message 0 elif [ "$1" = "BACKUP" ] && [ ! -d "${TARG_DIR}" ] && [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; then PTXT "${ERROR} No ${TARG_DIR}/dnscrypt-proxy to Backup!" end_op_message 1 fi if [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ] && [ "$1" = "RESTORE" ]; then PTXT "${INFO} Please wait a moment." tar -xzvf "${BASE_DIR}/backup_dnscrypt.tar.gz" -C "${BASE_DIR}" >/dev/null 2>&1 chown "$(nvram get http_username)":root ${TARG_DIR}/* chmod 755 "${TARG_DIR}/dnscrypt-proxy" inst_dnscrypt "${1:-RESTORE}" elif [ ! -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ] && [ "$1" = "RESTORE" ]; then PTXT "${ERROR} No Backup found!" \ "${ERROR} Please make sure Backup Resides in $BASE_DIR" end_op_message 1 return fi } branch_is_safe() { case "$1" in "" | /* | */ | *..* | *//* | *\* | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._/-]*) return 1 ;; esac return 0 } cleanup() { rm -rf "${TARG_DIR}/dnscrypt-fw-rules" "${TARG_DIR}/dnscrypt-start" "${TARG_DIR}/dnsmasq-dnscrypt-reconfig" "${TARG_DIR}/fake-hwclock*" "${TARG_DIR}/init-start" "${TARG_DIR}/services-stop" del_jffs_script /jffs/scripts/wan-start dnscrypt-start del_jffs_script /jffs/scripts/openvpn-event del_jffs_script /jffs/scripts/firewall-start del_jffs_script /jffs/scripts/wan-start } create_dir() { if ! mkdir -p "${1}"; then PTXT "${ERROR} Unable to create ${1}!" return 1 fi } del_between_magic() { local TARG MAGIC BOUNDS TARG="$1" MAGIC="$2" [ -f "${TARG}" ] || return BOUNDS="$(awk -v PATT="${MAGIC}" '($0 ~ PATT) {printf NR","}' "${TARG}")" if [ "${BOUNDS}" ]; then sed -i "${BOUNDS%,}d" "${TARG}" fi } del_conf() { [ ! -f "${CONF_FILE}" ] && return local KEY for KEY in "$@"; do sed -i "/^${KEY}=.*$/d" "${CONF_FILE}" done } del_jffs_script() { local TARG LINE_NUM LINE_ABOVE OP TARG="$1" [ -f "${TARG}" ] || return if [ "${2:-}" ]; then OP="$(printf '%.1s' "$2")" if [ "${OP}" = "!" ]; then LINE_NUM="$(grep -n -F "[ -x ${TARG_DIR}/" "${TARG}" | grep -v "$(_quote "$2")" | cut -d':' -f1)" else LINE_NUM="$(grep -n -F "[ -x ${TARG_DIR}/" "${TARG}" | grep "$(_quote "$2")" | cut -d':' -f1)" fi else LINE_NUM="$(grep -n -F "[ -x ${TARG_DIR}/" "${TARG}" | cut -d':' -f1)" fi [ -z "${LINE_NUM}" ] && return printf "%s\n" "${LINE_NUM}" | sort -rn | while IFS= read -r LINE_NUM; do [ -z "${LINE_NUM}" ] && continue sed -i "${LINE_NUM}d" "${TARG}" if [ "${LINE_NUM}" -gt 1 ]; then LINE_NUM="$((LINE_NUM - 1))" LINE_ABOVE="$(sed "${LINE_NUM}q;d" "${TARG}")" [ -z "${LINE_ABOVE}" ] && sed -i "${LINE_NUM}d" "${TARG}" fi done [ "$(awk '{ print }' "${TARG}")" = "#!/bin/sh" ] && rm -f "${TARG}" } download_file() { local TARG PERM URL RET FILENAME TMP_FILE TMP_MD5_FILE MD5SUM_OLD MD5SUM_CURR MD5SUM_EXPECTED COUNT TARG="$1" shift PERM="$1" shift RET="0" for URL in "$@"; do FILENAME="$(basename "${URL}")" TMP_FILE="${TARG}/.${FILENAME}.$$" TMP_MD5_FILE="${TMP_FILE}.md5sum" MD5SUM_OLD="" MD5SUM_CURR="" MD5SUM_EXPECTED="" COUNT="0" [ -f "${TARG}/${FILENAME}" ] && MD5SUM_OLD="$(md5sum "${TARG}/${FILENAME}" | awk '{print $1; exit}')" while [ "${COUNT}" -lt 3 ]; do PTXT "${INFO} Downloading ${FILENAME}" rm -f "${TMP_FILE}" "${TMP_MD5_FILE}" MD5SUM_EXPECTED="" if http_get_file "${URL}" "${TMP_FILE}" "" insecure && [ -s "${TMP_FILE}" ]; then if http_get_file "${URL}.md5sum" "${TMP_MD5_FILE}" "" insecure && [ -s "${TMP_MD5_FILE}" ]; then MD5SUM_EXPECTED="$(awk '{print $1; exit}' "${TMP_MD5_FILE}")" fi MD5SUM_CURR="$(md5sum "${TMP_FILE}" | awk '{print $1; exit}')" if md5_is_valid "${MD5SUM_EXPECTED}" && [ "${MD5SUM_EXPECTED}" != "${MD5SUM_CURR}" ]; then PTXT "${WARNING} ${FILENAME} checksum mismatch. Retrying..." COUNT="$((COUNT + 1))" continue fi break fi COUNT="$((COUNT + 1))" done if [ "${COUNT}" -eq 3 ]; then rm -f "${TMP_FILE}" "${TMP_MD5_FILE}" PTXT "${ERROR} Unable to download ${BOLD}${URL}${NORM}" RET="$((RET + 1))" continue fi if md5_is_valid "${MD5SUM_CURR}" && [ "${MD5SUM_CURR}" = "${MD5SUM_OLD}" ]; then rm -f "${TMP_FILE}" "${TMP_MD5_FILE}" PTXT "${INFO} ${FILENAME} is up to date. Skipping..." continue fi rm -f "${TMP_MD5_FILE}" if mv "${TMP_FILE}" "${TARG}/${FILENAME}" && chmod "${PERM}" "${TARG}/${FILENAME}"; then continue fi rm -f "${TMP_FILE}" "${TMP_MD5_FILE}" PTXT "${ERROR} Unable to install ${BOLD}${FILENAME}${NORM}" RET="$((RET + 1))" done if [ "${RET}" -ne 0 ]; then PTXT "${ERROR} One or more download failures has occurred." "${ERROR} It is recommended to rerun the installer, or restore from a backup!" fi return "${RET}" } installer_update_reexec() { local ACTION NEW_MD5 OLD_MD5 ACTION="$1" OLD_MD5="$2" [ "${ACTION}" = "update" ] || return 0 [ "${DI_REEXECED_INSTALLER:-0}" = "1" ] && return 0 [ -n "${OLD_MD5}" ] || return 0 [ -f "${TARG_DIR}/installer" ] || return 0 NEW_MD5="$(md5sum "${TARG_DIR}/installer" 2>/dev/null | awk '{print $1; exit}')" [ -n "${NEW_MD5}" ] || return 0 [ "${OLD_MD5}" != "${NEW_MD5}" ] || return 0 PTXT "${INFO} Installer was updated; restarting the update with the new installer." chmod 755 "${TARG_DIR}/installer" >/dev/null 2>&1 DI_REEXECED_INSTALLER="1" export DI_REEXECED_INSTALLER exec "${TARG_DIR}/installer" "${BRANCH}" "${ACTION}" } md5_is_valid() { [ "$(PTXT -n "$1" | wc -c)" -eq 32 ] || return 1 case "$1" in *[!0123456789abcdefABCDEF]*) return 1 ;; esac return 0 } read_conf() { [ -f "${CONF_FILE}" ] || return 1 awk -v KEY="$1" ' index($0, KEY "=") == 1 { VALUE = substr($0, length(KEY) + 2) gsub(/^"|"$/, "", VALUE) print VALUE exit } ' "${CONF_FILE}" } sanitize_branch() { local CANDIDATE CANDIDATE="$1" if branch_is_safe "${CANDIDATE}"; then PTXT "${CANDIDATE}" else PTXT "${WARNING} Ignoring unsafe installer branch ${CANDIDATE}, using master instead." >&2 PTXT "master" fi } write_command_script() { local TARG COMMAND FILENAME TARG="$1" COMMAND="$2" FILENAME="$(basename "${TARG}")" if [ ! -f "${TARG}" ]; then PTXT "${INFO} Creating ${FILENAME} file" PTXT "#!/bin/sh" >"${TARG}" fi chmod 755 "${TARG}" if [ "$(grep -c -F "${COMMAND}" "${TARG}")" -gt 0 ]; then PTXT "${INFO} ${FILENAME} file already configured" else PTXT "${INFO} Configure ${FILENAME} file" PTXT "${COMMAND}" >>"${TARG}" fi } write_conf() { local VAR VALUE VAR="$1" VALUE="$2" if [ -f "${TARG_DIR}/.opendns-auth" ]; then mv "${TARG_DIR}/.opendns-auth" "${CONF_FILE}" chmod 644 "${CONF_FILE}" fi if [ ! -f "${CONF_FILE}" ]; then if ! { touch "${CONF_FILE}" && chmod 644 "${CONF_FILE}"; }; then PTXT "${ERROR} Unable to create ${CONF_FILE}" return 1 fi fi if grep -q "^${VAR}=" "${CONF_FILE}"; then VALUE=$(_quote "${VALUE}") sed -i "/^${VAR}=/s/=.*/=${VALUE}/" "${CONF_FILE}" else PTXT "${VAR}=${VALUE}" >>"${CONF_FILE}" fi } write_manager_script() { local TARG OP FILENAME COMMAND TARG="$1" OP="$2" FILENAME="$(basename "${TARG}")" COMMAND="${TARG_DIR}/manager" if [ ! -f "${TARG}" ]; then PTXT "${INFO} Creating ${FILENAME} file" PTXT "#!/bin/sh" >"${TARG}" fi chmod 755 "${TARG}" "${COMMAND}" del_between_magic "${TARG}" dnscrypt-asuswrt-installer if [ "$(grep -c -F "[ -x ${COMMAND} ] && ${COMMAND} ${OP}" "${TARG}")" -gt 0 ]; then PTXT "${INFO} ${FILENAME} file already configured" else PTXT "${INFO} Configure ${FILENAME} file" if grep -q "^${COMMAND}" "${TARG}"; then sed -i "s~^${COMMAND}~[ -x ${COMMAND} ] \&\& ${COMMAND} ${OP}~" "${TARG}" else del_jffs_script "${TARG}" !manager [ "$(tail -1 "${TARG}" | grep -c '^$')" -eq 0 ] && PTXT "" >>"${TARG}" PTXT "[ -x ${COMMAND} ] && ${COMMAND} ${OP}" >>"${TARG}" fi fi } # DNSCrypt lifecycle helpers dnscrypt_complete_startup() { PTXT "${INFO} Starting dnscrypt-proxy..." dnscrypt_stop if ! dnscrypt_start; then dnscrypt_start_error return 1 fi PTXT "${INFO} Please wait while we perform one last check." if ! dnscrypt_restart; then dnscrypt_start_error return 1 fi PTXT "${INFO} dnscrypt-proxy setup is complete." return 0 } dnscrypt_is_running() { [ -n "$(pidof dnscrypt-proxy)" ] } dnscrypt_monitor_count() { local count pid count="0" for pid in $(pidof manager 2>/dev/null); do if awk '{ print }' "/proc/${pid}/cmdline" 2>/dev/null | grep -q 'monitor-start'; then count="$((count + 1))" fi done PTXT "${count}" } dnscrypt_prepare_binary_replace() { if { [ -f "${TARG_DIR}/dnscrypt-proxy" ] || [ -e "${TARG_DIR}/dnscrypt-proxy" ]; } && [ "$(dnscrypt_process_count)" -ge "1" ]; then PTXT "${INFO} Stopping Dnscrypt-Proxy before replacing the binary." if ! dnscrypt_stop; then PTXT "${ERROR} Unable to safely stop Dnscrypt-Proxy before replacing the binary." return 1 fi fi return 0 } dnscrypt_process_count() { local daemon_count monitor_count daemon_count="$(pidof dnscrypt-proxy 2>/dev/null | wc -w)" monitor_count="$(dnscrypt_monitor_count)" PTXT "$((daemon_count + monitor_count))" } dnscrypt_restart() { if dnscrypt_is_running; then if service restart_dnscrypt-proxy >/dev/null 2>&1; then sleep 1s elif [ -x "${TARG_DIR}/manager" ] && "${TARG_DIR}/manager" restart x >/dev/null 2>&1; then sleep 1s else return 1 fi else dnscrypt_start || return 1 fi sleep 1s dnscrypt_wait_ready "${DNSCRYPT_READY_TIMEOUT}" || return 1 dnscrypt_is_running } dnscrypt_start() { if ! dnscrypt_is_running; then if service start_dnscrypt-proxy >/dev/null 2>&1; then sleep 1s elif [ -x "${TARG_DIR}/manager" ] && "${TARG_DIR}/manager" start x >/dev/null 2>&1; then sleep 1s else return 1 fi fi sleep 1s dnscrypt_wait_started "${DNSCRYPT_WAIT_TIMEOUT}" || return 1 dnscrypt_is_running } dnscrypt_start_error() { PTXT "${ERROR} Couldn't start dnscrypt-proxy" \ "${ERROR} Please send WebUI System Log to dev" } dnscrypt_stop() { if [ "$(dnscrypt_process_count)" -ge "1" ]; then if service stop_dnscrypt-proxy >/dev/null 2>&1; then sleep 1s elif [ -x "${TARG_DIR}/manager" ] && "${TARG_DIR}/manager" stop x >/dev/null 2>&1; then sleep 1s else kill_processes dnscrypt-proxy manager sleep 1s fi fi sleep 1s dnscrypt_wait_stopped "${DNSCRYPT_WAIT_TIMEOUT}" || return 1 } dnscrypt_wait_ready() { local elapsed maxwait now remaining start maxwait="${1:-${DNSCRYPT_READY_TIMEOUT}}" start="$(monotonic_seconds)" || return 1 while :; do now="$(monotonic_seconds)" || return 1 elapsed="$((now - start))" if [ "${elapsed}" -ge "${maxwait}" ]; then return 1; fi remaining="$((maxwait - elapsed))" if check_connection "${remaining}" && dnscrypt_is_running; then return 0; fi now="$(monotonic_seconds)" || return 1 elapsed="$((now - start))" if [ "${elapsed}" -ge "${maxwait}" ]; then return 1; fi sleep 1s done } dnscrypt_wait_started() { local elapsed maxwait elapsed="0" maxwait="${1:-${DNSCRYPT_WAIT_TIMEOUT}}" while ! dnscrypt_is_running; do if [ "${elapsed}" -ge "${maxwait}" ]; then return 1; fi sleep 1s elapsed="$((elapsed + 1))" done return 0 } dnscrypt_wait_stopped() { local elapsed maxwait elapsed="0" maxwait="${1:-${DNSCRYPT_WAIT_TIMEOUT}}" while [ "$(dnscrypt_process_count)" -ge "1" ]; do if [ "${elapsed}" -ge "${maxwait}" ]; then return 1; fi sleep 1s elapsed="$((elapsed + 1))" done return 0 } # Environment and validation checks check_anonymized_automatic() { if [ "$1" -eq 0 ] && grep -q '^server_names = .*Static.*' "${TOML_FILE}"; then PTXT "${INFO} Custom servers that are potentially not compatible with relays are detected!" \ "${WARNING} These servers might not work with relays." \ "${WARNING} Use at your own risk." fi local USE_BROKEN USE_WILDCARD PTXT "${INFO} This allows for the use of server_name='*' as wildcard option for all servers compatible with relays." \ "${INFO} This will be the default route for all compatible servers." \ "${INFO} Additionally routes can be distinctly selected by using via=['*'] as relay wildcard." if read_yesno "Do you want to use wildcard relay (via=['*']) option?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_automatic_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_automatic fi if read_yesno "Do you want to skip using resolvers that are incompatible with anonymization instead of using them directly?"; then USE_BROKEN="true"; else USE_BROKEN="false"; fi toml_avars_prep skip_incompatible "${USE_BROKEN}" } check_anonymized_disabled() { toml_avar_disable routes toml_avars_prep skip_incompatible false PTXT "${INFO} Continue without Relays Support" } ########################Modified Version of @Adamm Check_Connection#################################################### check_connection() { local deadline i livecheck="0" maxwait now remaining sleep_for maxwait="${1:-}" if [ -n "${maxwait}" ]; then now="$(monotonic_seconds)" || return 1 deadline="$((now + maxwait))" fi while [ "${livecheck}" != "4" ]; do for i in google.com github.com snbforums.com; do if [ -n "${deadline}" ]; then now="$(monotonic_seconds)" || return 1 [ "${now}" -ge "${deadline}" ] && return 1 fi if { ! nslookup "${i}" 127.0.0.1 >/dev/null 2>&1; } && { ping -q -w3 -c1 "${i}" >/dev/null 2>&1; }; then remaining="" if [ -n "${deadline}" ]; then now="$(monotonic_seconds)" || return 1 remaining="$((deadline - now))" [ "${remaining}" -le 0 ] && return 1 fi if ! http_probe "http://${i}" "${remaining}" >/dev/null 2>&1; then if [ -n "${deadline}" ]; then now="$(monotonic_seconds)" || return 1 [ "${now}" -ge "${deadline}" ] && return 1 fi sleep 1s continue fi fi return 0 done livecheck="$((livecheck + 1))" if [ "${livecheck}" != "4" ]; then if [ -n "${deadline}" ]; then now="$(monotonic_seconds)" || return 1 sleep_for="$((deadline - now))" [ "${sleep_for}" -le 0 ] && return 1 [ "${sleep_for}" -gt 10 ] && sleep_for="10" sleep "${sleep_for}s" else sleep 10s fi continue fi return 1 done } ####################################################################################################################### check_dns_environment() { if [ -f "/opt/etc/init.d/S61stubby" ] || [ -f "/opt/sbin/stubby" ] || [ -f "/opt/bin/install_stubby" ] || [ -f "/jffs/scripts/install_stubby.sh" ] || [ -d "/jffs/addons/AdGuardHome.d" ]; then PTXT "${ERROR} Potential stubby or adguardhome installation detected." \ "${ERROR} Please remove before attempting to continue." \ "${ERROR} Exiting..." exit 1 fi local MODE NVCHECK dns_env_set_nvram() { local key expected cur changed key="$1" expected="$2" cur="$(nvram get "${key}" 2>/dev/null)" if [ "${cur}" = "${expected}" ]; then return 1 fi nvram set "${key}=${expected}" changed="1" return 0 } dns_env_apply_profile() { local changed changed="0" if dns_env_set_nvram "dnspriv_enable" "0"; then changed="$((changed + 1))"; fi if dns_env_set_nvram "dhcpd_dns_router" "1"; then changed="$((changed + 1))"; fi if dns_env_set_nvram "dhcp_dns1_x" ""; then changed="$((changed + 1))"; fi if dns_env_set_nvram "dhcp_dns2_x" ""; then changed="$((changed + 1))"; fi if [ "${changed}" != "0" ]; then return 0; else return 1; fi } dns_env_restore_profile() { local changed key cur old changed="0" for key in dnspriv_enable dhcpd_dns_router dhcp_dns1_x dhcp_dns2_x; do cur="$(nvram get "${key}" 2>/dev/null)" case "${key}" in dnspriv_enable) old="${_OLD_dnspriv_enable}" ;; dhcpd_dns_router) old="${_OLD_dhcpd_dns_router}" ;; dhcp_dns1_x) old="${_OLD_dhcp_dns1_x}" ;; dhcp_dns2_x) old="${_OLD_dhcp_dns2_x}" ;; esac if [ "${cur}" != "${old}" ]; then nvram set "${key}=${old}" changed="$((changed + 1))" fi done if [ "${changed}" != "0" ]; then return 0; else return 1; fi } MODE="$1" NVCHECK="0" case "${MODE}" in 0) # Save original values only once. if [ "${_DNS_NVRAM_SAVED:-0}" != "1" ]; then save_dns_nvram_environment fi if [ "$(pidof stubby)" ]; then { kill_processes stubby; } NVCHECK="$((NVCHECK + 1))" fi if dns_env_apply_profile; then NVCHECK="$((NVCHECK + 1))"; fi ;; 1) # Do not restore if we never saved anything. if [ "${_DNS_NVRAM_SAVED:-0}" != "1" ]; then return 0 fi if dns_env_restore_profile; then NVCHECK="$((NVCHECK + 1))"; fi ;; *) return 1 ;; esac if [ "${NVCHECK}" != "0" ]; then { nvram commit; } { service restart_dnsmasq >/dev/null 2>&1; } (while { ! check_connection; }; do sleep 1s; done) & local PID="$!" wait "${PID}" 2>/dev/null fi PTXT "${INFO} DNS Environment is Ready." return 0 } check_dns_filter() { local NVCHECK USE_SOME NVCHECK="0" if [ "$1" -eq 0 ]; then if [ "$(nvram get dnsfilter_enable_x 2>/dev/null)" -ne 0 ]; then { nvram set dnsfilter_enable_x="0"; } NVCHECK="$((NVCHECK + 1))" fi PTXT "${INFO} DNS will not be forced through to Dnscrypt-Proxy." fi if [ "$1" -eq 1 ]; then if [ "$(nvram get dnsfilter_enable_x 2>/dev/null)" -ne 1 ]; then { nvram set dnsfilter_enable_x="1"; } NVCHECK="$((NVCHECK + 1))" fi PTXT "${INFO} You can choose to keep any custom dnsfilter values by only redirect non-custom traffic or send all traffic through to Dnscrypt-Proxy." if read_yesno "Do you want to redirect only NON-CUSTOM DNS resolutions on your network through to Dnscrypt-Proxy?"; then USE_SOME="0"; else USE_SOME="1"; fi if [ "${USE_SOME}" -eq 0 ]; then if [ "$(nvram get dnsfilter_mode 2>/dev/null)" != "11" ]; then { nvram set dnsfilter_mode="11"; } NVCHECK="$((NVCHECK + 1))" fi PTXT "${INFO} DNSFilter is set to control DNS through to Dnscrypt-Proxy, while leaving any Custom Rules and Values." fi if [ "$USE_SOME" -eq 1 ]; then for i in dnsfilter_mode dhcpd_dns_router dnsfilter_custom1 dnsfilter_custom2 dnsfilter_custom3 dnsfilter_rulelist dnsfilter_rulelist1 dnsfilter_rulelist2 dnsfilter_rulelist3 dnsfilter_rulelist4 dnsfilter_rulelist5 dhcp_dns1_x dhcp_dns2_x; do VAR="$(nvram get "${i}" 2>/dev/null)" if [ "${i}" = "dnsfilter_mode" ]; then if [ "$VAR" != "11" ]; then { nvram set "${i}"="11" }; else continue; fi elif [ "${i}" = "dhcpd_dns_router" ]; then if [ "$VAR" != "1" ]; then { nvram set "${i}"="1" }; else continue; fi elif [ "$VAR" ]; then { nvram set "${i}"="" }; else continue; fi NVCHECK="$((NVCHECK + 1))" done PTXT "${INFO} DNS is set to redirect All DNS resolutions through to Dnscrypt-Proxy." fi fi if [ "${NVCHECK}" != "0" ]; then { nvram commit; } { service "restart_firewall;restart_dnsmasq" >/dev/null 2>&1; } (while { ! check_connection; }; do sleep 1s; done) & local PID="$!" wait "${PID}" 2>/dev/null fi } check_dns_local() { local LOCAL_CACHE case "$1" in 0) LOCAL_CACHE="NO" write_conf DNSCRYPT_LOCAL "\"${LOCAL_CACHE}\"" ;; 1) LOCAL_CACHE="YES" write_conf DNSCRYPT_LOCAL "\"${LOCAL_CACHE}\"" ;; esac } check_dnscrypt_toml() { [ ! -f "${TOML_FILE}" ] && return PTXT "${INFO} Checking dnscrypt-proxy configuration..." if ! ${TARG_DIR}/dnscrypt-proxy -check -config "${TOML_FILE}"; then PTXT "${INFO} Move invalid configuration file to ${TOML_ERR}" \ "${INFO} Operation will continue with clean config file." mv "${TOML_FILE}" "${TOML_ERR}" return 1 fi } check_jffs_enabled() { if [ "$(nvram get jffs2_format 2>/dev/null)" = "1" ]; then PTXT "${ERROR} JFFS partition is scheduled to be reformatted." \ "${ERROR} Please reboot to format or disable that setting and try again." \ "${ERROR} Exiting..." exit 1 fi local JFFS2_SCRIPTS JFFS2_ENABLED jffs2_on JFFS2_SCRIPTS="$(nvram get jffs2_scripts 2>/dev/null)" if [ -z "$(nvram get jffs2_enable 2>/dev/null)" ]; then JFFS2_ENABLED="$(nvram get jffs2_on 2>/dev/null)"; else JFFS2_ENABLED="$(nvram get jffs2_enable 2>/dev/null)"; fi if [ -z "$(nvram get jffs2_enable 2>/dev/null)" ]; then jffs2_on="jffs2_on"; else jffs2_on="jffs2_enable"; fi if [ "${JFFS2_ENABLED}" -ne 1 ] || [ "${JFFS2_SCRIPTS}" -ne 1 ]; then PTXT "${INFO} JFFS custom scripts and configs are not enabled." \ "${INFO} Enabling them now!" nvram set "${jffs2_on}"=1 nvram set jffs2_scripts=1 nvram commit else PTXT "${INFO} JFFS custom scripts and configs are already enabled." fi } check_opendns() { if grep -q '^server_names = .*cisco.*' "${TOML_FILE}"; then if [ -f "${CONF_FILE}" ]; then local OPENDNS_USER OPENDNS_PASSWORD OPENDNS_USER="$(read_conf OPENDNS_USER)" OPENDNS_PASSWORD="$(read_conf OPENDNS_PASSWORD)" if [ "${OPENDNS_USER}" ] && [ "${OPENDNS_PASSWORD}" ]; then PTXT "${INFO} Found OpenDNS account ${BOLD}${OPENDNS_USER}" \ "${INFO} What do you want to do:" \ " 1) Use this account" \ " 2) Setup new account" \ " 3) Disable OpenDNS account authen" read_input_num "Your choice" 1 3 case "${CHOSEN}" in 1) PTXT "${INFO} Use previous account ${BOLD}${OPENDNS_USER}${NORM}" ;; 2) opendns_authen 1 ;; 3) opendns_authen 0 ;; esac else if read_yesno "Do you want to set up OpenDNS account ip update?"; then opendns_authen 1; else opendns_authen 0; fi fi else if read_yesno "Do you want to set up OpenDNS account ip update?"; then opendns_authen 1; else opendns_authen 0; fi fi else opendns_authen 0 fi } check_relays() { local DNSCRYPT_ARGS DNSCRYPT ODOH_ARGS ODOH FRAGSBLOCKED_ARGS FRAGSBLOCKED VARSARGS SERVER COUNT NUMFRAG NUMCRYPT CRYPT FRAGSBLOCKED_ARGS="$(grep '^fragments_blocked =' "${TOML_ORI}" | cut -d'[' -f2- | sed "s/['\"\,]//g;s/]//g;s/^ [ t]*//;s/[ \t]*$//;s/ /|/g")" NUMCRYPT="0" while read -r CRYPT; do CRYPT="$(PTXT "${CRYPT}" | cut -d',' -f1)" if [ "${NUMCRYPT}" -eq 0 ]; then NUMCRYPT="1" continue fi if [ "${NUMCRYPT}" -eq 1 ]; then if ! PTXT "${FRAGSBLOCKED_ARGS}" | grep -qoF "${CRYPT}"; then DNSCRYPT_ARGS="${CRYPT}"; fi elif [ "${NUMCRYPT}" -gt 1 ]; then if ! PTXT "${FRAGSBLOCKED_ARGS}" | grep -qoF "${CRYPT}"; then DNSCRYPT_ARGS="${DNSCRYPT_ARGS}|${CRYPT}"; fi fi NUMCRYPT="$((NUMCRYPT + 1))" done <${TARG_DIR}/dnscrypt-resolvers.csv ODOH_ARGS="$(awk -v PATT="odohrelay" '/^## / && ($0 !~ PATT) {printf "";printf ""$2"";getline;print}' "${TARG_DIR}/odoh-servers.md" | tr '\n' ' ' | sed 's/[ \t]*$//' | sed 's/ /|/g')" if [ -n "${STAT_CRYPT}" ]; then DNSCRYPT_ARGS="${DNSCRYPT_ARGS}|${STAT_CRYPT}" fi if [ -n "${STAT_ODOH}" ]; then ODOH_ARGS="${ODOH_ARGS}|${STAT_ODOH}" fi VARSARGS="${DNSCRYPT_ARGS}|${ODOH_ARGS}|${FRAGSBLOCKED_ARGS}" COUNT="0" NUMFRAG="0" [ "${NUMFRAG}" -eq 0 ] && toml_avars_prep skip_incompatible false for SERVER in ${VARSARGS//|/ }; do if [ "$(grep '^server_names = .*'"${SERVER}"'.*' "${TOML_FILE}" | grep -cF "'${SERVER}'")" -ne 0 ]; then if PTXT "${DNSCRYPT_ARGS}" | grep -qoF "${SERVER}"; then DNSCRYPT="${SERVER}"; fi if PTXT "${ODOH_ARGS}" | grep -qoF "${SERVER}"; then ODOH="${SERVER}"; fi if PTXT "${FRAGSBLOCKED_ARGS}" | grep -qoF "${SERVER}"; then FRAGSBLOCKED="${SERVER}"; fi case "${SERVER}" in "${DNSCRYPT}") if read_yesno "Do you want to add relays for ${SERVER}?"; then ADD_RELAYS="YES"; else ADD_RELAYS="NO"; fi if [ "${ADD_RELAYS}" = "YES" ]; then PTXT "${INFO} You may manually choose relays for ${SERVER} or you may specify wildcard relay (via=['*'])."; fi if [ "${COUNT}" -eq 0 ] && [ "${ADD_RELAYS}" = "YES" ]; then toml_avar_enable routes if read_yesno "Do you want to use wildcard relay (via=['*']) option for ${SERVER}?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_manual_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_manual fi COUNT="$((COUNT + 1))" elif [ "${COUNT}" -gt 0 ] && [ "${ADD_RELAYS}" = "YES" ]; then if read_yesno "Do you want to use wildcard relay (via=['*']) option for ${SERVER}?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_manual_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_manual fi elif [ "${ADD_RELAYS}" = "NO" ]; then PTXT "${INFO} Skipping relays for ${SERVER}." fi ;; "${ODOH}") PTXT "${INFO} Found ${SERVER}, Oblivious DNS-over-HTTPS relays are required for Oblivious DNS-over-HTTPS servers." \ "${INFO} You may manually choose relays for ${SERVER} server or you may specify wildcard relay (via=['*'])." if [ "${COUNT}" -eq 0 ]; then if read_yesno "Do you want to use wildcard relay (via=['*']) option for ${SERVER}?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_manual_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_manual_odoh fi COUNT="$((COUNT + 1))" elif [ "${COUNT}" -gt 0 ]; then if read_yesno "Do you want to use wildcard relay (via=['*']) option for ${SERVER}?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_manual_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_manual_odoh fi fi ;; "${FRAGSBLOCKED}") if [ "${NUMFRAG}" -eq 0 ] && [ "${COUNT}" -gt 0 ]; then local USE_BROKEN if read_yesno "Do you want to skip using resolvers that are incompatible with anonymization instead of using them directly?"; then USE_BROKEN="true"; else USE_BROKEN="false"; fi toml_avars_prep skip_incompatible "${USE_BROKEN}" NUMFRAG="$((NUMFRAG + 1))" fi ;; esac fi done if [ "${COUNT}" -eq 0 ] && grep -q '^odoh_servers = .*false.*' "${TOML_FILE}" && grep -q '^dnscrypt_servers = .*true.*' "${TOML_FILE}"; then if [ -n "${DNSCRYPT}" ] || { grep -q '^dnscrypt_servers = .*true.*' "${TOML_FILE}" && ! grep -q '^server_names' "${TOML_FILE}"; }; then PTXT "${INFO} To continue, you may still define a default route for all compatible DNSCrypt servers and relays by selecting wildcard option for servers and relays." if read_yesno "Do you still want to setup wildcard options for servers (server_name "*") and relays (via=['*']) for all compatible DNSCrypt servers and relays?"; then check_anonymized_automatic 0; else check_anonymized_disabled; fi else check_anonymized_disabled fi elif [ "${COUNT}" -eq 0 ] && grep -q '^odoh_servers = .*true.*' "${TOML_FILE}" && grep -q '^dnscrypt_servers = .*true.*' "${TOML_FILE}"; then PTXT "${INFO} This option allows you to setup wildcard options for servers (server_name "*") and relays (via=['*']) for all compatible servers and relays." if read_yesno "Do you only want to skip this option for Dnscrypt Servers (still required for ODOH)?"; then choose_relays_automatic_odoh; else COUNT="$((COUNT + 1))"; fi if [ "${COUNT}" -gt 0 ]; then check_anonymized_automatic 0; fi elif [ "${COUNT}" -eq 0 ] && grep -q '^odoh_servers = .*true.*' "${TOML_FILE}" && grep -q '^dnscrypt_servers = .*false.*' "${TOML_FILE}"; then PTXT "${INFO} This option allows you to setup wildcard options for both servers (server_name "*") and relays (via=['*']) required for Oblivious DNS-over-HTTPS servers." if read_yesno "Do you want to use wildcard relay (via=['*']) option for (server_name "*")?"; then USE_WILDCARD="YES"; else USE_WILDCARD="NO"; fi if [ "${USE_WILDCARD}" = "YES" ]; then choose_relays_automatic_wildcard; elif [ "${USE_WILDCARD}" = "NO" ]; then PTXT "${INFO} You chose not to use wildcard for relay selection." "${INFO} Instead you will manually choose relays from a list." choose_relays_automatic_odoh fi elif [ "${COUNT}" -eq 0 ] && grep -q '^odoh_servers = .*false.*' "${TOML_FILE}" && grep -q '^dnscrypt_servers = .*false.*' "${TOML_FILE}"; then check_anonymized_disabled fi } check_swap() { local SWAP_SIZE SWAP_SIZE="$(awk '/SwapTotal/ {print $2}' /proc/meminfo)" if [ "${SWAP_SIZE}" -gt 0 ]; then PTXT "${INFO} Swap file is already setup" end_op_message 0 return fi inst_swap } check_version() { local RMNSTALL LINSTALL MD5SUM_L MD5SUM_R MD5SUM_REMOTE REMOTE_INSTALLER REMOTE_INSTALLER_MD5 varcnt if [ -f "${TARG_DIR}/installer" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ] && [ -z "$2" ]; then if [ -n "$1" ] || { check_connection; }; then REMOTE_INSTALLER="${TARG_DIR}/.installer.remote.$$" REMOTE_INSTALLER_MD5="${REMOTE_INSTALLER}.md5sum" varcnt="0" until [ -n "${LINSTALL}" ] && [ -n "${RMNSTALL}" ] && [ -n "${MD5SUM_L}" ] && [ -n "${MD5SUM_R}" ]; do if [ -z "${LINSTALL}" ]; then LINSTALL="$(awk -F= '/^DI_VERSION=/ { gsub(/"/, "", $2); sub(/^v/, "", $2); if ($2 ~ /^[0-9]{1,2}(\.[0-9]{1,2}){2}$/) print $2; exit }' "${TARG_DIR}/installer")"; fi if [ -z "${MD5SUM_L}" ]; then MD5SUM_L="$(md5sum "${TARG_DIR}/installer" | awk '{print $1; exit}')"; fi if [ -z "${RMNSTALL}" ] || [ -z "${MD5SUM_R}" ]; then MD5SUM_REMOTE="" rm -f "${REMOTE_INSTALLER}" "${REMOTE_INSTALLER_MD5}" if http_get_file "${RURL}/installer" "${REMOTE_INSTALLER}" && [ -s "${REMOTE_INSTALLER}" ]; then if http_get_file "${RURL}/installer.md5sum" "${REMOTE_INSTALLER_MD5}" && [ -s "${REMOTE_INSTALLER_MD5}" ]; then MD5SUM_REMOTE="$(awk '{print $1; exit}' "${REMOTE_INSTALLER_MD5}")" fi MD5SUM_R="$(md5sum "${REMOTE_INSTALLER}" | awk '{print $1; exit}')" if md5_is_valid "${MD5SUM_REMOTE}" && [ "${MD5SUM_REMOTE}" != "${MD5SUM_R}" ]; then RMNSTALL="" MD5SUM_R="" rm -f "${REMOTE_INSTALLER}" "${REMOTE_INSTALLER_MD5}" else RMNSTALL="$(awk -F= '/^DI_VERSION=/ { gsub(/"/, "", $2); sub(/^v/, "", $2); if ($2 ~ /^[0-9]{1,2}(\.[0-9]{1,2}){2}$/) print $2; exit }' "${REMOTE_INSTALLER}")" fi fi fi varcnt="$((varcnt + 1))" if [ "${varcnt}" -ge 2 ] && { [ -z "${LINSTALL}" ] || [ -z "${RMNSTALL}" ] || [ -z "${MD5SUM_L}" ] || [ -z "${MD5SUM_R}" ]; }; then rm -f "${REMOTE_INSTALLER}" "${REMOTE_INSTALLER_MD5}" PTXT "One or more critical variables could not be set in a timely manner." "Please check your internet connection, or try again later." "The installer script will now exit." sleep 3s exit 1 fi done rm -f "${REMOTE_INSTALLER}" "${REMOTE_INSTALLER_MD5}" if { [ -n "${LINSTALL}" ] && [ -n "${RMNSTALL}" ]; }; then [ -z "${LINSTALL}" ] && exit 1 [ -z "${RMNSTALL}" ] && exit 1 if [ "${RMNSTALL}" != "${LINSTALL}" ]; then PTXT "${INFO} New DI_VERSION=v${RMNSTALL} Available!" \ "${INFO} Run Option 1 of the Installer to upgrade DNScrypt Asuswrt Installer." AUTO_UPDATE="update" elif [ "${MD5SUM_R}" = "${MD5SUM_L}" ]; then PTXT "${INFO} DI_VERSION=v${LINSTALL}" else PTXT "${INFO} DI_VERSION=v${LINSTALL}, but a New Minor Update is Available!" \ "${INFO} Run Option 1 of the Installer to upgrade DNScrypt Asuswrt Installer." AUTO_UPDATE="update" fi local LVERSION LVERSION="$("${TARG_DIR}/dnscrypt-proxy" -version)" [ -z "${LVERSION}" ] && exit 1 if [ -z "${DNSCRYPT_VER}" ]; then PTXT "${WARNING} Unable to check the developer latest dnscrypt-proxy release." elif [ "${DNSCRYPT_VER}" != "${LVERSION}" ]; then PTXT "${INFO} New DNSCRYPT_VER=${DNSCRYPT_VER} Available!" \ "${INFO} Run Option 1 of the Installer to upgrade DNScrypt Proxy." AUTO_UPDATE="update" else PTXT "${INFO} DNSCRYPT_VER=${LVERSION}" fi if [ -f "${TARG_DIR}/manager" ]; then local MD5SUM_LM MD5SUM_M MURL REMOTE_MANAGER varcnt=0 MURL="${URL_GEN}/manager" REMOTE_MANAGER="${TARG_DIR}/.manager.remote.$$" until [ -n "${MD5SUM_LM}" ] && [ -n "${MD5SUM_M}" ]; do if [ -z "${MD5SUM_LM}" ]; then MD5SUM_LM="$(md5sum "${TARG_DIR}/manager" | awk '{print $1; exit}')"; fi if [ -z "${MD5SUM_M}" ]; then rm -f "${REMOTE_MANAGER}" if http_get_file "${MURL}" "${REMOTE_MANAGER}" && [ -s "${REMOTE_MANAGER}" ]; then MD5SUM_M="$(md5sum "${REMOTE_MANAGER}" | awk '{print $1; exit}')" fi fi varcnt="$((varcnt + 1))" if [ "${varcnt}" -ge 2 ] && { [ -z "${MD5SUM_LM}" ] || [ -z "${MD5SUM_M}" ]; }; then rm -f "${REMOTE_MANAGER}" PTXT "One or more critical variables could not be set in a timely manner." "Please check your internet connection, or try again later." "The installer script will now exit." sleep 3s exit 1 fi done rm -f "${REMOTE_MANAGER}" if [ "${MD5SUM_M}" = "${MD5SUM_LM}" ]; then PTXT "${INFO} Manager file is Up-To-Date!" else PTXT "${INFO} New Manager file is Available!" \ "${INFO} Run Option 1 of the Installer to upgrade the Manager File." AUTO_UPDATE="update" fi fi fi elif { [ -z "$LINSTALL" ] && [ -z "$RMNSTALL" ]; } && [ -z "$1" ]; then while { ! check_connection; }; do sleep 1s; done && check_version x else check_version x x fi fi } save_dns_nvram_environment() { local VAR VALUE for VAR in dnspriv_enable dhcpd_dns_router dhcp_dns1_x dhcp_dns2_x; do VALUE="$(nvram get "${VAR}" 2>/dev/null)" case "${VAR}" in dnspriv_enable) _OLD_dnspriv_enable="${VALUE}" ;; dhcpd_dns_router) _OLD_dhcpd_dns_router="${VALUE}" ;; dhcp_dns1_x) _OLD_dhcp_dns1_x="${VALUE}" ;; dhcp_dns2_x) _OLD_dhcp_dns2_x="${VALUE}" ;; esac done export _OLD_dnspriv_enable _OLD_dhcpd_dns_router _OLD_dhcp_dns1_x _OLD_dhcp_dns2_x _DNS_NVRAM_SAVED="1" export _DNS_NVRAM_SAVED } # Installation and setup operations end_op_header() { sed -n -e "1,$(($(grep -wn 'esac' "$0" | cut -d':' -f1 | tail -n1) + 1))p" "$0" >"${0}.tmp" chmod 755 "${0}.tmp" exec "${0}.tmp" "${BRANCH}" && rm -rf "${0}.tmp" } end_op_message() { case "${1:-0}" in 0) [ "$2" = "update" ] && exit 0 PTXT "${INFO} Operation completed, returning to Main Menu. You can quit or continue." ;; 1) [ "$2" = "update" ] && exit 1 PTXT "${INFO} Operation aborted, returning to Main Menu. You can quit or continue." ;; 2) PTXT "${INFO} Abnormal operations, returning to Main Menu. You can quit or continue." ;; esac PTXT "=====================================================" PTXT " " PTXT " " sleep 3s && clear if [ -f "${TARG_DIR}/installer" ]; then chmod 755 "${TARG_DIR}/installer" >/dev/null 2>&1 exec "${TARG_DIR}/installer" "${BRANCH}" elif [ ! -f "${TARG_DIR}/installer" ] && [ -f "${SCRIPT_LOC}" ]; then chmod 755 "${SCRIPT_LOC}" >/dev/null 2>&1 exec "${SCRIPT_LOC}" "${BRANCH}" elif [ -f "${HOME}/installer" ]; then chmod 755 "${HOME}/installer" exec "${HOME}/installer" "${BRANCH}" else clear && { end_op_header 2>/dev/null; } fi exit $? } inst_dnscrypt() { local DNSCRYPT_TAR DNSCRYPT_PACKAGE_URL RESOLVERS_URL_PREFIX CRYPT_RESOLVERS FULL_RESOLVERS INSTALLER_MD5_OLD if ping -q -w3 -c1 "download.dnscrypt.info" >/dev/null 2>&1; then RESOLVERS_URL_PREFIX="https://download.dnscrypt.info/resolvers-list/" else RESOLVERS_URL_PREFIX="https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/" fi FULL_RESOLVERS="v3" CRYPT_RESOLVERS="v1" CRYPT_RESOLVERS="${RESOLVERS_URL_PREFIX}${CRYPT_RESOLVERS}" RESOLVERS_URL_PREFIX="${RESOLVERS_URL_PREFIX}${FULL_RESOLVERS}" INSTALLER_MD5_OLD="" [ -f "${SCRIPT_LOC}" ] && INSTALLER_MD5_OLD="$(md5sum "${SCRIPT_LOC}" 2>/dev/null | awk '{print $1; exit}')" if [ -z "$2" ]; then if [ "${1:-RESTORE}" != "RESTORE" ]; then if [ ! -d "$TARG_DIR" ] && [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then PTXT "${INFO} Backup is detected." local USE_OLD if read_yesno "Do you want Restore instead?"; then USE_OLD="YES"; else USE_OLD="NO"; fi if [ "${USE_OLD}" = "YES" ]; then PTXT "${INFO} Installing from an old backup!" backup_restore RESTORE elif [ "${USE_OLD}" = "NO" ]; then PTXT "${INFO} Continuing without restoring from backup!" fi elif [ -d "${TARG_DIR}" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ] && [ ! -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then if read_yesno "Do you want create a backup before updating?"; then backup_restore BACKUP 0; else PTXT "${INFO} continuing without making a backup."; fi fi fi if ! check_connection; then PTXT "${ERROR} Unable to detect the Internet!" end_op_message 1 "$1" return fi if ! create_dir "${TARG_DIR}"; then end_op_message 1 "$1" return fi if ! download_file "${TARG_DIR}" 755 "${RURL}/installer" || ! awk '{ print }' "${TARG_DIR}/installer" | grep -m1 "^DI_VERSION=" | grep -qoE '[0-9]{1,2}([.][0-9]{1,2})([.][0-9]{1,2})'; then PTXT "${ERROR} Failed to download installer." end_op_message 1 "$1" return fi installer_update_reexec "${1:-install}" "${INSTALLER_MD5_OLD}" download_file "${TARG_DIR}" 755 "${URL_GEN}/manager" if [ "${1:-RESTORE}" != "RESTORE" ]; then if [ "${1:-install}" != "update" ] || [ -z "${DNSCRYPT_VER}" ]; then choose_dnscrypt_binary_source; fi DNSCRYPT_BINARY_SOURCE="$(read_conf DNSCRYPT_BINARY_SOURCE)" if [ "${DNSCRYPT_BINARY_SOURCE}" = "nightly" ]; then inst_dnscrypt "${1:-install}" "${DNSCRYPT_NIGHTLY_VER}" return fi if [ -f "${TARG_DIR}/dnscrypt-proxy" ]; then local LVERSION LVERSION="$("${TARG_DIR}/dnscrypt-proxy" -version)" [ -z "${LVERSION}" ] && exit 1 [ -z "${DNSCRYPT_VER}" ] && exit 1 if [ "${DNSCRYPT_VER}" != "${LVERSION}" ]; then PTXT "${INFO} New DNSCRYPT_VER=${DNSCRYPT_VER} Available!" \ "${INFO} Updating DNSCRYPT_VER=${LVERSION} to ${DNSCRYPT_VER}." inst_dnscrypt "${1:-update}" "${DNSCRYPT_VER}" else PTXT "${INFO} DNSCRYPT_VER=${LVERSION}" fi else inst_dnscrypt "${1:-install}" "${DNSCRYPT_VER}" fi fi else [ -z "${DNSCRYPT_NIGHTLY_PACKAGE_URL:-}" ] && prepare_dnscrypt_download_vars if [ "$2" = "${DNSCRYPT_NIGHTLY_VER}" ]; then DNSCRYPT_TAR="${DNSCRYPT_NIGHTLY_TAR}" DNSCRYPT_PACKAGE_URL="${DNSCRYPT_NIGHTLY_PACKAGE_URL}" if ! download_file "${TARG_DIR}" 644 "${DNSCRYPT_PACKAGE_URL}" "${DNSCRYPT_NIGHTLY_MINISIG_URL}"; then PTXT "${ERROR} Unable to download dnscrypt-proxy nightly package for your router" end_op_message 1 "$1" return fi else DNSCRYPT_TAR="dnscrypt-proxy-${DNSCRYPT_ARCH}-${2}.tar.gz" DNSCRYPT_PACKAGE_URL="${DNSCRYPT_REPO_URL}/releases/download/${2}/${DNSCRYPT_TAR}" if [ "$2" = "${DNSCRYPT_VER}" ] && [ -n "${DNSCRYPT_RELEASE_PACKAGE_URL}" ]; then DNSCRYPT_TAR="${DNSCRYPT_RELEASE_TAR}" DNSCRYPT_PACKAGE_URL="${DNSCRYPT_RELEASE_PACKAGE_URL}" fi if ! download_file "${TARG_DIR}" 644 "${DNSCRYPT_PACKAGE_URL}"; then PTXT "${ERROR} Unable to download dnscrypt-proxy package for your router" end_op_message 1 "$1" return fi fi if ! dnscrypt_prepare_binary_replace; then end_op_message 1 "$1" return fi tar xzv -C "${TARG_DIR}" -f "${TARG_DIR}/${DNSCRYPT_TAR}" chown "$(nvram get http_username)":root ${TARG_DIR}/"${DNSCRYPT_ARCH_TAR}"/* mv ${TARG_DIR}/"${DNSCRYPT_ARCH_TAR}"/* "${TARG_DIR}" rm -r "${TARG_DIR:?}/${DNSCRYPT_ARCH_TAR}" "${TARG_DIR:?}/${DNSCRYPT_TAR}" if ! chmod 755 "${TARG_DIR}/dnscrypt-proxy" && [ -z "$("${TARG_DIR}/dnscrypt-proxy" -version)" ]; then PTXT "${ERROR} Failed to download dnscrypt-proxy package for your router" end_op_message 1 "$1" return fi fi PTXT "${INFO} Skipping legacy nonroot helper; dnscrypt-proxy starts directly setting under privileged user to nobody after binding privileged ports." download_file "${TARG_DIR}" 644 "${RESOLVERS_URL_PREFIX}/public-resolvers.md" \ "${RESOLVERS_URL_PREFIX}/public-resolvers.md.minisig" \ "${RESOLVERS_URL_PREFIX}/relays.md" \ "${RESOLVERS_URL_PREFIX}/relays.md.minisig" \ "${RESOLVERS_URL_PREFIX}/odoh-servers.md" \ "${RESOLVERS_URL_PREFIX}/odoh-servers.md.minisig" \ "${RESOLVERS_URL_PREFIX}/odoh-relays.md" \ "${RESOLVERS_URL_PREFIX}/odoh-relays.md.minisig" download_file "${TARG_DIR}" 644 "${CRYPT_RESOLVERS}/dnscrypt-resolvers.csv" \ "${CRYPT_RESOLVERS}/dnscrypt-resolvers.csv.minisig" chown nobody:nobody "${TARG_DIR}/public-resolvers.md" \ "${TARG_DIR}/public-resolvers.md.minisig" \ "${TARG_DIR}/relays.md" \ "${TARG_DIR}/relays.md.minisig" \ "${TARG_DIR}/odoh-servers.md" \ "${TARG_DIR}/odoh-servers.md.minisig" \ "${TARG_DIR}/odoh-relays.md" \ "${TARG_DIR}/odoh-relays.md.minisig" \ "${TARG_DIR}/dnscrypt-resolvers.csv" \ "${TARG_DIR}/dnscrypt-resolvers.csv.minisig" for i in init-start services-stop; do if { ! grep -q "${TARG_DIR}/manager ${i} &" "/jffs/scripts/${i}" && grep -q "${TARG_DIR}/manager ${i}" "/jffs/scripts/${i}"; }; then del_jffs_script "/jffs/scripts/${i}"; fi; done write_manager_script /jffs/scripts/init-start "init-start &" write_manager_script /jffs/scripts/services-stop "services-stop &" write_manager_script /jffs/scripts/dnsmasq.postconf dnsmasq if nvram get rc_support | grep -q 'mtlancfg'; then write_manager_script /jffs/scripts/dnsmasq-sdn.postconf 'dnsmasq-sdn $2'; fi del_between_magic /jffs/scripts/service-event-end '# Asuswrt-Merlin-Dnscrypt-Proxy-Installer' write_command_script /jffs/scripts/service-event-end 'if printf "%s" "$@" | /bin/grep -qE "^(((((dnscrypt-)?(start|stop)|restart|kill))_?.*dnscrypt-proxy)$)"; then { sh /jffs/dnscrypt/manager "$(printf "%s" "$@" | /bin/grep -oE "^(((dnscrypt-)?(start|stop)|restart|kill))")" x & }; fi # Asuswrt-Merlin-Dnscrypt-Proxy-Installer' if [ "${1:-update}" != "update" ]; then if ! setup_dnscrypt "" "${1:-install}"; then end_op_message 1 return fi fi if ! dnscrypt_complete_startup; then end_op_message 1 "$1" return fi PTXT "${INFO} For dnscrypt-proxy version 2 to work reliably, you might also want to:" \ "${INFO} - Add swap" \ "${INFO} - Add a RNG" \ "${INFO} - Set your timezone" end_op_message 0 "$1" } inst_ran_dev() { local RNG_DEV if [ -c "/dev/ttyACM0" ]; then local PRODSTR VID PID PRODSTR="$(awk '{ print }' "/sys/class/tty/ttyACM0/device/uevent" | grep "^PRODUCT\=")" VID="$(PTXT "${PRODSTR}" | cut -d '=' -f 2 | cut -d '/' -f 1)" PID="$(PTXT "${PRODSTR}" | cut -d '=' -f 2 | cut -d '/' -f 2)" if [ "${VID}" = "4d8" ] && [ "${PID}" = "f5fe" ]; then PTXT "${INFO} Found TrueRNG USB HW RNG" RNG_DEV="ttyACM0" fi if [ "${VID}" = "16d0" ] && [ "${PID}" = "aa0" ]; then PTXT "${INFO} Found TrueRNGpro USB HW RNG" RNG_DEV="ttyACM0" fi if [ "${VID}" = "1d50" ] && [ "${PID}" = "6086" ]; then PTXT "${INFO} Found OneRNG USB HW RNG" RNG_DEV="ttyACM0" fi if [ "${VID}" = "20df" ] && [ "${PID}" = "1" ]; then PTXT "${INFO} Found EntropyKey USB HW RNG" RNG_DEV="ttyACM0" fi fi if [ -z "${RNG_DEV}" ]; then PTXT "${ERROR} Unable to find any HW RNG device! Retrying..." inst_random return 1 fi write_conf RNG_DEV "/dev/${RNG_DEV}" } inst_random() { local RNG_DEV RAN_PRV MAX_OPTION HAS_JITTERENTROPY create_dir "${TARG_DIR}" HAS_JITTERENTROPY="0" if http_get_file "${URL_ARCH}/jitterentropy-rngd.md5sum" "/dev/null" "" insecure; then HAS_JITTERENTROPY="1" fi PTXT "${INFO} Install a (P)RNG for better cryptographic operations" \ "${INFO} Available random number generator providers:" \ " 1) HAVEGED (Preferred if you do not have a HW RNG)" \ " 2) RNGD (Preferred if you have a HW RNG)" if [ "${HAS_JITTERENTROPY}" = "1" ]; then PTXT " 3) JITTERENTROPY-RNGD (Alternative software PRNG)" else PTXT "${WARNING} 3) JITTERENTROPY-RNGD is temporarily unavailable for this architecture." fi PTXT "${INFO} If you choose a HW RNG, please have it plugged in now before" \ "${INFO} proceeding with your selection." MAX_OPTION="2" [ "${HAS_JITTERENTROPY}" = "1" ] && MAX_OPTION="3" read_input_num "Please enter the number designates your selection" 1 "${MAX_OPTION}" case "${CHOSEN}" in 1) rm -f "${TARG_DIR}/rngd" "${TARG_DIR}/stty" { kill_processes haveged jitterentropy-rngd rngd stty; } download_file "${TARG_DIR}" 755 "${URL_ARCH}/haveged" "${URL_GEN}/manager" if [ ! -x "${TARG_DIR}/haveged" ] || ! "${TARG_DIR}/haveged" -w 1024 -d 32 -i 32 -v 1; then PTXT "${ERROR} Failed to start haveged. Please try reinstalling (P)RNG or switch to RNGD." end_op_message 1 return 1 fi RAN_PRV="haveged" ;; 2) RNG_DEV="$(read_conf RNG_DEV)" { kill_processes haveged jitterentropy-rngd rngd stty; } download_file "$TARG_DIR" 755 "${URL_ARCH}/haveged" "${URL_ARCH}/rngd" "${URL_ARCH}/stty" "${URL_GEN}/manager" inst_ran_dev || return if [ ! -x "${TARG_DIR}/stty" ] || [ ! -x "${TARG_DIR}/rngd" ] || ! "${TARG_DIR}/stty" raw -echo -ixoff -F "${RNG_DEV}" speed 115200 || ! "${TARG_DIR}/rngd" -r "${RNG_DEV}"; then PTXT "${ERROR} Failed to start RNGD. Please verify your HW RNG device and reinstall (P)RNG." end_op_message 1 return 1 fi RAN_PRV="rngd" ;; 3) if [ "${HAS_JITTERENTROPY}" != "1" ]; then PTXT "${ERROR} JITTERENTROPY-RNGD is currently unavailable for your architecture." end_op_message 1 return 1 fi rm -f "${TARG_DIR}/haveged" "${TARG_DIR}/rngd" "${TARG_DIR}/stty" { kill_processes haveged jitterentropy-rngd rngd stty; } if ! download_file "${TARG_DIR}" 755 "${URL_ARCH}/jitterentropy-rngd" "${URL_GEN}/manager"; then PTXT "${ERROR} Failed to download jitterentropy-rngd and/or updated manager script." end_op_message 1 return 1 fi if [ ! -x "${TARG_DIR}/jitterentropy-rngd" ] || ! "${TARG_DIR}/jitterentropy-rngd"; then PTXT "${ERROR} Failed to start jitterentropy-rngd. Please try reinstalling (P)RNG or switch providers." end_op_message 1 return 1 fi RAN_PRV="jitterentropy-rngd" ;; esac write_conf RAN_PRV "${RAN_PRV}" write_manager_script /jffs/scripts/init-start init-start end_op_message 0 } inst_swap() { local SWAP_SIZE USB_COUNT SWAP_SIZE="524288" USB_COUNT="$(df | awk -v SWS="$((SWAP_SIZE * 2))" '/\/tmp\/mnt\// {if ($4 > SWS){print $6}}' | wc -l)" if [ "${USB_COUNT}" -lt 1 ]; then PTXT "${ERROR} Unable to find any external USB storage" \ "${ERROR} Or no suitable external USB storage found" \ "${ERROR} Please connect a USB storage with at least" \ "${ERROR} $((SWAP_SIZE * 2 / 1024))MB of free space." end_op_message 1 return fi PTXT "${INFO} Available partition to install swap file:${NORM}" df | awk -v SWS="$((SWAP_SIZE * 2))" '/\/tmp\/mnt\// {if ($4 > SWS){++i; print " " i ") " $6 " (" $4/1024 "MB free)"}}' read_input_num "Please select the partition to install swap file" 1 "${USB_COUNT}" local MOUNT MOUNT="$(df | awk -v IDX="${CHOSEN}" -v SWS="$((SWAP_SIZE * 2))" '/\/tmp\/mnt\// {if ($4 > SWS){++i; if (i==IDX){print $6}}}')" PTXT "${INFO} Please wait..." dd if=/dev/zero of="${MOUNT}/swap" bs=1024 count="${SWAP_SIZE}" local MOUNT_FS MOUNT_FS="$(df -T "${MOUNT}" | awk 'FNR==2 {print $2}')" [ "${MOUNT_FS%?}" = "ext" ] && chmod 600 "${MOUNT}/swap" mkswap "${MOUNT}/swap" if ! swapon "${MOUNT}/swap"; then sed -i "/^$(_quote '[ -f $1/swap ] && swapon $1/swap')$/d" /jffs/scripts/post-mount sed -i "/^$(_quote '[ -f $1/swap ] && swapoff $1/swap')$/d" /jffs/scripts/unmount write_command_script /jffs/scripts/post-mount '[ -f "$1/swap" ] && swapon "$1/swap"' write_command_script /jffs/scripts/unmount '[ -f "$1/swap" ] && swapoff "$1/swap"' end_op_message 0 else PTXT "${ERROR} Unable to create swap. Get the command log to dev" end_op_message 1 fi } manager_monitor_restart() { local MAN_PID PID MAN_PID="$(pidof manager)" if [ "${MAN_PID}" ]; then for PID in ${MAN_PID}; do if awk '{ print }' "/proc/${PID}/cmdline" | grep -q dnscrypt; then { kill -s 10 "${PID}" 2>/dev/null || kill -s 9 "${PID}" 2>/dev/null; } break fi done fi ${TARG_DIR}/manager monitor-start } opendns_authen() { if [ "$1" -eq 0 ]; then del_conf OPENDNS_USER OPENDNS_PASSWORD return fi if [ -z "${PW1}" ] || [ -z "${PW2}" ]; then local USERNAME PTXT -n "${INPUT} Please enter OpenDNS username${NORM}: " read -r USERNAME fi local PW1 PW2 PTXT -n "${INPUT} Please enter OpenDNS password${NORM}: " read -rs PW1 PTXT " " PTXT -n "${INPUT} Please reenter OpenDNS password${NORM}: " read -rs PW2 PTXT " " if [ -z "${PW1}" ] || [ -z "${PW2}" ] || [ "${PW1}" != "${PW2}" ]; then PTXT "${ERROR} Password entered incorrectly!" opendns_authen "$1" fi write_conf OPENDNS_USER "\"${USERNAME}\"" write_conf OPENDNS_PASSWORD "\"${PW1}\"" } set_timezone() { local TMP TZ_DATA INDEX TZ_ARCH TMP="/root" TZ_ARCH="$(uname -m)" case "${TZ_ARCH}" in "aarch64" | "arm64") TZ_ARCH="aarch64" ;; "armv7l") TZ_ARCH="arm" ;; esac TZ_DATA="tzdata-2021e-1-${TZ_ARCH}.pkg.tar.bz2" download_file "${TARG_DIR}" 755 "${URL_GEN}/manager" download_file "${TMP}" 644 "${URL_GEN}/${TZ_DATA}" local INDEX INDEX="$(tar tjf "${TMP}/${TZ_DATA}" | awk -F'/' '!/\/$/ && /\/posix\//' | wc -l)" PTXT "${INFO} Available timezones/locations:" tar tjf "${TMP}/${TZ_DATA}" | awk -F'/' '!/\/$/ && /\/posix\//' | sort | cut -d'/' -f2- | awk -v INDEX=0 -F'/' '!/\/$/ {++INDEX;printf " " INDEX") ";for (i=5; i/dev/null 2>&1; } rm -r "${TMP:?}/${TZ_DATA}" "${TMP:?}/usr" end_op_message 0 } setup_amtmupdate() { local AMTM_UPDATE CURRENT_AMTM_UPDATE CURRENT_AMTM_UPDATE="$(read_conf AMTM_UPDATE)" if [ -z "${CURRENT_AMTM_UPDATE}" ] || [ "${CURRENT_AMTM_UPDATE}" = "DISABLED" ]; then AMTM_UPDATE="ENABLED" else AMTM_UPDATE="DISABLED" fi PTXT "${INFO} The installer will now set AMTM Update to ${AMTM_UPDATE}." write_conf AMTM_UPDATE "\"${AMTM_UPDATE}\"" end_op_message 0 } setup_dnscrypt() { if [ ! -f "${TOML_ORI}" ] || [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; then PTXT "${ERROR} dnscrypt-proxy is not installed. Aborting..." end_op_message 1 return fi PTXT "${INFO} Configuring dnscrypt-proxy..." setup_dnscrypt_impl "$@" local RET="$?" check_opendns if [ "$1" = "reconfig" ]; then if [ "${RET}" -eq 0 ]; then PTXT "${INFO} Restarting dnscrypt-proxy with new config..." if ! dnscrypt_restart; then dnscrypt_start_error end_op_message 1 return fi end_op_message 0 else end_op_message 0 fi fi return "${RET}" } setup_dnscrypt_impl() { if [ -z "$1" ] && [ -f "${TOML_FILE}" ]; then if ! check_dnscrypt_toml; then setup_dnscrypt_impl x return fi PTXT "${INFO} Found previous dnscrypt-proxy config file" if read_yesno "Do you want to use this file without reconfiguring?"; then PTXT "${INFO} Use previous settings file"; else setup_dnscrypt_impl x; fi else if [ -f "${TOML_FILE}" ]; then if [ "$1" = "reconfig" ]; then if ! check_dnscrypt_toml; then setup_dnscrypt_impl x return fi PTXT "${INFO} Found previous dnscrypt-proxy config file" fi PTXT "${INFO} How do you want to reconfigure:" \ "${INFO} 1) Start from previous settings file" \ "${INFO} 2) Start from default config" read_input_num "Your selection" 1 2 case "${CHOSEN}" in 1) PTXT "${INFO} Use previous settings file" ;; 2) PTXT "${INFO} Backing up previous settings file..." mv "${TOML_FILE}" "${TOML_BAK}" cp -f "${TOML_ORI}" "${TOML_FILE}" ;; esac else cp -f "${TOML_ORI}" "${TOML_FILE}" fi case "${2:-reconfig}" in "install" | "reconfig") if read_yesno "Do you want to redirect all DNS resolutions on your network through to Dnscrypt-Proxy?"; then check_dns_filter 1; else check_dns_filter 0; fi if [ "$(nvram get dns_local_cache)" != "1" ]; then { if read_yesno "Do you want to run Dnsmasq as a local caching DNS service which includes sending the routers traffic to Dnscrypt-Proxy?"; then check_dns_local 1; else check_dns_local 0; fi; }; else { check_dns_local 0; }; fi toml_avar_enable disabled_server_names local PHX NXT PHX="$(grep -wn "sources.odoh-servers" "${TOML_FILE}" | cut -f1 -d:)" NXT="$((PHX + 11))" sed -i "${PHX},${NXT} s/#//g" "${TOML_FILE}" choose_dnscrypt_server PTXT "${INFO} Evaluating the possibilities for other dnscrypt-proxy configurations such as relay support..." check_relays PTXT "${INFO} Set the DNS server(s) for initializing dnscrypt-proxy" \ "${INFO} and router services (e.g. ntp) at boot" read_input_dns "Default is" 9.9.9.9 read_input_dns "2nd Default is" 8.8.8.8 read_input_num "Set log level, default is 2, 0 is the most verbose" 0 6 toml_nvars_replace "fallback_resolvers =" "bootstrap_resolvers = [$BOOTSTRAP2]" "$TOML_FILE" if read_yesno "Do you want to use TLSv1.3 (http3)?"; then toml_avar_disable tls_cipher_suite toml_avars_prep http3 true else toml_avar_enable tls_cipher_suite toml_avars_prep http3 false tls_cipher_suite "\"[52393, 52392, 49199, 49195, 4867, 4865]\"" fi toml_avars_prep bootstrap_resolvers "\"[${BOOTSTRAP2}]\"" log_level "${CHOSEN}" ignore_system_dns true listen_addresses "[\'127.0.1.1:53\']" cache false cert_ignore_timestamp true max_clients 25000 keepalive 120 netprobe_timeout 120 netprobe_address "\'${PROBE}\'" tls_disable_session_tickets true dnscrypt_ephemeral_keys true case "${ROUTER_MODEL}" in RT-AX56U | RT-AX58U | RT-AX3000) toml_avar_disable user_name ;; *) toml_avars_prep user_name "\'nobody\'" ;; esac PTXT "${INFO} Writing dnscrypt-proxy configuration..." if ! check_dnscrypt_toml; then PTXT "${INFO} Writing dnscrypt-proxy configuration failed " \ "${INFO} Please send ${TOML_ERR} file and screen log of " \ "${INFO} all operations you have made to this script dev" return 1 fi ;; esac fi } uninst_all() { if [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then PTXT "${INFO} Old Backup Detected!" if read_yesno "Do you want to remove backup?(this will prevent restoring from backups later)"; then rm -rf "${BASE_DIR}/backup_dnscrypt.tar.gz"; else PTXT "${INFO} Keeping backup instead."; fi fi dnscrypt_stop mv "${TARG_DIR}/installer" "${HOME}/installer" rm -f "${TARG_DIR}/nonroot" rm -rf "${TARG_DIR}" del_jffs_script /jffs/scripts/dnsmasq.postconf if nvram get rc_support | grep -q 'mtlancfg'; then del_jffs_script /jffs/scripts/dnsmasq-sdn.postconf; fi del_jffs_script /jffs/scripts/init-start del_jffs_script /jffs/scripts/services-stop { kill_processes haveged jitterentropy-rngd rngd stty dnscrypt-proxy; } del_between_magic /jffs/scripts/service-event-end '# Asuswrt-Merlin-Dnscrypt-Proxy-Installer' local MAN_PID PID MAN_PID="$(pidof manager)" if [ "${MAN_PID}" ]; then for PID in ${MAN_PID}; do if awk '{ print }' "/proc/${PID}/cmdline" | grep -q dnscrypt; then { kill -s 10 "${PID}" 2>/dev/null || kill -s 9 "${PID}" 2>/dev/null; } break fi done fi service restart_dnsmasq >/dev/null 2>&1 end_op_message 0 } uninst_dnscrypt() { dnscrypt_stop PTXT "${INFO} Uninstalling dnscrypt-proxy..." rm -f "${TARG_DIR}/dnscrypt-proxy" "${TARG_DIR}/nonroot" del_jffs_script /jffs/scripts/dnsmasq.postconf if nvram get rc_support | grep -q 'mtlancfg'; then del_jffs_script /jffs/scripts/dnsmasq-sdn.postconf; fi { kill_processes dnscrypt-proxy; } service restart_dnsmasq >/dev/null 2>&1 PTXT "${INFO} Some configuration files are not removed in case you want to reinstall" end_op_message 0 } uninst_random() { PTXT "${INFO} Uninstalling (P)RNG..." rm -f "${TARG_DIR}/haveged" "${TARG_DIR}/rngd" "${TARG_DIR}/stty" "${TARG_DIR}/jitterentropy-rngd" { kill_processes haveged jitterentropy-rngd rngd stty; } del_conf RAN_PRV RNG_DEV if [ ! -f "${TARG_DIR}/localtime" ] && [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; then del_jffs_script /jffs/scripts/init-start del_jffs_script /jffs/scripts/services-stop fi end_op_message 0 } unset_timezone() { rm -f "${TARG_DIR}/localtime" if [ -z "$(read_conf RAN_PRV)" ] && [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; then del_jffs_script /jffs/scripts/init-start del_jffs_script /jffs/scripts/services-stop fi end_op_message 0 } # Interactive selection helpers choose_dnscrypt_server() { local USE_IPV6 if [ "$(nvram get ipv6_service)" != "disabled" ]; then { if read_yesno "Do you want to use DNS server over IPv6 (yes only if your connection has IPv6)?"; then USE_IPV6="true"; else USE_IPV6="false"; fi; }; else USE_IPV6="false"; fi toml_avars_prep ipv6_servers "${USE_IPV6}" PTXT "${INFO} Choose DNS resolving load balancing strategy:" \ " 1) p2 (default)" \ " 2) ph" \ " 3) first" \ " 4) random" read_input_num "Select your strategy" 1 4 case "${CHOSEN}" in 1) toml_avars_prep lb_strategy "\'p2\'" ;; 2) toml_avars_prep lb_strategy "\'ph\'" ;; 3) toml_avars_prep lb_strategy "\'first\'" ;; 4) toml_avars_prep lb_strategy "\'random\'" ;; esac if read_yesno "Do you want to use load balance estimator to adjust resolvers based on latency calculations?"; then USE_LBE="true"; else USE_LBE="false"; fi toml_avars_prep lb_estimator "${USE_LBE}" PTXT "${INFO} Choose how your DNS servers are selected:" \ " 1) Automatically (default)" \ " 2) Manually" \ " 3) Static" read_input_num "Select your mode" 1 3 case "${CHOSEN}" in 1) choose_dnscrypt_server_auto if grep -q '^dnscrypt_servers = .*true.*' "${TOML_FILE}" && [ -z "${CRYPT_COUNT}" ]; then CRYPT_COUNT="1"; fi if read_yesno "Do you want to choose which servers to disable (this can be a long process)?"; then CHOOSE_DISABLED="true"; else CHOOSE_DISABLED="false"; fi if [ "${CHOOSE_DISABLED}" = "true" ]; then choose_dnscrypt_server_disabled; elif [ "${CHOOSE_DISABLED}" = "false" ]; then toml_avar_disable disabled_server_names; fi ;; 2) toml_avar_disable disabled_server_names if read_yesno "Do you only want to use the Oblivious DNS-over-HTTPS protocol?"; then ODOH_ONLY="true"; else ODOH_ONLY="false"; fi if [ "${ODOH_ONLY}" = "true" ]; then choose_dnscrypt_server_odoh; elif [ "${ODOH_ONLY}" = "false" ]; then choose_dnscrypt_server_manual; fi ;; 3) toml_avar_disable disabled_server_names static_chosen 0 ;; esac } choose_dnscrypt_server_auto() { toml_avar_disable server_names if read_yesno "Use servers that support the DNSCrypt protocol"; then toml_avars_prep dnscrypt_servers true; else toml_avars_prep dnscrypt_servers false; fi if read_yesno "Use servers that support the DNS-over-HTTPS protocol"; then toml_avars_prep doh_servers true; else toml_avars_prep doh_servers false; fi if read_yesno "Use servers that support the Oblivious DNS-over-HTTPS protocol"; then toml_avars_prep odoh_servers true; else toml_avars_prep odoh_servers false; fi if read_yesno "Use only servers that support DNSSEC"; then toml_avars_prep require_dnssec true; else toml_avars_prep require_dnssec false; fi if read_yesno "Use only servers that do not log user's queries"; then toml_avars_prep require_nolog true; else toml_avars_prep require_nolog false; fi if read_yesno "Use only servers that do not filter result"; then toml_avars_prep require_nofilter true; else toml_avars_prep require_nofilter false; fi } choose_dnscrypt_server_disabled() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then if [ "${USE_IPV6}" = "true" ]; then USE_IPV6="NOMATCH"; else USE_IPV6="6"; fi local RESOLVERS PTXT "${INFO} Available DNS servers to disable: " INDEX="$(awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/public-resolvers.md" | wc -l)" awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/public-resolvers.md" read_input_num "Please choose DNS server to disable" 1 "${INDEX}" else if ! read_input_num "Please choose next DNS server to disable or press n to stop" 1 "${INDEX}" n; then if grep -q '^odoh_servers = .*true.*' "${TOML_FILE}"; then if read_yesno "Do you want to choose which Oblivious DNS-over-HTTPS DNS servers to disable?"; then ODOH_DISABLED="true"; else ODOH_DISABLED="false"; fi if [ "${ODOH_DISABLED}" = "true" ]; then choose_dnscrypt_server_disabled_odoh; fi fi toml_avars_prep disabled_server_names "\"[${RESOLVERS}]\"" return fi fi local ITEM ITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/public-resolvers.md")" if PTXT "${RESOLVERS}" | grep -qoF "'${ITEM}'"; then PTXT "${INFO} ${ITEM} is already set." else if [ "${RESOLVERS}" ]; then RESOLVERS="${RESOLVERS%?}', '${ITEM}'" else RESOLVERS="'${ITEM}'" fi fi choose_dnscrypt_server_disabled "${INDEX}" } choose_dnscrypt_server_disabled_odoh() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then local ORESOLVERS PTXT "${INFO} Available DNS servers to disable: " INDEX="$(awk -v PATT="odohrelay" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/odoh-servers.md" | wc -l)" awk -v PATT="odohrelay" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/odoh-servers.md" read_input_num "Please choose DNS server to disable" 1 "${INDEX}" else if ! read_input_num "Please choose next DNS server to disable or press n to stop" 1 "${INDEX}" n; then RESOLVERS="${ORESOLVERS}, ${RESOLVERS}" return fi fi local OITEM OITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="odohrelay" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/odoh-servers.md")" if PTXT "${ORESOLVERS}" | grep -qoF "'${OITEM}'"; then PTXT "${INFO} ${OITEM} is already set." else if [ "${ORESOLVERS}" ]; then ORESOLVERS="${ORESOLVERS%?}', '${OITEM}'" else ORESOLVERS="'${OITEM}'" fi fi choose_dnscrypt_server_disabled_odoh "${INDEX}" } choose_dnscrypt_server_manual() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then [ "${USE_IPV6}" = "true" ] && USE_IPV6="NOMATCH" || USE_IPV6="6" local RESOLVERS toml_avars_prep dnscrypt_servers true doh_servers true require_dnssec false require_nolog false require_nofilter false PTXT "${INFO} Available DNS servers: " INDEX="$(awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/public-resolvers.md" | wc -l)" awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/public-resolvers.md" read_input_num "Please choose DNS server." 1 "${INDEX}" else if ! read_input_num "Please choose next DNS server or press n to stop." 1 "${INDEX}" n; then if read_yesno "Do you want to choose which Oblivious DNS-over-HTTPS DNS servers to enable?"; then ODOH_ENABLE="true"; else ODOH_ENABLE="false"; fi if [ "${ODOH_ENABLE}" = "true" ]; then choose_dnscrypt_server_odoh; elif [ "${ODOH_ENABLE}" = "false" ]; then toml_avars_prep odoh_servers "${ODOH_ENABLE}"; fi if read_yesno "Do you want to add any static servers?"; then ADD_STATIC="YES"; else ADD_STATIC="NO"; fi if [ "${ADD_STATIC}" = "YES" ]; then static_chosen 0; fi toml_avars_prep server_names "\"[${RESOLVERS}]\"" return fi fi local ITEM ITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/public-resolvers.md")" if PTXT "${RESOLVERS}" | grep -qoF "'${ITEM}'"; then PTXT "${INFO} ${ITEM} is already set" else if [ "${RESOLVERS}" ]; then RESOLVERS="${RESOLVERS%?}', '${ITEM}'" else RESOLVERS="'${ITEM}'" fi fi choose_dnscrypt_server_manual "${INDEX}" } choose_dnscrypt_server_odoh() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then local ORESOLVERS toml_avars_prep odoh_servers true PTXT "${INFO} Available DNS servers: " INDEX="$(awk -v PATT="odohrelay" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/odoh-servers.md" | wc -l)" awk -v PATT="odohrelay" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/odoh-servers.md" read_input_num "Please choose DNS server." 1 "${INDEX}" else if ! read_input_num "Please choose next DNS server or press n to stop." 1 "${INDEX}" n; then if [ "${ODOH_ONLY}" = "true" ]; then toml_avars_prep server_names "\"[${ORESOLVERS}]\"" dnscrypt_servers false doh_servers false require_dnssec false require_nolog false require_nofilter false; elif [ "${ODOH_ONLY}" = "false" ]; then RESOLVERS="${ORESOLVERS}, ${RESOLVERS}"; fi return fi fi local OITEM OITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="odohrelay" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/odoh-servers.md")" if PTXT "${ORESOLVERS}" | grep -qoF "'${OITEM}'"; then PTXT "${INFO} ${OITEM} is already set" else if [ "${ORESOLVERS}" ]; then ORESOLVERS="${ORESOLVERS%?}', '${OITEM}'" else ORESOLVERS="'${OITEM}'" fi fi choose_dnscrypt_server_odoh "${INDEX}" } choose_relays_automatic() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then if [ "${USE_IPV6}" = "true" ]; then USE_IPV6="NOMATCH"; else USE_IPV6="6"; fi local RELAYS PTXT "${INFO} Available Relay servers: " INDEX="$(awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/relays.md" | wc -l)" awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/relays.md" read_input_num "Please choose RELAY server" 1 "${INDEX}" else if ! read_input_num "Please choose next RELAY server or press n to stop" 1 "${INDEX}" n; then if grep -q '^odoh_servers = .*true.*' "${TOML_FILE}"; then PTXT "${INFO} Now to pick relays for Oblivious DNS-over-HTTPS DNS servers." choose_relays_automatic_odoh fi if read_yesno "Do you want to add any static relays?"; then ADD_STATIC="YES"; else ADD_STATIC="NO"; fi if [ "${ADD_STATIC}" = "YES" ]; then static_chosen_relays 0; fi toml_avars_prep routes "\"[ { server_name='*', via=[${RELAYS}] } ]\"" return fi fi local ITEM ITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/relays.md")" if PTXT "${RELAYS}" | grep -qoF "'${ITEM}'"; then PTXT "${INFO} ${ITEM} is already set." else if [ "${RELAYS}" ]; then RELAYS="${RELAYS%?}', '${ITEM}'" else RELAYS="'${ITEM}'" fi fi choose_relays_automatic "${INDEX}" } choose_relays_automatic_odoh() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then local ORELAYS PTXT "${INFO} Available Relay servers: " INDEX="$(awk -v PATT="odoh-" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/odoh-relays.md" | wc -l)" awk -v PATT="odoh-" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/odoh-relays.md" read_input_num "Please choose RELAY server" 1 "${INDEX}" else if ! read_input_num "Please choose next RELAY server or press n to stop" 1 "${INDEX}" n; then if grep -q '^dnscrypt_servers = .*false.*' "${TOML_FILE}" || [ "${COUNT}" -eq 0 ]; then toml_avars_prep routes "\"[ { server_name='*', via=[${ORELAYS}] } ]\""; else RELAYS="${ORELAYS}, ${RELAYS}"; fi return fi fi local OITEM OITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="odoh-" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/odoh-relays.md")" if PTXT "${ORELAYS}" | grep -qoF "'${OITEM}'"; then PTXT "${INFO} ${OITEM} is already set." else if [ "${ORELAYS}" ]; then ORELAYS="${ORELAYS%?}', '${OITEM}'" else ORELAYS="'${OITEM}'" fi fi choose_relays_automatic_odoh "${INDEX}" } choose_relays_automatic_wildcard() { toml_avars_prep routes "\"[ { server_name='*', via=['*'] } ]\"" } choose_relays_manual() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then if [ "${USE_IPV6}" = "true" ]; then USE_IPV6="NOMATCH"; else USE_IPV6="6"; fi local RELAYS PTXT "${INFO} Available Relay servers: " INDEX="$(awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/relays.md" | wc -l)" awk -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/relays.md" read_input_num "Please choose RELAY server" 1 "${INDEX}" else if ! read_input_num "Please choose next RELAY server or press n to stop" 1 "${INDEX}" n; then if read_yesno "Do you want to add any static relays?"; then ADD_STATIC="YES"; else ADD_STATIC="NO"; fi if [ "${ADD_STATIC}" = "YES" ]; then static_chosen_relays 0; fi if [ "${COUNT}" -eq 0 ]; then toml_avars_prep routes "\"[ { server_name='${SERVER}', via=[${RELAYS}] } ]\"" else toml_nvars_replace "} ]" "}, { server_name='${SERVER}', via=[${RELAYS}] } ]" "${TOML_FILE}" fi return fi fi local ITEM ITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="${USE_IPV6}" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/relays.md")" if PTXT "${RELAYS}" | grep -qoF "'${ITEM}'"; then PTXT "${INFO} ${ITEM} is already set." else if [ "${RELAYS}" ]; then RELAYS="${RELAYS%?}', '${ITEM}'" else RELAYS="'${ITEM}'" fi fi choose_relays_manual "${INDEX}" } choose_relays_manual_odoh() { local INDEX INDEX="$1" if [ -z "${INDEX}" ]; then local RELAYS PTXT "${INFO} Available Relay servers: " INDEX="$(awk -v PATT="odoh-" '/^## / && ($0 !~ PATT)' "${TARG_DIR}/odoh-relays.md" | wc -l)" awk -v PATT="odoh-" '/^## / && ($0 !~ PATT) {printf " "; printf ++i") "$2": "; getline; getline; print}' "${TARG_DIR}/odoh-relays.md" read_input_num "Please choose RELAY server" 1 "${INDEX}" else if ! read_input_num "Please choose next RELAY server or press n to stop" 1 "${INDEX}" n; then if read_yesno "Do you want to add any static relays?"; then ADD_STATIC="YES"; else ADD_STATIC="NO"; fi if [ "${ADD_STATIC}" = "YES" ]; then static_chosen_relays 0; fi if [ "${COUNT}" -eq 0 ]; then toml_avars_prep routes "\"[ { server_name='${SERVER}', via=[${RELAYS}] } ]\"" else toml_nvars_replace "} ]" "}, { server_name='${SERVER}', via=[${RELAYS}] } ]" "${TOML_FILE}" fi return fi fi local ITEM ITEM="$(awk -v INDEX="${CHOSEN}" -v PATT="odoh-" '/^## / && ($0 !~ PATT) {i++} i==INDEX {print $2;exit}' "${TARG_DIR}/odoh-relays.md")" if PTXT "${RELAYS}" | grep -qoF "'${ITEM}'"; then PTXT "${INFO} ${ITEM} is already set." else if [ "${RELAYS}" ]; then RELAYS="${RELAYS%?}', '${ITEM}'" else RELAYS="'${ITEM}'" fi fi choose_relays_manual_odoh "${INDEX}" } choose_relays_manual_wildcard() { if [ "${COUNT}" -eq 0 ]; then toml_avars_prep routes "\"[ { server_name='${SERVER}', via=['*'] } ]\"" else toml_nvars_replace "} ]" "}, { server_name='${SERVER}', via=['*'] } ]" "${TOML_FILE}" fi } choose_dnscrypt_binary_source() { if [ "$1" = "1" ]; then del_conf DNSCRYPT_BINARY_SOURCE fi local DNSCRYPT_BINARY_SOURCE if [ -z "${DNSCRYPT_VER}" ]; then DNSCRYPT_BINARY_SOURCE="nightly" PTXT "${WARNING} Unable to determine the developer latest dnscrypt-proxy release." \ "${INFO} Using dnscrypt-proxy-nightly." write_conf DNSCRYPT_BINARY_SOURCE "\"${DNSCRYPT_BINARY_SOURCE}\"" return fi if [ ! -f "${CONF_FILE}" ] || [ -z "$(read_conf DNSCRYPT_BINARY_SOURCE)" ]; then PTXT "${INFO} Available dnscrypt-proxy binary builds:" \ " 1) dnscrypt-proxy-nightly, built from DNSCrypt/dnscrypt-proxy master by this installer repository" \ " 2) Developer latest release (${DNSCRYPT_VER}) from DNSCrypt/dnscrypt-proxy" read_input_num "Please choose dnscrypt-proxy binary source" 1 2 case "${CHOSEN}" in 1) DNSCRYPT_BINARY_SOURCE="nightly" PTXT "${INFO} Using dnscrypt-proxy-nightly." ;; 2) DNSCRYPT_BINARY_SOURCE="release" PTXT "${INFO} Using developer latest release ${DNSCRYPT_VER}." ;; esac write_conf DNSCRYPT_BINARY_SOURCE "\"${DNSCRYPT_BINARY_SOURCE}\"" else if read_yesno "Do you want to switch dnscrypt-proxy binary sources?"; then choose_dnscrypt_binary_source 1; else PTXT "${INFO} continuing without changing binary sources."; fi fi } read_input_dns() { PTXT -n "${INPUT} $1 ${BOLD}${2}: ${NORM}" local DNS_SERVER read -r DNS_SERVER [ -z "${DNS_SERVER}" ] && DNS_SERVER="$2" if ! PTXT "${DNS_SERVER}" | grep -qoE "\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"; then PTXT "${ERROR} Invalid DNS server address entered" read_input_dns "$@" fi if [ "${DNS_SERVER1}" = "${DNS_SERVER}" ]; then PTXT "${ERROR} ${DNS_SERVER} DNS server address already entered, please try again!" read_input_dns "$@" fi case "$1" in "Default is") BOOTSTRAP="'${DNS_SERVER}:53'" PROBE="${DNS_SERVER}:53" DNS_SERVER1="${DNS_SERVER}" ;; "2nd Default is") BOOTSTRAP2="${BOOTSTRAP}, '${DNS_SERVER}:53'" ;; esac } read_input_num() { local RANGE [ -z "$4" ] && [ -z "$5" ] && [ -z "$6" ] && [ -z "$7" ] && RANGE="[${2}-${3}]" [ -n "$4" ] && [ -z "$5" ] && [ -z "$6" ] && [ -z "$7" ] && RANGE="[${2}-${3}/${4}]" [ -n "$4" ] && [ -n "$5" ] && [ -z "$6" ] && [ -z "$7" ] && RANGE="[${2}-${3}/${4}/${5}]" [ -n "$4" ] && [ -n "$5" ] && [ -n "$6" ] && [ -z "$7" ] && RANGE="[${2}-${3}/${4}/${5}/${6}]" [ -n "$4" ] && [ -n "$5" ] && [ -n "$6" ] && [ -n "$7" ] && RANGE="[${2}-${3}/${4}/${5}/${6}/${7}]" PTXT -n "${INPUT} $1, ${BOLD}${RANGE}${NORM}: " read -r CHOSEN case "$1" in "Set log level, default is 2, 0 is the most verbose") if [ -z "${CHOSEN}" ]; then CHOSEN="2"; fi ;; "Select your strategy" | "Select your mode") if [ -z "${CHOSEN}" ]; then CHOSEN="1"; fi ;; *) if [ -z "${CHOSEN}" ]; then PTXT "${ERROR} Invalid character(s) entered! Retrying..." read_input_num "$@" return fi ;; esac case "${CHOSEN}" in "$4" | "$5" | "$6" | "$7") return 1 ;; "$2" | "$3" | *) if ! PTXT "${CHOSEN}" | grep -qE '^[0-9]+$'; then PTXT "${ERROR} Invalid character(s) entered! Retrying..." read_input_num "$@" return fi if [ "${CHOSEN}" -lt "$2" ] || [ "${CHOSEN}" -gt "$3" ]; then PTXT "${ERROR} Chosen number is not in range! Retrying..." read_input_num "$@" return fi ;; esac } read_yesno() { PTXT -n "${INPUT} $1 ${BOLD}[y/n]${NORM}: " local YESNO read -r YESNO case "${YESNO}" in y | Y) return 0 ;; n | N) return 1 ;; *) PTXT "${ERROR} Invalid input!" read_yesno "$@" ;; esac } static_chosen() { local SDNSSTAMP STATICNAME if [ "$1" -eq 0 ]; then local STATICRESOLVERS [ -z "${ADD_STATIC}" ] && toml_avars_prep dnscrypt_servers true doh_servers true odoh_servers false require_dnssec false require_nolog false require_nofilter false PTXT -n "${INPUT} Please choose Static Server Name${NORM}: " read -r STATICNAME PTXT -n "${INPUT} Please enter Static Server SDNS stamp${NORM}: " read -r SDNSSTAMP else if read_yesno "Do you want to set up another Static Server?"; then ANOTHER="YES"; else ANOTHER="NO"; fi if [ "${ANOTHER}" = "YES" ]; then PTXT -n "${INPUT} Please choose Static Server Name${NORM}: " read -r STATICNAME PTXT -n "${INPUT} Please enter Static Server SDNS stamp${NORM}: " read -r SDNSSTAMP elif [ "${ANOTHER}" = "NO" ]; then PTXT "${INFO} finished static setup." [ "${ADD_STATIC}" = "YES" ] && RESOLVERS="${STATICRESOLVERS}, ${RESOLVERS}" [ -z "${ADD_STATIC}" ] && toml_avars_prep server_names "\"[${STATICRESOLVERS}]\"" return fi fi local STATIC STATIC="${STATICNAME}-Static" if PTXT "${STATICRESOLVERS}" | grep -qoF "${STATIC}"; then PTXT "${INFO} ${STATIC} is already set" else toml_nvars_insert "[static]" "[static.'${STATICNAME}-Static']" "${TOML_FILE}" toml_nvars_insert "[static.'${STATICNAME}-Static']" "stamp = '${SDNSSTAMP}'" "${TOML_FILE}" if [ "${STATICRESOLVERS}" ]; then STATICRESOLVERS="${STATICRESOLVERS%?}', '${STATIC}'" else STATICRESOLVERS="'${STATIC}'" fi fi if read_yesno "Is ${STATIC} a DNSCrypt Server?"; then DNSCRYPT_STATIC="true"; else DNSCRYPT_STATIC="false"; fi if [ "${DNSCRYPT_STATIC}" = "true" ]; then if [ -z "${STAT_CRYPT}" ]; then STAT_CRYPT="${STATIC}" else STAT_CRYPT="${STAT_CRYPT}|${STATIC}" fi else if read_yesno "Is ${STATIC} an Oblivious DNS-over-HTTPS Server?"; then ODOH_ENABLE="true"; else ODOH_ENABLE="false"; fi if [ "${ODOH_ENABLE}" = "true" ]; then if [ -z "${STAT_ODOH}" ]; then if grep -q '^odoh_servers = .*false.*' "${TOML_FILE}"; then toml_avars_prep odoh_servers true; fi STAT_ODOH="${STATIC}" else STAT_ODOH="${STAT_ODOH}|${STATIC}" fi fi fi static_chosen 1 } static_chosen_relays() { local SDNSSTAMP STATICNAME if [ "$1" -eq 0 ]; then local STATICRELAYS PTXT -n "${INPUT} Please choose Static Relay Name${NORM}: " read -r STATICNAME PTXT -n "${INPUT} Please enter Static Relay SDNS stamp${NORM}: " read -r SDNSSTAMP else if read_yesno "Do you want to set up another Static Relay?"; then ANOTHER="YES"; else ANOTHER="NO"; fi if [ "${ANOTHER}" = "YES" ]; then PTXT -n "${INPUT} Please choose Static Relay Name${NORM}: " read -r STATICNAME PTXT -n "${INPUT} Please enter Static Relay SDNS stamp${NORM}: " read -r SDNSSTAMP elif [ "${ANOTHER}" = "NO" ]; then PTXT "${INFO} finished static setup." RELAYS="${STATICRELAYS}, ${RELAYS}" return fi fi local STATIC STATIC="${STATICNAME}-Static" if PTXT "${STATICRELAYS}" | grep -qoF "${STATIC}"; then PTXT "${INFO} ${STATIC} is already set" else toml_nvars_insert "[static]" "[static.'${STATICNAME}-Static']" "${TOML_FILE}" toml_nvars_insert "[static.'${STATICNAME}-Static']" "stamp = '${SDNSSTAMP}'" "${TOML_FILE}" if [ "${STATICRELAYS}" ]; then STATICRELAYS="${STATICRELAYS%?}', '${STATIC}'" else STATICRELAYS="'${STATIC}'" fi fi static_chosen_relays 1 } # Process and time helpers kill_processes() { local PID PIDS PROCESS for PROCESS in "$@"; do PIDS="$(pidof "${PROCESS}" 2>/dev/null)" for PID in ${PIDS}; do kill -s 9 "${PID}" 2>/dev/null done done killall -q -9 "$@" 2>/dev/null } monotonic_seconds() { local uptime if read -r uptime _ >"$2" } toml_nvars_delete() { PATTERN="$(_quote "$1")" sed -i "/${PATTERN}/d" "$2" } toml_nvars_insert() { PATTERN="$(_quote "$1")" CONTENT="$(_quote "$2")" sed -i "/${PATTERN}/a${CONTENT}" "$3" } toml_nvars_replace() { PATTERN="$(_quote "$1")" CONTENT="$(_quote "$2")" sed -i "s/${PATTERN}/${CONTENT}/" "$3" } toml_static_removal() { PTXT "${INFO} Removing any static server configuration." toml_nvars_delete "[static.'" "${TOML_FILE}" toml_nvars_delete "stamp =" "${TOML_FILE}" } # Main menu menu() { trap - HUP INT QUIT ABRT TERM case "$1" in "") PTXT "${INFO} Choose what you want to do:" \ " 1) Install/Update dnscrypt-proxy" \ " 2) Uninstall dnscrypt-proxy" \ " 3) Configure dnscrypt-proxy" \ " 4) Set timezone" \ " 5) Unset timezone" \ " 6) Install (P)RNG" \ " 7) Uninstall (P)RNG" \ " 8) Install swap file" \ " 9) Uninstall ALL" if { [ -d "${TARG_DIR}" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ]; }; then { PTXT " a) Enable/Disable AMTM updates" " b) Backup"; }; fi if { [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; }; then { PTXT " r) Restore"; }; fi PTXT " q) Quit" if { [ ! -d "${TARG_DIR}" ] || [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; } && [ ! -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then { read_input_num "Please enter the number that designates your selection:" 1 9 q; }; fi if { [ ! -d "${TARG_DIR}" ] || [ ! -f "${TARG_DIR}/dnscrypt-proxy" ]; } && [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; then { read_input_num "Please enter the number that designates your selection:" 1 9 r q; }; fi if { [ -d "${TARG_DIR}" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ] && [ ! -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; }; then { read_input_num "Please enter the number that designates your selection:" 1 9 a b q; }; fi if { [ -d "${TARG_DIR}" ] && [ -f "${TARG_DIR}/dnscrypt-proxy" ] && [ -f "${BASE_DIR}/backup_dnscrypt.tar.gz" ]; }; then { read_input_num "Please enter the number that designates your selection:" 1 9 a b r q; }; fi ;; *) CHOSEN="$1" ;; esac [ -n "${CHOSEN}" ] && trap 'clear; end_op_message 2' HUP INT QUIT ABRT TERM case "${CHOSEN}" in "1" | "install" | "update") if [ "${CHOSEN}" = "update" ]; then AUTO_UPDATE="update" inst_dnscrypt "${AUTO_UPDATE:-update}" else PTXT "${INFO} This operation will install dnscrypt-proxy and related files (<6MB)" \ "${INFO} to jffs, no other data will be changed." \ "${INFO} Also some start scripts will be installed/modified as required." if read_yesno "Do you want to install dnscrypt-proxy to /jffs?"; then inst_dnscrypt "${AUTO_UPDATE:-install}"; else end_op_message 1; fi fi ;; "2" | "uninstall") PTXT "${INFO} This operation will uninstall dnscrypt-proxy and related files" \ "${INFO} from jffs, no other data will be changed." \ "${INFO} Also some start scripts will be modified as required." if read_yesno "Do you want to uninstall dnscrypt-proxy from /jffs?"; then uninst_dnscrypt; else end_op_message 1; fi ;; "3" | "configure") PTXT "${INFO} This operation allows you to configure dnscrypt-proxy" if read_yesno "Do you want to proceed?"; then setup_dnscrypt reconfig; else end_op_message 1; fi ;; "4" | "setTZ") PTXT "${INFO} This operation allows you to set your router timezone for background services and processes." if read_yesno "Do you want to proceed?"; then set_timezone; else end_op_message 1; fi ;; "5" | "unsetTZ") PTXT "${INFO} This operation allows you to unset your router timezone for background services and processes." if read_yesno "Do you want to proceed?"; then unset_timezone; else end_op_message 1; fi ;; "6" | "instRNG") PTXT "${INFO} This operation will install a (P)RNG (<0.5MB) to jffs, no other data will be changed." \ "${INFO} Also some start scripts will be installed/modified as required." if read_yesno "Do you want to install (P)RNG to /jffs?"; then inst_random; else end_op_message 1; fi ;; "7" | "unstRNG") PTXT "${INFO} This operation will uninstall (P)RNG" \ "${INFO} from jffs, no other data will be changed." \ "${INFO} Also some start scripts will be installed/modified as required." if read_yesno "Do you want to uninstall (P)RNG from /jffs?"; then uninst_random; else end_op_message 1; fi ;; "8" | "instSWAP") PTXT "${INFO} This operation will install a swap file for your device." \ "${INFO} You need an external USB storage to host this file." if read_yesno "Do you want to install a swap file (512MB on ext filesystem partition)?"; then check_swap; else end_op_message 1; fi ;; "9" | "unstALL") PTXT "${INFO} This operation will cleanup everything installed by this script (except swap)." if read_yesno "Do you want to continue?"; then uninst_all; else end_op_message 1; fi ;; "a" | "A" | "setAMTMUPDATE") PTXT "${INFO} This operation allows you to enable or disable AMTM's ability to manage updates for this script and by extension, Dnscrypt-Proxy." PTXT "${INFO} If the option is already disabled and you choose to proceed, then you will be enabling." PTXT "${INFO} The same is true if the opposite is true and you choose to proceed." if read_yesno "Do you want to proceed?"; then setup_amtmupdate; else end_op_message 1; fi ;; "b" | "B" | "backup") PTXT "${INFO} This operation will backup everything!" if read_yesno "Do you want to continue?"; then backup_restore BACKUP; else end_op_message 1; fi ;; "r" | "R" | "restore") PTXT "${INFO} This operation will restore everything!" if read_yesno "Do you want to continue?"; then backup_restore RESTORE; else end_op_message 1; fi ;; "q" | "Q") PTXT "${INFO} Operations have been applied if any has been made" \ "${INFO} In case of anomaly, please reboot your router!" if [ -f "${HOME}/installer" ]; then rm -rf "${HOME}/installer"; fi sleep 3s clear ;; esac } trap 'on_installer_exit' EXIT varcnt=0 readonly MAX_RETRIES="1" until [ -n "${DNSCRYPT_VER}" ]; do collect_dnscrypt_release_metadata if [ -n "${DNSCRYPT_VER}" ]; then break fi if [ "${varcnt}" -gt "${MAX_RETRIES}" ]; then PTXT "${WARNING} Unable to determine the developer latest dnscrypt-proxy release." "The github API, github releases/latest redirect, and github releases.atom metadata checks did not return a usable version." "The installer can still use dnscrypt-proxy-nightly if network access to the installer repository is available." DNSCRYPT_VER="" break fi varcnt="$((varcnt + 1))" done cleanup_api_files wait unset varcnt readonly DNSCRYPT_VER readonly DNSCRYPT_VER_SOURCE readonly DNSCRYPT_VER_API readonly DNSCRYPT_VER_REDIRECT readonly DNSCRYPT_VER_ATOM case "${1}" in "amtmupdate") BRANCH="$(read_conf INSTALLER_BRANCH)" [ -n "${BRANCH}" ] && BRANCH="$(sanitize_branch "${BRANCH}")" || BRANCH="master" case "$2" in "check") AMTM_UPDATE="$(read_conf AMTM_UPDATE)" if [ "${AMTM_UPDATE}" = "DISABLED" ] || [ -z "${AMTM_UPDATE}" ]; then exit 1 elif [ "${AMTM_UPDATE}" = "ENABLED" ]; then exit 0 fi ;; "") CHOSEN="${1#amtm}" set -- "$BRANCH" "$CHOSEN" ;; esac ;; "") BRANCH="master" ;; *) BRANCH="${1}" ;; esac BRANCH="$(sanitize_branch "${BRANCH}")" write_conf INSTALLER_BRANCH "\"${BRANCH}\"" [ -z "$(nvram get odmpid)" ] && ROUTER_MODEL="$(nvram get productid)" || ROUTER_MODEL="$(nvram get odmpid)" RURL="https://raw.githubusercontent.com/thuantran/dnscrypt-asuswrt-installer/${BRANCH}" URL_GEN="${RURL}/gen" ROUTER_OS="$(uname)" ROUTER_ARCH="$(uname -m)" [ -z "${ROUTER_MODEL}" ] && PTXT "${ERROR} This is an unsupported router, sorry." && sleep 3s && exit 1 [ "$(nvram get sw_mode)" != "1" ] && PTXT "${ERROR} You are not running in router mode, sorry." && sleep 3s && exit 1 if [ -z "$2" ]; then printf '\e[8;50;125t' printf '\033[?7l' clear sed -n '2,21p' "$0" printf '\033[?7h' fi case "${ROUTER_MODEL}" in #RT-AX56U|RT-AX58U|RT-AX3000) # PTXT "${ERROR} This is an unsupported router, sorry." # exit 1 # ;; *) [ -z "$2" ] && PTXT "${INFO} Detected ${ROUTER_MODEL} router." ;; esac case "${ROUTER_OS}" in "Linux") [ -z "$2" ] && PTXT "${INFO} Detected ${ROUTER_OS} platform." ROUTER_OS="linux" ;; *) PTXT "${ERROR} This is an unsupported platform, sorry." exit 1 ;; esac case "${ROUTER_ARCH}" in "aarch64" | "arm64") ROUTER_ARCH="arm64" URL_ARCH="${RURL}/armv8" DNSCRYPT_ARCH="${ROUTER_OS}_${ROUTER_ARCH}" DNSCRYPT_ARCH_TAR="${ROUTER_OS}-${ROUTER_ARCH}" [ -z "$2" ] && PTXT "${INFO} Detected ARMv8 architecture." ;; "armv7l") ROUTER_ARCH="arm" URL_ARCH="${RURL}/armv7" DNSCRYPT_ARCH="${ROUTER_OS}_${ROUTER_ARCH}" DNSCRYPT_ARCH_TAR="${ROUTER_OS}-${ROUTER_ARCH}" [ -z "$2" ] && PTXT "${INFO} Detected ARMv7 architecture." ;; *) PTXT "${ERROR} This is an unsupported architecture, sorry." exit 1 ;; esac prepare_dnscrypt_download_vars case "$2" in "") cleanup check_jffs_enabled check_dns_environment 0 check_version menu ;; [1-9] | "install" | "update" | "uninstall" | "configure" | "setTZ" | "unsetTZ" | "instRNG" | "unstRNG" | "instSWAP" | "unstALL" | [aA] | "setAMTMUPDATE" | [bB] | "backup" | [rR] | "restore") menu "$2" ;; *) PTXT "${INFO} Usage: sh installer {master|dev?|""} (1 - {install/update} | 2 - uninstall | 3 - configure | 4 - setTZ | 5 - unsetTZ | 6 - instRNG | 7 - unstRNG | 8 - instSWAP | 9 - unstALL | {a/A} - setAMTMUPDATE | {b/B} - backup | {r/R} - restore)" \ "${INFO} Branch or Tag must be represented by a value or empty quotes in place of string e.g. \"\" in the \$1 string position." \ "${INFO} Action must be represented by a usage value in the \$2 string position." \ "${INFO} An update example: sh installer master update, or just use the regular menu by not specifying an action e.g: sh installer master." ;; esac