1151 lines
29 KiB
Bash
Executable File
1151 lines
29 KiB
Bash
Executable File
#!/bin/sh
|
|
export RUN_COMMAND=$1
|
|
|
|
main() {
|
|
OS=$(detect_os)
|
|
GOARCH=$(detect_goarch)
|
|
GOOS=$(detect_goos)
|
|
NEXTDNS_BIN=$(bin_location)
|
|
INSTALL_RELEASE=$(get_release)
|
|
|
|
export NEXTDNS_INSTALLER=1
|
|
|
|
log_info "OS: $OS"
|
|
log_info "GOARCH: $GOARCH"
|
|
log_info "GOOS: $GOOS"
|
|
log_info "NEXTDNS_BIN: $NEXTDNS_BIN"
|
|
log_info "INSTALL_RELEASE: $INSTALL_RELEASE"
|
|
|
|
if [ -z "$OS" ] || [ -z "$GOARCH" ] || [ -z "$GOOS" ] || [ -z "$NEXTDNS_BIN" ] || [ -z "$INSTALL_RELEASE" ]; then
|
|
log_error "Cannot detect running environment."
|
|
exit 1
|
|
fi
|
|
|
|
case "$RUN_COMMAND" in
|
|
install|upgrade|uninstall|configure) "$RUN_COMMAND"; exit ;;
|
|
esac
|
|
|
|
while true; do
|
|
CURRENT_RELEASE=$(get_current_release)
|
|
log_debug "Start install loop with CURRENT_RELEASE=$CURRENT_RELEASE"
|
|
|
|
if [ "$CURRENT_RELEASE" ]; then
|
|
if ! is_version_current; then
|
|
log_debug "NextDNS is out of date ($CURRENT_RELEASE != $INSTALL_RELEASE)"
|
|
menu \
|
|
u "Upgrade NextDNS from $CURRENT_RELEASE to $INSTALL_RELEASE" upgrade \
|
|
c "Configure NextDNS" configure \
|
|
r "Remove NextDNS" uninstall \
|
|
e "Exit" exit
|
|
else
|
|
log_debug "NextDNS is up to date ($CURRENT_RELEASE)"
|
|
menu \
|
|
c "Configure NextDNS" configure \
|
|
r "Remove NextDNS" uninstall \
|
|
e "Exit" exit
|
|
fi
|
|
else
|
|
log_debug "NextDNS is not installed"
|
|
menu \
|
|
i "Install NextDNS" install \
|
|
e "Exit" exit
|
|
fi
|
|
done
|
|
}
|
|
|
|
install() {
|
|
if [ "$(get_current_release)" ]; then
|
|
log_info "Already installed"
|
|
return
|
|
fi
|
|
if type=$(install_type); then
|
|
log_info "Installing NextDNS..."
|
|
log_debug "Using $type install type"
|
|
if "install_$type"; then
|
|
if [ ! -x "$NEXTDNS_BIN" ]; then
|
|
log_error "Installation failed: binary not installed in $NEXTDNS_BIN"
|
|
return 1
|
|
fi
|
|
# configure
|
|
post_install
|
|
exit 0
|
|
fi
|
|
else
|
|
return $?
|
|
fi
|
|
}
|
|
|
|
upgrade() {
|
|
if [ "$(get_current_release)" = "$INSTALL_RELEASE" ]; then
|
|
log_info "Already on the latest version"
|
|
return
|
|
fi
|
|
if type=$(install_type); then
|
|
log_info "Upgrading NextDNS..."
|
|
log_debug "Using $type install type"
|
|
"upgrade_$type"
|
|
else
|
|
return $?
|
|
fi
|
|
}
|
|
|
|
uninstall() {
|
|
if type=$(install_type); then
|
|
log_info "Uninstalling NextDNS..."
|
|
log_debug "Using $type uninstall type"
|
|
"uninstall_$type"
|
|
else
|
|
return $?
|
|
fi
|
|
}
|
|
|
|
precheck() {
|
|
if [ -e "/data/unifi" ] && [ -f "/run/dnsfilter/dnsfilter" ]; then
|
|
log_warn "UDM Content Filtering and/or Ad Blocking feature is enabled."
|
|
log_warn "Please disable it to use NextDNS."
|
|
log_warn ""
|
|
log_warn " To disable Content Filtering, go to Settings > Network."
|
|
log_warn " For each network, set the Content Filtering feature to None."
|
|
log_warn ""
|
|
log_warn " To disable Ad Blocking, go to Settings > Application Firewall"
|
|
log_warn " In the General tab, uncheck the Ad Blocking checkbox."
|
|
log_warn ""
|
|
while [ -f "/run/dnsfilter/dnsfilter" ]; do
|
|
sleep 1
|
|
done
|
|
log_info "Content Filtering feature successfully disabled."
|
|
fi
|
|
}
|
|
|
|
configure() {
|
|
log_debug "Start configure"
|
|
precheck
|
|
args=""
|
|
add_arg() {
|
|
for value in $2; do
|
|
log_debug "Add arg -$1=$value"
|
|
args="$args -$1=$value"
|
|
done
|
|
}
|
|
add_arg_bool_ask() {
|
|
arg=$1
|
|
msg=$2
|
|
default=$3
|
|
if [ -z "$default" ]; then
|
|
default=$(get_config_bool "$arg")
|
|
fi
|
|
# shellcheck disable=SC2046
|
|
add_arg "$arg" $(ask_bool "$msg" "$default")
|
|
}
|
|
# Use profile from now on
|
|
add_arg profile "$(get_profile_id)"
|
|
|
|
doc "Sending your devices name lets you filter analytics and logs by device."
|
|
add_arg_bool_ask report-client-info 'Report device name?' true
|
|
|
|
case $(guess_host_type) in
|
|
router)
|
|
add_arg setup-router true
|
|
;;
|
|
unsure)
|
|
doc "Accept DNS request from other network hosts."
|
|
if [ "$(get_config_bool setup-router)" = "true" ]; then
|
|
router_default=true
|
|
fi
|
|
if [ "$(ask_bool 'Setup as a router?' $router_default)" = "true" ]; then
|
|
add_arg setup-router true
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
doc "Make NextDNS CLI cache responses. This improves latency and reduces the amount"
|
|
doc "of queries sent to NextDNS."
|
|
if [ "$(guess_host_type)" = "router" ]; then
|
|
doc "Note that enabling this feature will disable dnsmasq for DNS to avoid double"
|
|
doc "caching."
|
|
fi
|
|
if [ "$(get_config cache-size)" != "0" ]; then
|
|
cache_default=true
|
|
fi
|
|
if [ "$(ask_bool 'Enable caching?' $cache_default)" = "true" ]; then
|
|
add_arg cache-size "10MB"
|
|
|
|
doc "Instant refresh will force low TTL on responses sent to clients so they rely"
|
|
doc "on CLI DNS cache. This will allow changes on your NextDNS config to be applied"
|
|
doc "on your LAN hosts without having to wait for their cache to expire."
|
|
if [ "$(get_config max-ttl)" = "5s" ]; then
|
|
instant_refresh_default=true
|
|
fi
|
|
if [ "$(ask_bool 'Enable instant refresh?' $instant_refresh_default)" = "true" ]; then
|
|
add_arg max-ttl "5s"
|
|
fi
|
|
fi
|
|
|
|
if [ "$(guess_host_type)" != "router" ]; then
|
|
doc "Changes DNS settings of the host automatically when NextDNS is started."
|
|
doc "If you say no here, you will have to manually configure DNS to 127.0.0.1."
|
|
add_arg_bool_ask auto-activate 'Automatically setup local host DNS?' true
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
asroot "$NEXTDNS_BIN" install $args
|
|
}
|
|
|
|
post_install() {
|
|
println
|
|
println "Congratulations! NextDNS is now installed."
|
|
println
|
|
println "To upgrade/uninstall, run this command again and select the appropriate option."
|
|
println
|
|
println "You can use the NextDNS command to control the daemon."
|
|
println "Here are a few important commands to know:"
|
|
println
|
|
println "# Start, stop, restart the daemon:"
|
|
println "nextdns start"
|
|
println "nextdns stop"
|
|
println "nextdns restart"
|
|
println
|
|
println "# Configure the local host to point to NextDNS or not:"
|
|
println "nextdns activate"
|
|
println "nextdns deactivate"
|
|
println
|
|
println "# Explore daemon logs:"
|
|
println "nextdns log"
|
|
println
|
|
println "# For more commands, use:"
|
|
println "nextdns help"
|
|
println
|
|
}
|
|
|
|
install_bin() {
|
|
bin_path=$NEXTDNS_BIN
|
|
if [ "$1" ]; then
|
|
bin_path=$1
|
|
fi
|
|
log_debug "Installing $INSTALL_RELEASE binary for $GOOS/$GOARCH to $bin_path"
|
|
case "$INSTALL_RELEASE" in
|
|
*/*)
|
|
# Snapshot
|
|
branch=${INSTALL_RELEASE%/*}
|
|
hash=${INSTALL_RELEASE#*/}
|
|
url="https://snapshot.nextdns.io/${branch}/nextdns-${hash}_${GOOS}_${GOARCH}.tar.gz"
|
|
;;
|
|
*)
|
|
url="https://github.com/nextdns/nextdns/releases/download/v${INSTALL_RELEASE}/nextdns_${INSTALL_RELEASE}_${GOOS}_${GOARCH}.tar.gz"
|
|
;;
|
|
esac
|
|
log_debug "Downloading $url"
|
|
asroot mkdir -p "$(dirname "$bin_path")" &&
|
|
curl -sL "$url" | asroot sh -c "tar Ozxf - nextdns > \"$bin_path\"" &&
|
|
asroot chmod 755 "$bin_path"
|
|
}
|
|
|
|
upgrade_bin() {
|
|
tmp=$NEXTDNS_BIN.tmp
|
|
if install_bin "$tmp"; then
|
|
asroot "$NEXTDNS_BIN" uninstall
|
|
asroot mv "$tmp" "$NEXTDNS_BIN"
|
|
asroot "$NEXTDNS_BIN" install
|
|
fi
|
|
log_debug "Removing spurious temporary install file"
|
|
asroot rm -rf "$tmp"
|
|
}
|
|
|
|
uninstall_bin() {
|
|
asroot "$NEXTDNS_BIN" uninstall
|
|
asroot rm -f "$NEXTDNS_BIN"
|
|
}
|
|
|
|
install_rpm() {
|
|
asroot curl -Ls https://repo.nextdns.io/nextdns.repo -o /etc/yum.repos.d/nextdns.repo &&
|
|
asroot yum install -y nextdns
|
|
}
|
|
|
|
upgrade_rpm() {
|
|
asroot yum update -y nextdns
|
|
}
|
|
|
|
uninstall_rpm() {
|
|
asroot yum remove -y nextdns
|
|
}
|
|
|
|
install_zypper() {
|
|
if asroot zypper repos | grep -q nextdns >/dev/null; then
|
|
echo "Repository nextdns already exists. Skipping adding repository..."
|
|
else
|
|
asroot zypper ar -f -r https://repo.nextdns.io/nextdns.repo nextdns
|
|
fi
|
|
asroot zypper refresh && asroot zypper in -y nextdns
|
|
}
|
|
|
|
upgrade_zypper() {
|
|
asroot zypper up nextdns
|
|
}
|
|
|
|
uninstall_zypper() {
|
|
asroot zypper remove -y nextdns
|
|
case $(ask_bool 'Do you want to remove the repository from the repositories list?' true) in
|
|
true)
|
|
asroot zypper removerepo nextdns
|
|
;;
|
|
esac
|
|
}
|
|
|
|
install_deb() {
|
|
if [ -f /etc/default/ubnt-dpkg-cache ]; then
|
|
# On UnifiOS 2, make sure the package is persisted over upgrades
|
|
sed -e '/^DPKG_CACHE_UBNT_PKGS+=" nextdns"/{:a;n;ba;q}' \
|
|
-e '$aDPKG_CACHE_UBNT_PKGS+=" nextdns"' \
|
|
-i /etc/default/ubnt-dpkg-cache
|
|
fi
|
|
|
|
install_deb_keyring &&
|
|
asroot sh -c 'echo "deb [signed-by=/etc/apt/keyrings/nextdns.gpg] https://repo.nextdns.io/deb stable main" > /etc/apt/sources.list.d/nextdns.list' &&
|
|
(dpkg --compare-versions $(dpkg-query --showformat='${Version}' --show apt) ge 1.1 ||
|
|
asroot ln -s /etc/apt/keyrings/nextdns.gpg /etc/apt/trusted.gpg.d/.) &&
|
|
(test "$OS" = "debian" && asroot apt-get -y install apt-transport-https || true) &&
|
|
(asroot apt-get update || true) &&
|
|
asroot apt-get install -y nextdns
|
|
}
|
|
|
|
install_deb_keyring() {
|
|
# Fallback on curl, some debian based distrib don't have wget while debian
|
|
# doesn't have curl by default.
|
|
asroot mkdir -p /etc/apt/keyrings
|
|
( asroot wget -qO /etc/apt/keyrings/nextdns.gpg https://repo.nextdns.io/nextdns.gpg ||
|
|
asroot curl -sfL https://repo.nextdns.io/nextdns.gpg -o /etc/apt/keyrings/nextdns.gpg ) &&
|
|
asroot chmod 0644 /etc/apt/keyrings/nextdns.gpg
|
|
}
|
|
|
|
upgrade_deb() {
|
|
install_deb_keyring &&
|
|
(asroot apt-get update || true) &&
|
|
asroot apt-get install -y nextdns
|
|
}
|
|
|
|
uninstall_deb() {
|
|
asroot apt-get remove -y nextdns
|
|
}
|
|
|
|
install_apk() {
|
|
repo=https://repo.nextdns.io/apk
|
|
asroot wget -O /etc/apk/keys/nextdns.pub https://repo.nextdns.io/nextdns.pub &&
|
|
(grep -v $repo /etc/apk/repositories; echo $repo) | asroot tee /etc/apk/repositories >/dev/null &&
|
|
asroot apk update &&
|
|
asroot apk add nextdns
|
|
}
|
|
|
|
upgrade_apk() {
|
|
asroot apk update && asroot apk upgrade nextdns
|
|
}
|
|
|
|
uninstall_apk() {
|
|
asroot apk del nextdns
|
|
}
|
|
|
|
install_arch() {
|
|
asroot pacman -Sy yay &&
|
|
yay -Sy nextdns
|
|
}
|
|
|
|
upgrade_arch() {
|
|
yay -Suy nextdns
|
|
}
|
|
|
|
uninstall_arch() {
|
|
asroot pacman -R nextdns
|
|
}
|
|
|
|
install_merlin_path() {
|
|
# Add next to Merlin's path
|
|
mkdir -p /tmp/opt/sbin
|
|
ln -sf "$NEXTDNS_BIN" /tmp/opt/sbin/nextdns
|
|
}
|
|
|
|
install_merlin() {
|
|
if install_bin; then
|
|
install_merlin_path
|
|
fi
|
|
}
|
|
|
|
uninstall_merlin() {
|
|
uninstall_bin
|
|
rm -f /tmp/opt/sbin/nextdns
|
|
}
|
|
|
|
upgrade_merlin() {
|
|
if upgrade_bin; then
|
|
install_merlin_path
|
|
fi
|
|
}
|
|
|
|
install_openwrt() {
|
|
opkg update &&
|
|
opkg install nextdns
|
|
rt=$?
|
|
if [ $rt -eq 0 ]; then
|
|
case $(ask_bool 'Install the GUI?' true) in
|
|
true)
|
|
opkg install luci-app-nextdns
|
|
rt=$?
|
|
;;
|
|
esac
|
|
fi
|
|
return $rt
|
|
}
|
|
|
|
upgrade_openwrt() {
|
|
opkg update &&
|
|
opkg upgrade nextdns
|
|
}
|
|
|
|
uninstall_openwrt() {
|
|
opkg remove nextdns
|
|
}
|
|
|
|
install_ddwrt() {
|
|
if [ "$(nvram get enable_jffs2)" = "0" ]; then
|
|
log_error "JFFS support not enabled"
|
|
log_info "To enabled JFFS:"
|
|
log_info " 1. On the router web page click on Administration."
|
|
log_info " 2. Scroll down until you see JFFS2 Support section."
|
|
log_info " 3. Click Enable JFFS."
|
|
log_info " 4. Click Save."
|
|
log_info " 5. Wait couple seconds, then click Apply."
|
|
log_info " 6. Wait again. Go back to the Enable JFFS section, and enable Clean JFFS."
|
|
log_info " 7. Do not click Save. Click Apply instead."
|
|
log_info " 8. Wait till you get the web-GUI back, then disable Clean JFFS again."
|
|
log_info " 9. Click Save."
|
|
log_info "10. Relaunch this installer."
|
|
exit 1
|
|
fi
|
|
mkdir -p /jffs/nextdns &&
|
|
openssl_get https://curl.haxx.se/ca/cacert.pem | http_body > /jffs/nextdns/ca.pem &&
|
|
install_bin
|
|
}
|
|
|
|
upgrade_ddwrt() {
|
|
upgrade_bin
|
|
}
|
|
|
|
uninstall_ddwrt() {
|
|
uninstall_bin
|
|
rm -rf /jffs/nextdns
|
|
}
|
|
|
|
install_brew() {
|
|
silent_exec brew install nextdns/tap/nextdns
|
|
}
|
|
|
|
upgrade_brew() {
|
|
silent_exec brew upgrade nextdns/tap/nextdns
|
|
asroot "$NEXTDNS_BIN" install
|
|
}
|
|
|
|
uninstall_brew() {
|
|
silent_exec brew uninstall nextdns/tap/nextdns
|
|
}
|
|
|
|
install_freebsd() {
|
|
# TODO: port install
|
|
install_bin
|
|
}
|
|
|
|
upgrade_freebsd() {
|
|
# TODO: port upgrade
|
|
upgrade_bin
|
|
}
|
|
|
|
uninstall_freebsd() {
|
|
# TODO: port uninstall
|
|
uninstall_bin
|
|
}
|
|
|
|
install_pfsense() {
|
|
# TODO: port install + UI
|
|
install_bin
|
|
}
|
|
|
|
upgrade_pfsense() {
|
|
# TODO: port upgrade
|
|
upgrade_bin
|
|
}
|
|
|
|
uninstall_pfsense() {
|
|
# TODO: port uninstall
|
|
uninstall_bin
|
|
}
|
|
|
|
install_opnsense() {
|
|
# TODO: port install + UI
|
|
install_bin
|
|
}
|
|
|
|
upgrade_opnsense() {
|
|
# TODO: port upgrade
|
|
upgrade_bin
|
|
}
|
|
|
|
uninstall_opnsense() {
|
|
# TODO: port uninstall
|
|
uninstall_bin
|
|
}
|
|
|
|
ubios_install_source() {
|
|
echo "deb [signed-by=/etc/apt/keyrings/nextdns.gpg] https://repo.nextdns.io/deb stable main" > /data/nextdns.list
|
|
podman exec unifi-os mv /data/nextdns.list /etc/apt/sources.list.d/nextdns.list
|
|
rm -f /tmp/nextdns.list
|
|
podman exec unifi-os apt-get install -y gnupg1 curl
|
|
podman exec unifi-os mkdir -p /etc/apt/keyrings/
|
|
podman exec unifi-os curl -sfL https://repo.nextdns.io/nextdns.gpg -o /etc/apt/keyrings/nextdns.gpg
|
|
podman exec unifi-os apt-get update -o Dir::Etc::sourcelist="sources.list.d/nextdns.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" || true
|
|
}
|
|
|
|
install_ubios() {
|
|
ubios_install_source
|
|
podman exec unifi-os apt-get install -y nextdns
|
|
}
|
|
|
|
upgrade_ubios() {
|
|
ubios_install_source
|
|
podman exec unifi-os apt-get install --only-upgrade -y nextdns
|
|
}
|
|
|
|
uninstall_ubios() {
|
|
podman exec unifi-os apt-get remove -y nextdns
|
|
}
|
|
|
|
install_ubios_snapshot() {
|
|
branch=${INSTALL_RELEASE%/*}
|
|
hash=${INSTALL_RELEASE#*/}
|
|
url="https://snapshot.nextdns.io/${branch}/nextdns-${hash}_${GOOS}_${GOARCH}.tar.gz"
|
|
podman exec unifi-os sh -c "curl -o- $url | tar Ozxf - nextdns > /usr/bin/nextdns; /usr/bin/nextdns install"
|
|
}
|
|
|
|
upgrade_ubios_snapshot() {
|
|
/data/nextdns uninstall
|
|
install_ubios_snapshot
|
|
}
|
|
|
|
install_type() {
|
|
if [ "$FORCE_INSTALL_TYPE" ]; then
|
|
echo "$FORCE_INSTALL_TYPE"; return 0
|
|
fi
|
|
case "$INSTALL_RELEASE" in
|
|
*/*)
|
|
case $OS in
|
|
ubios)
|
|
echo "ubios_snapshot"; return 0
|
|
;;
|
|
*)
|
|
# Snapshot mode always use binary install
|
|
echo "bin"; return 0
|
|
;;
|
|
esac
|
|
esac
|
|
case $OS in
|
|
centos|fedora|rhel)
|
|
echo "rpm"
|
|
;;
|
|
opensuse-tumbleweed|opensuse-leap|opensuse)
|
|
echo "zypper"
|
|
;;
|
|
debian|ubuntu|elementary|raspbian|linuxmint|pop|neon|sparky|vyos|Deepin)
|
|
echo "deb"
|
|
;;
|
|
alpine)
|
|
echo "apk"
|
|
;;
|
|
arch|manjaro|steamos)
|
|
#echo "arch" # TODO: fix AUR install
|
|
echo "bin"
|
|
;;
|
|
openwrt)
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
major=$(echo "$VERSION_ID" | cut -d. -f1)
|
|
case $major in
|
|
*[!0-9]*)
|
|
if [ "$VERSION_ID" = "19.07.0-rc1" ]; then
|
|
# No opkg support before 19.07.0-rc2
|
|
echo "bin"
|
|
else
|
|
# Likely 'snapshot' build in this case, but still > major version 19
|
|
echo "openwrt"
|
|
fi
|
|
;;
|
|
*)
|
|
if [ "$major" -lt 19 ]; then
|
|
# No opkg support before 19.07.0-rc2
|
|
echo "bin"
|
|
else
|
|
echo "openwrt"
|
|
fi
|
|
;;
|
|
esac
|
|
;;
|
|
asuswrt-merlin)
|
|
echo "merlin"
|
|
;;
|
|
edgeos|synology|clear-linux-os|solus|openbsd|netbsd|overthebox)
|
|
echo "bin"
|
|
;;
|
|
ddwrt)
|
|
echo "ddwrt"
|
|
;;
|
|
darwin)
|
|
if [ -x /usr/local/bin/brew ] || [ -x /opt/homebrew/bin/brew ]; then
|
|
echo "brew"
|
|
else
|
|
log_debug "Homebrew not installed, fallback on binary install"
|
|
echo "bin"
|
|
fi
|
|
;;
|
|
freebsd)
|
|
echo "freebsd"
|
|
;;
|
|
pfsense)
|
|
echo "pfsense"
|
|
;;
|
|
opnsense)
|
|
echo "opnsense"
|
|
;;
|
|
ubios)
|
|
echo "ubios"
|
|
;;
|
|
gentoo)
|
|
echo "bin"
|
|
;;
|
|
void)
|
|
# TODO: pkg for xbps
|
|
echo "bin"
|
|
;;
|
|
*)
|
|
log_error "Unsupported installation for $(detect_os)"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_config() {
|
|
"$NEXTDNS_BIN" config | grep -E "^$1 " | cut -d' ' -f 2
|
|
}
|
|
|
|
get_config_bool() {
|
|
val=$(get_config "$1")
|
|
case $val in
|
|
true|false)
|
|
echo "$val"
|
|
;;
|
|
esac
|
|
echo "$2"
|
|
}
|
|
|
|
get_profile_id() {
|
|
log_debug "Get profile ID"
|
|
if [ "$CONFIG_ID" ]; then
|
|
# backward compat
|
|
PROFILE_ID="$CONFIG_ID"
|
|
fi
|
|
while [ -z "$PROFILE_ID" ]; do
|
|
default=
|
|
prev_id=$(get_config profile)
|
|
if [ -z "$prev_id" ]; then
|
|
# backward compat
|
|
prev_id=$(get_config config)
|
|
fi
|
|
if [ "$prev_id" ]; then
|
|
log_debug "Previous profile ID: $prev_id"
|
|
default=" (default=$prev_id)"
|
|
fi
|
|
print "NextDNS Profile ID%s: " "$default"
|
|
read -r id
|
|
if [ -z "$id" ]; then
|
|
id=$prev_id
|
|
fi
|
|
if echo "$id" | grep -qE '^[0-9a-f]{6}$'; then
|
|
PROFILE_ID=$id
|
|
break
|
|
else
|
|
log_error "Invalid profile ID."
|
|
println
|
|
println "ID format is 6 alphanumerical lowercase characters (example: 123abc)."
|
|
println "Your ID can be found on the Setup tab of https://my.nextdns.io."
|
|
println
|
|
fi
|
|
done
|
|
echo "$PROFILE_ID"
|
|
}
|
|
|
|
log_debug() {
|
|
if [ "$DEBUG" = "1" ]; then
|
|
printf "\033[30;1mDEBUG: %s\033[0m\n" "$*" >&2
|
|
fi
|
|
}
|
|
|
|
log_info() {
|
|
printf "INFO: %s\n" "$*" >&2
|
|
}
|
|
|
|
log_warn() {
|
|
printf "\033[33mWARN: %s\033[0m\n" "$*" >&2
|
|
}
|
|
|
|
log_error() {
|
|
printf "\033[31mERROR: %s\033[0m\n" "$*" >&2
|
|
}
|
|
|
|
print() {
|
|
format=$1
|
|
if [ $# -gt 0 ]; then
|
|
shift
|
|
fi
|
|
# shellcheck disable=SC2059
|
|
printf "$format" "$@" >&2
|
|
}
|
|
|
|
println() {
|
|
format=$1
|
|
if [ $# -gt 0 ]; then
|
|
shift
|
|
fi
|
|
# shellcheck disable=SC2059
|
|
printf "$format\n" "$@" >&2
|
|
}
|
|
|
|
doc() {
|
|
# shellcheck disable=SC2059
|
|
printf "\033[30;1m%s\033[0m\n" "$*" >&2
|
|
}
|
|
|
|
menu() {
|
|
while true; do
|
|
n=0
|
|
default=
|
|
for item in "$@"; do
|
|
case $((n%3)) in
|
|
0)
|
|
key=$item
|
|
if [ -z "$default" ]; then
|
|
default=$key
|
|
fi
|
|
;;
|
|
1)
|
|
echo "$key) $item"
|
|
;;
|
|
esac
|
|
n=$((n+1))
|
|
done
|
|
print "Choice (default=%s): " "$default"
|
|
read -r choice
|
|
if [ -z "$choice" ]; then
|
|
choice=$default
|
|
fi
|
|
n=0
|
|
for item in "$@"; do
|
|
case $((n%3)) in
|
|
0)
|
|
key=$item
|
|
;;
|
|
2)
|
|
if [ "$key" = "$choice" ]; then
|
|
if ! "$item"; then
|
|
log_error "$item: exit $?"
|
|
fi
|
|
break 2
|
|
fi
|
|
;;
|
|
esac
|
|
n=$((n+1))
|
|
done
|
|
echo "Invalid choice"
|
|
done
|
|
}
|
|
|
|
ask_bool() {
|
|
msg=$1
|
|
default=$2
|
|
case $default in
|
|
true)
|
|
msg="$msg [Y|n]: "
|
|
;;
|
|
false)
|
|
msg="$msg [y|N]: "
|
|
;;
|
|
*)
|
|
msg="$msg (y/n): "
|
|
esac
|
|
while true; do
|
|
print "%s" "$msg"
|
|
read -r answer
|
|
if [ -z "$answer" ]; then
|
|
answer=$default
|
|
fi
|
|
case $answer in
|
|
y|Y|yes|YES|true)
|
|
echo "true"
|
|
return 0
|
|
;;
|
|
n|N|no|NO|false)
|
|
echo "false"
|
|
return 0
|
|
;;
|
|
*)
|
|
echo "Invalid input, use yes or no"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
detect_endiannes() {
|
|
if ! hexdump /dev/null 2>/dev/null; then
|
|
# Some firmwares do not contain hexdump, for those, try to detect endianness
|
|
# differently.
|
|
case $(cat /proc/cpuinfo) in
|
|
*BCM5300*)
|
|
# RT-AC66U does not support Merlin version over 380.70 which
|
|
# lacks hexdump command.
|
|
echo "le"
|
|
;;
|
|
*)
|
|
log_error "Cannot determine endianness"
|
|
return 1
|
|
;;
|
|
esac
|
|
return 0
|
|
fi
|
|
case $(hexdump -s 5 -n 1 -e '"%x"' /bin/sh | head -c1) in
|
|
1)
|
|
echo "le"
|
|
;;
|
|
2)
|
|
echo ""
|
|
;;
|
|
esac
|
|
}
|
|
|
|
detect_goarch() {
|
|
if [ "$FORCE_GOARCH" ]; then
|
|
echo "$FORCE_GOARCH"; return 0
|
|
fi
|
|
case $(uname -m) in
|
|
x86_64|amd64)
|
|
echo "amd64"
|
|
;;
|
|
i386|i686)
|
|
echo "386"
|
|
;;
|
|
arm)
|
|
# FreeBSD does not include arm version
|
|
case "$(sysctl -b hw.model 2>/dev/null)" in
|
|
*A9*)
|
|
echo "armv7"
|
|
;;
|
|
*)
|
|
# Unknown version, fallback to the lowest
|
|
echo "armv5"
|
|
;;
|
|
esac
|
|
;;
|
|
armv5*)
|
|
echo "armv5"
|
|
;;
|
|
armv6*|armv7*)
|
|
if grep -q vfp /proc/cpuinfo 2>/dev/null; then
|
|
echo "armv$(uname -m | sed -e 's/[[:alpha:]]//g')"
|
|
else
|
|
# Soft floating point
|
|
echo "armv5"
|
|
fi
|
|
;;
|
|
aarch64)
|
|
case "$(uname -o 2>/dev/null)" in
|
|
ASUSWRT-Merlin*)
|
|
# XXX when using arm64 build on ASUS AC66U and ACG86U, we get Go error:
|
|
# "out of memory allocating heap arena metadata".
|
|
echo "armv7"
|
|
;;
|
|
*)
|
|
echo "arm64"
|
|
;;
|
|
esac
|
|
;;
|
|
armv8*|arm64)
|
|
echo "arm64"
|
|
;;
|
|
mips*)
|
|
# TODO: detect hardfloat
|
|
echo "$(uname -m)$(detect_endiannes)_softfloat"
|
|
;;
|
|
*)
|
|
log_error "Unsupported GOARCH: $(uname -m)"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
detect_goos() {
|
|
if [ "$FORCE_GOOS" ]; then
|
|
echo "$FORCE_GOOS"; return 0
|
|
fi
|
|
case $(uname -s) in
|
|
Linux)
|
|
echo "linux"
|
|
;;
|
|
Darwin)
|
|
echo "darwin"
|
|
;;
|
|
FreeBSD)
|
|
echo "freebsd"
|
|
;;
|
|
NetBSD)
|
|
echo "netbsd"
|
|
;;
|
|
OpenBSD)
|
|
echo "openbsd"
|
|
;;
|
|
*)
|
|
log_error "Unsupported GOOS: $(uname -s)"
|
|
return 1
|
|
esac
|
|
}
|
|
|
|
detect_os() {
|
|
if [ "$FORCE_OS" ]; then
|
|
echo "$FORCE_OS"; return 0
|
|
fi
|
|
case $(uname -s) in
|
|
Linux)
|
|
case $(uname -o) in
|
|
GNU/Linux|Linux)
|
|
if grep -q -e '^EdgeRouter' -e '^UniFiSecurityGateway' /etc/version 2> /dev/null; then
|
|
echo "edgeos"; return 0
|
|
fi
|
|
if uname -u 2>/dev/null | grep -q '^synology'; then
|
|
echo "synology"; return 0
|
|
fi
|
|
# shellcheck disable=SC1091
|
|
dist=$(. /etc/os-release; echo "$ID")
|
|
case $dist in
|
|
ubios)
|
|
if [ -z "$(command -v podman)" ]; then
|
|
log_error "This version of UnifiOS is not supported. Make sure you run version 1.7.0 or above."
|
|
return 1
|
|
fi
|
|
echo "$dist"; return 0
|
|
;;
|
|
debian|ubuntu|elementary|raspbian|centos|fedora|rhel|arch|manjaro|openwrt|clear-linux-os|linuxmint|opensuse-tumbleweed|opensuse-leap|opensuse|solus|pop|neon|overthebox|sparky|vyos|void|alpine|Deepin|gentoo|steamos)
|
|
echo "$dist"; return 0
|
|
;;
|
|
esac
|
|
# shellcheck disable=SC1091
|
|
for dist in $(. /etc/os-release; echo "$ID_LIKE"); do
|
|
case $dist in
|
|
debian|ubuntu|rhel|fedora|openwrt|arch)
|
|
log_debug "Using ID_LIKE"
|
|
echo "$dist"; return 0
|
|
;;
|
|
esac
|
|
done
|
|
;;
|
|
ASUSWRT-Merlin*)
|
|
echo "asuswrt-merlin"; return 0
|
|
;;
|
|
DD-WRT)
|
|
echo "ddwrt"; return 0
|
|
esac
|
|
;;
|
|
Darwin)
|
|
echo "darwin"; return 0
|
|
;;
|
|
FreeBSD)
|
|
if [ -f /etc/platform ]; then
|
|
case $(cat /etc/platform) in
|
|
pfSense)
|
|
echo "pfsense"; return 0
|
|
;;
|
|
esac
|
|
fi
|
|
if [ -x /usr/local/sbin/opnsense-version ]; then
|
|
case $(/usr/local/sbin/opnsense-version -N) in
|
|
OPNsense)
|
|
echo "opnsense"; return 0
|
|
;;
|
|
esac
|
|
fi
|
|
echo "freebsd"; return 0
|
|
;;
|
|
NetBSD)
|
|
echo "netbsd"; return 0
|
|
;;
|
|
OpenBSD)
|
|
echo "openbsd"; return 0
|
|
;;
|
|
*)
|
|
esac
|
|
log_error "Unsupported OS: $(uname -o) $(grep ID "/etc/os-release" 2>/dev/null | xargs)"
|
|
return 1
|
|
}
|
|
|
|
guess_host_type() {
|
|
if [ -d /data/unifi ]; then
|
|
# Special case when installer is run from inside the ubios podman
|
|
echo "router"; return 0
|
|
fi
|
|
|
|
case $OS in
|
|
pfsense|opnsense|openwrt|asuswrt-merlin|edgeos|ddwrt|synology|overthebox|ubios)
|
|
echo "router"
|
|
;;
|
|
darwin|steamos)
|
|
echo "workstation"
|
|
;;
|
|
*)
|
|
echo "unsure"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
asroot() {
|
|
# Some platform (Merlin) do not have the "id" command and $USER report a non root username with uid 0.
|
|
if [ "$(grep '^Uid:' /proc/$$/status 2>/dev/null|cut -f2)" = "0" ] || [ "$USER" = "root" ] || [ "$(id -u 2>/dev/null)" = "0" ]; then
|
|
"$@"
|
|
elif [ "$(command -v sudo 2>/dev/null)" ]; then
|
|
sudo "$@"
|
|
else
|
|
echo "Root required"
|
|
su -m root -c "$*"
|
|
fi
|
|
}
|
|
|
|
silent_exec() {
|
|
if [ "$DEBUG" = 1 ]; then
|
|
"$@"
|
|
else
|
|
if ! out=$("$@" 2>&1); then
|
|
rt=$?
|
|
println "\033[30;1m%s\033[0m" "$out"
|
|
return $rt
|
|
fi
|
|
fi
|
|
}
|
|
|
|
bin_location() {
|
|
case $OS in
|
|
centos|fedora|rhel|debian|ubuntu|elementary|raspbian|arch|manjaro|clear-linux-os|linuxmint|opensuse-tumbleweed|opensuse-leap|opensuse|solus|pop|neon|sparky|vyos|void|alpine|Deepin|gentoo)
|
|
echo "/usr/bin/nextdns"
|
|
;;
|
|
openwrt|overthebox)
|
|
echo "/usr/sbin/nextdns"
|
|
;;
|
|
synology)
|
|
echo "/usr/local/bin/nextdns"
|
|
;;
|
|
darwin)
|
|
echo "$(brew --prefix 2>/dev/null || echo /usr/local)/bin/nextdns"
|
|
;;
|
|
asuswrt-merlin|ddwrt)
|
|
echo "/jffs/nextdns/nextdns"
|
|
;;
|
|
freebsd|pfsense|opnsense|netbsd|openbsd)
|
|
echo "/usr/local/sbin/nextdns"
|
|
;;
|
|
edgeos)
|
|
echo "/config/nextdns/nextdns"
|
|
;;
|
|
ubios)
|
|
echo "/data/nextdns"
|
|
;;
|
|
steamos)
|
|
echo "$HOME/.local/bin/nextdns"
|
|
;;
|
|
*)
|
|
log_error "Unknown bin location for $OS"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
is_version_current() {
|
|
case "$INSTALL_RELEASE" in
|
|
*/*)
|
|
# Snapshot
|
|
hash=${INSTALL_RELEASE#*/}
|
|
test "0.0.0-$hash" = "$CURRENT_RELEASE"
|
|
;;
|
|
*)
|
|
test "$INSTALL_RELEASE" = "$CURRENT_RELEASE"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_current_release() {
|
|
if [ -x "$NEXTDNS_BIN" ]; then
|
|
$NEXTDNS_BIN version|cut -d' ' -f 3
|
|
fi
|
|
}
|
|
|
|
get_release() {
|
|
if [ "$NEXTDNS_VERSION" ]; then
|
|
echo "$NEXTDNS_VERSION"
|
|
else
|
|
for cmd in curl wget openssl true; do
|
|
# command is the "right" way but may be compiled out of busybox shell
|
|
! command -v $cmd > /dev/null 2>&1 || break
|
|
! which $cmd > /dev/null 2>&1 || break
|
|
done
|
|
case "$cmd" in
|
|
curl) cmd="curl -A curl -s" ;;
|
|
wget) cmd="wget -qO- -U curl" ;;
|
|
openssl) cmd="openssl_get" ;;
|
|
*)
|
|
log_error "Cannot retrieve latest version"
|
|
return
|
|
;;
|
|
esac
|
|
v=$($cmd "https://api.github.com/repos/nextdns/nextdns/releases/latest" | \
|
|
grep '"tag_name":' | esed 's/.*"([^"]+)".*/\1/' | sed -e 's/^v//')
|
|
if [ -z "$v" ]; then
|
|
log_error "Cannot get latest version: $out"
|
|
fi
|
|
echo "$v"
|
|
fi
|
|
}
|
|
|
|
esed() {
|
|
if (echo | sed -E '' >/dev/null 2>&1); then
|
|
sed -E "$@"
|
|
else
|
|
sed -r "$@"
|
|
fi
|
|
}
|
|
|
|
http_redirect() {
|
|
while read -r header; do
|
|
case $header in
|
|
Location:*)
|
|
echo "${header#Location: }"
|
|
return
|
|
;;
|
|
esac
|
|
if [ "$header" = "" ]; then
|
|
break
|
|
fi
|
|
done
|
|
cat > /dev/null
|
|
return 1
|
|
}
|
|
|
|
http_body() {
|
|
sed -n '/^\r/,$p' | sed 1d
|
|
}
|
|
|
|
openssl_get() {
|
|
host=${1#https://*} # https://dom.com/path -> dom.com/path
|
|
path=/${host#*/} # dom.com/path -> /path
|
|
host=${host%$path} # dom.com/path -> dom.com
|
|
printf "GET %s HTTP/1.0\nHost: %s\nUser-Agent: curl\n\n" "$path" "$host" |
|
|
openssl s_client -quiet -connect "$host:443" 2>/dev/null
|
|
}
|
|
|
|
umask 0022
|
|
main
|