Files
Keenetic-Split-DNS/install.sh
Андрей Бобырев 66354221a4 fix: audit corrections
Fix YAML section parsing and upstream ID extraction in compile-config,
detect-lan shell syntax, lighttpd CGI modules, API reload path, install
idempotency, and dashboard log display.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 23:04:44 +03:00

162 lines
5.8 KiB
Bash
Executable File

#!/bin/sh
# Keenetic-Split-DNS — one-line installer for Keenetic + Entware
# curl -fsSL https://raw.githubusercontent.com/andrey271192/Keenetic-Split-DNS/main/install.sh | sh
set -e
KSD_VERSION="1.0.0"
KSD_ETC="/opt/etc/keenetic-split-dns"
KSD_SHARE="/opt/share/keenetic-split-dns"
KSD_VAR_LOG="/opt/var/log/keenetic-split-dns"
KSD_VAR_RUN="/opt/var/run/keenetic-split-dns"
REPO_RAW="${KSD_REPO_RAW:-https://raw.githubusercontent.com/andrey271192/Keenetic-Split-DNS/main}"
log() { printf '[keenetic-split-dns] %s\n' "$*"; }
die() { log "ERROR: $*"; exit 1; }
# --- Entware check ---
[ -x /opt/bin/opkg ] || die "Entware not found. Install Entware on USB first."
[ -d /opt/etc ] || die "/opt/etc missing — Entware broken?"
# --- resolve source tree ---
SRC_DIR=""
case "$0" in
/*|./*|*/install.sh)
_d="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
[ -f "${_d}/etc/config.yaml.example" ] && SRC_DIR="$_d"
;;
esac
if [ -z "$SRC_DIR" ]; then
TMP="$(mktemp -d /tmp/ksd-install.XXXXXX)"
trap 'rm -rf "$TMP"' EXIT INT HUP
log "Downloading repository..."
if command -v git >/dev/null 2>&1; then
git clone --depth 1 https://github.com/andrey271192/Keenetic-Split-DNS.git "$TMP/repo"
SRC_DIR="$TMP/repo"
else
die "git not found. On router: opkg install git git-http. Or clone repo manually and run install.sh from it."
fi
fi
log "Installing Keenetic-Split-DNS v${KSD_VERSION}..."
# --- packages ---
log "Installing Entware packages..."
opkg update >/dev/null 2>&1 || true
for pkg in smartdns lighttpd lighttpd-mod-cgi ca-certificates curl grep sed bind-dig; do
opkg list-installed 2>/dev/null | grep -q "^${pkg} " || opkg install "$pkg" >/dev/null 2>&1 || {
case "$pkg" in
bind-dig) opkg install bind-tools >/dev/null 2>&1 || opkg install dig >/dev/null 2>&1 || true ;;
*) log "Warning: package $pkg may be missing" ;;
esac
}
done
mkdir -p "$KSD_ETC" "$KSD_SHARE" "$KSD_VAR_LOG" "$KSD_VAR_RUN" \
"${KSD_ETC}/domain-sets" "${KSD_SHARE}/www" "${KSD_SHARE}/scripts" \
"${KSD_SHARE}/cgi-bin" "${KSD_SHARE}/smartdns" "${KSD_SHARE}/lighttpd" \
"${KSD_SHARE}/domain-sets"
# --- copy files ---
if [ ! -f "${KSD_ETC}/config.yaml" ]; then
cp "$SRC_DIR/etc/config.yaml.example" "${KSD_ETC}/config.yaml"
fi
cp -rf "$SRC_DIR/scripts/"* "${KSD_SHARE}/scripts/"
cp -rf "$SRC_DIR/www/"* "${KSD_SHARE}/www/"
cp -f "$SRC_DIR/cgi-bin/api.cgi" "${KSD_SHARE}/cgi-bin/"
cp -rf "$SRC_DIR/etc/domain-sets/"* "${KSD_SHARE}/domain-sets/" 2>/dev/null || true
cp -f "$SRC_DIR/etc/smartdns/"* "${KSD_SHARE}/smartdns/" 2>/dev/null || true
cp -f "$SRC_DIR/etc/lighttpd/lighttpd.conf" "${KSD_SHARE}/lighttpd/"
# symlink API CGI into web root
ln -sf "${KSD_SHARE}/cgi-bin/api.cgi" "${KSD_SHARE}/www/api.cgi"
mkdir -p "${KSD_SHARE}/www/api"
ln -sf "${KSD_SHARE}/cgi-bin/api.cgi" "${KSD_SHARE}/www/api/index.cgi"
chmod +x "${KSD_SHARE}/scripts/"*.sh "${KSD_SHARE}/cgi-bin/api.cgi"
# --- detect LAN ---
DETECT="${KSD_SHARE}/scripts/detect-lan.sh"
LAN_IP="$("$DETECT" lan 2>/dev/null || echo "192.168.1.1")"
if grep -q 'lan_ip: "192.168.1.1"' "${KSD_ETC}/config.yaml" 2>/dev/null; then
if sed -i "s/lan_ip: \"192.168.1.1\"/lan_ip: \"${LAN_IP}\"/" "${KSD_ETC}/config.yaml" 2>/dev/null; then
:
else
sed "s/lan_ip: \"192.168.1.1\"/lan_ip: \"${LAN_IP}\"/" "${KSD_ETC}/config.yaml" > "${KSD_ETC}/config.yaml.tmp" \
&& mv "${KSD_ETC}/config.yaml.tmp" "${KSD_ETC}/config.yaml"
fi
fi
# --- API token ---
if [ ! -f "${KSD_ETC}/token" ]; then
if [ -r /dev/urandom ]; then
TOKEN="$(head -c 24 /dev/urandom | hexdump -ve '1/1 "%02x"' 2>/dev/null | head -c 48)"
else
TOKEN="$(date +%s)$(uname -n)"
fi
[ -n "$TOKEN" ] || TOKEN="change-me-$(date +%s)"
echo "$TOKEN" > "${KSD_ETC}/token"
chmod 600 "${KSD_ETC}/token"
fi
# --- init.d ---
for s in S97ksd-compile S98smartdns S99ksd-web; do
cp -f "$SRC_DIR/init.d/$s" "/opt/etc/init.d/$s"
chmod +x "/opt/etc/init.d/$s"
done
# --- netfilter fallback ---
mkdir -p /opt/etc/ndm/netfilter.d
cp -f "$SRC_DIR/etc/ndm/netfilter.d/010-keenetic-split-dns.sh" /opt/etc/ndm/netfilter.d/
chmod +x /opt/etc/ndm/netfilter.d/010-keenetic-split-dns.sh
# --- domain sets to etc (seed defaults only) ---
for _ds in "${KSD_SHARE}/domain-sets/"*.txt; do
[ -f "$_ds" ] || continue
_base="$(basename "$_ds")"
[ -f "${KSD_ETC}/domain-sets/${_base}" ] || cp -f "$_ds" "${KSD_ETC}/domain-sets/${_base}"
done
# --- compile & start ---
export KSD_ETC KSD_SHARE
"${KSD_SHARE}/scripts/compile-config.sh"
# --- dns-override (HydraRoute Neo compatible path) ---
DNS_OVERRIDE_STATE="${KSD_ETC}/dns-override.state"
if opkg dns-override 2>/dev/null | grep -q enable; then
log "Configuring opkg dns-override..."
if ! grep -q '^enabled=1' /opt/etc/dns-override.conf 2>/dev/null; then
cp /opt/etc/dns-override.conf /opt/etc/dns-override.conf.ksd-bak 2>/dev/null || true
echo "before-install" > "$DNS_OVERRIDE_STATE"
fi
opkg dns-override enable 2>/dev/null || true
echo "enabled" > "$DNS_OVERRIDE_STATE"
log "dns-override enabled — clients use Entware SmartDNS"
else
log "dns-override not available — using netfilter.d redirect (if br0 DNS used)"
echo "netfilter" > "$DNS_OVERRIDE_STATE"
fi
/opt/etc/init.d/S97ksd-compile start
/opt/etc/init.d/S98smartdns start
/opt/etc/init.d/S99ksd-web start
ndm -p netfilter restart 2>/dev/null || true
WEB_PORT="$(grep '^web_port:' "${KSD_ETC}/config.yaml" | awk '{print $2}')"
[ -n "$WEB_PORT" ] || WEB_PORT="3200"
TOKEN_SHOW="$(cat "${KSD_ETC}/token")"
log "=============================================="
log "Keenetic-Split-DNS installed successfully."
log "Web UI: http://${LAN_IP}:${WEB_PORT}"
log "API token (save it): ${TOKEN_SHOW}"
log "Config: ${KSD_ETC}/config.yaml"
log ""
log "IMPORTANT: Disable global DoT in Keenetic UI"
log "(Интернет-фильтры -> DNS) to avoid conflicts."
log "HydraRoute Neo: keep DHCP DNS = router IP."
log "=============================================="
exit 0