#!/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