Compare commits
No commits in common. "main" and "bins" have entirely different histories.
6 changed files with 58 additions and 119 deletions
|
|
@ -27,10 +27,8 @@ cd nikovpn_openwrt
|
|||
echo 'login:password' > /root/creds
|
||||
```
|
||||
|
||||
Бинарники при установке качаются из [релизов репозитория]
|
||||
(https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/tag/bins) — каталог
|
||||
`bin/` в клон не входит; если он есть рядом с install.sh — берётся из него.
|
||||
f.n1ko.dev остаётся резервным источником.
|
||||
Бинарники при установке качаются с f.n1ko.dev (каталог `bin/` ~150 MB
|
||||
в репозиторий не входит; если он есть рядом с install.sh — берётся из него).
|
||||
|
||||
## Команды
|
||||
|
||||
|
|
|
|||
103
install.sh
103
install.sh
|
|
@ -18,9 +18,8 @@
|
|||
# Требования:
|
||||
# - креды "login:password" (без кавычек): файл /root/creds
|
||||
# на роутере или переменная окружения NIKOVPN_CREDS
|
||||
# - даунлоадер: curl, wget или uclient-fetch
|
||||
# - доступ в интернет (бинарники — из релизов git.n1ko.dev,
|
||||
# резервом f.n1ko.dev; если рядом с install.sh есть bin/ — из него)
|
||||
# - доступ в интернет (скрипт тянет всё только с f.n1ko.dev и vpnd.n1ko.dev;
|
||||
# если рядом с install.sh есть каталог bin/ — бинарники берутся из него)
|
||||
#
|
||||
# Скрипт сам определяет архитектуру (openwrt_release/apk/opkg/uname),
|
||||
# выбирает лучший протокол и сервер (Hysteria2 > TUIC > Naive > VLESS > SS)
|
||||
|
|
@ -28,7 +27,6 @@
|
|||
# ============================================================================
|
||||
|
||||
BASE_URL="https://f.n1ko.dev/nikovpn_openwrt"
|
||||
REL_URL="https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/download/bins"
|
||||
API_URL="https://vpnd.n1ko.dev/api/v1"
|
||||
WORK_DIR="/etc/nikovpn"
|
||||
CREDS_FILE="/root/creds"
|
||||
|
|
@ -54,8 +52,8 @@ need_root() { [ "$(id -u)" = "0" ] || die "нужны права root"; }
|
|||
|
||||
# --- downloader ---
|
||||
DL=""
|
||||
for t in curl wget uclient-fetch; do have "$t" && DL="$t" && break; done
|
||||
[ -n "$DL" ] || die "нужен curl, wget или uclient-fetch"
|
||||
for t in curl wget; do have "$t" && DL="$t" && break; done
|
||||
[ -n "$DL" ] || die "нужен curl или wget"
|
||||
|
||||
dl() { # $1=url $2=out ; резерв на http:// для f.n1ko.dev
|
||||
local url="$1" out="$2" ok=""
|
||||
|
|
@ -63,47 +61,14 @@ dl() { # $1=url $2=out ; резерв на http:// для f.n1ko.dev
|
|||
curl -fsSL --max-time 120 -o "$out" "$url" && ok=1
|
||||
[ -z "$ok" ] && case "$url" in https://f.n1ko.dev/*)
|
||||
curl -fsSL --max-time 120 -o "$out" "http://${url#https://}" && ok=1 ;; esac
|
||||
elif [ "$DL" = wget ]; then
|
||||
else
|
||||
wget -q -T 120 -O "$out" "$url" && ok=1
|
||||
[ -z "$ok" ] && case "$url" in https://f.n1ko.dev/*)
|
||||
wget -q -T 120 -O "$out" "http://${url#https://}" && ok=1 ;; esac
|
||||
else
|
||||
uclient-fetch -q --timeout=120 -O "$out" "$url" && ok=1
|
||||
[ -z "$ok" ] && case "$url" in https://f.n1ko.dev/*)
|
||||
uclient-fetch -q --timeout=120 -O "$out" "http://${url#https://}" && ok=1 ;; esac
|
||||
fi
|
||||
[ -n "$ok" ]
|
||||
}
|
||||
|
||||
pipe_dl() { # $1=url -> поток в stdout (для больших файлов: без staging в tmpfs,
|
||||
# /tmp на OpenWRT — это RAM, крупный бинарник туда класть нельзя)
|
||||
if [ "$DL" = curl ]; then
|
||||
curl -fsSL --max-time 600 "$1"
|
||||
elif [ "$DL" = wget ]; then
|
||||
wget -q -T 600 -O - "$1"
|
||||
else
|
||||
uclient-fetch -q --timeout=600 -O - "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
fetch_gz() { # $1=имя-файла $2=dest ; источники: локальный bin/ -> релиз -> f.n1ko.dev
|
||||
local f="$1" out="$2" ok=0
|
||||
if [ -f "$REPO_DIR/bin/$f" ]; then
|
||||
gzip -dc "$REPO_DIR/bin/$f" > "$out" 2>/dev/null && [ -s "$out" ] && ok=1
|
||||
fi
|
||||
if [ $ok != 1 ]; then
|
||||
log "Качаю $f из релизов git.n1ko.dev ..."
|
||||
pipe_dl "$REL_URL/$f" | gzip -dc > "$out" 2>/dev/null
|
||||
[ -s "$out" ] && ok=1
|
||||
fi
|
||||
if [ $ok != 1 ]; then
|
||||
log "Качаю $f с f.n1ko.dev ..."
|
||||
pipe_dl "$BASE_URL/bin/$f" | gzip -dc > "$out" 2>/dev/null
|
||||
[ -s "$out" ] && ok=1
|
||||
fi
|
||||
[ $ok = 1 ]
|
||||
}
|
||||
|
||||
# --- API (HTTP Basic auth) ---
|
||||
API_AUTH=""; API_AUTH_V=""
|
||||
api_init_auth() {
|
||||
|
|
@ -133,13 +98,11 @@ api_get() {
|
|||
}
|
||||
|
||||
read_creds() {
|
||||
# ВАЖНО: не использовать tr '[:space:]' — старые busybox не знают
|
||||
# POSIX-классы и вырезают литеральные буквы из кредов
|
||||
if [ -n "$NIKOVPN_CREDS" ]; then
|
||||
CRED=$(printf '%s' "$NIKOVPN_CREDS" | tr -d ' \t\r\n')
|
||||
CRED=$(printf '%s' "$NIKOVPN_CREDS" | tr -d '[:space:]')
|
||||
else
|
||||
[ -f "$CREDS_FILE" ] || die "нет кредов: запишите 'login:password' в $CREDS_FILE или задайте env NIKOVPN_CREDS"
|
||||
CRED=$(grep -v '^[[:space:]]*#' "$CREDS_FILE" 2>/dev/null | grep -v '^[[:space:]]*$' | head -1 | tr -d ' \t\r\n')
|
||||
CRED=$(grep -v '^[[:space:]]*#' "$CREDS_FILE" 2>/dev/null | grep -v '^[[:space:]]*$' | head -1 | tr -d '[:space:]')
|
||||
[ -n "$CRED" ] || die "$CREDS_FILE пуст — запишите 'login:password'"
|
||||
fi
|
||||
case "$CRED" in *:*) ;; *) die "в кредах нет ':' — формат login:password" ;; esac
|
||||
|
|
@ -496,16 +459,26 @@ install_bins() {
|
|||
|
||||
if [ "$skip_sb" != 1 ]; then
|
||||
log "Получаю sing-box ($SB_ARCH) ..."
|
||||
fetch_gz "sing-box-$SB_ARCH.gz" "$SB_PATH" || die "не удалось скачать sing-box"
|
||||
chmod +x "$SB_PATH"
|
||||
"$SB_PATH" version >/dev/null 2>&1 || die "sing-box не запускается на этой системе (архитектура?)"
|
||||
dl "$BASE_URL/bin/sing-box-$SB_ARCH.gz" "$TMP/sing-box.gz" || \
|
||||
cp "$REPO_DIR/bin/sing-box-$SB_ARCH.gz" "$TMP/sing-box.gz" 2>/dev/null
|
||||
[ -s "$TMP/sing-box.gz" ] || die "не удалось скачать sing-box"
|
||||
gzip -dc "$TMP/sing-box.gz" > "$TMP/sing-box" 2>/dev/null || die "повреждённый архив sing-box"
|
||||
chmod +x "$TMP/sing-box"
|
||||
"$TMP/sing-box" version >/dev/null 2>&1 || die "sing-box не запускается на этой системе (архитектура?)"
|
||||
mv "$TMP/sing-box" "$SB_PATH"
|
||||
rm -f "$TMP/sing-box.gz"
|
||||
fi
|
||||
|
||||
if [ "$TUNNEL" = "ipt2socks" ] && [ "$skip_ipt" != 1 ]; then
|
||||
log "Получаю ipt2socks ($IPT_ARCH) ..."
|
||||
fetch_gz "ipt2socks-$IPT_ARCH.gz" "$IPT_PATH" || die "не удалось скачать ipt2socks"
|
||||
chmod +x "$IPT_PATH"
|
||||
"$IPT_PATH" -V >/dev/null 2>&1 || die "ipt2socks не запускается на этой системе (архитектура?)"
|
||||
dl "$BASE_URL/bin/ipt2socks-$IPT_ARCH.gz" "$TMP/ipt2socks.gz" || \
|
||||
cp "$REPO_DIR/bin/ipt2socks-$IPT_ARCH.gz" "$TMP/ipt2socks.gz" 2>/dev/null
|
||||
[ -s "$TMP/ipt2socks.gz" ] || die "не удалось скачать ipt2socks"
|
||||
gzip -dc "$TMP/ipt2socks.gz" > "$TMP/ipt2socks" 2>/dev/null || die "повреждённый архив ipt2socks"
|
||||
chmod +x "$TMP/ipt2socks"
|
||||
"$TMP/ipt2socks" -V >/dev/null 2>&1 || die "ipt2socks не запускается на этой системе (архитектура?)"
|
||||
mv "$TMP/ipt2socks" "$IPT_PATH"
|
||||
rm -f "$TMP/ipt2socks.gz"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -767,10 +740,9 @@ status() {
|
|||
echo "Сервер: $HOST:$PORT"
|
||||
echo "Архитектура: $ARCH (sing-box $SB_VER, ipt2socks $IPT_VER)"
|
||||
echo "Режим: $MODE / $TUNNEL / $FW"
|
||||
# pgrep без -x: busybox с argv[0]=/usr/bin/sing-box не матчит -x
|
||||
pgrep sing-box >/dev/null 2>&1 && echo "sing-box: RUNNING" || echo "sing-box: STOPPED"
|
||||
pgrep -x sing-box >/dev/null 2>&1 && echo "sing-box: RUNNING" || echo "sing-box: STOPPED"
|
||||
if [ "$TUNNEL" = ipt2socks ]; then
|
||||
pgrep ipt2socks >/dev/null 2>&1 && echo "ipt2socks: RUNNING" || echo "ipt2socks: STOPPED"
|
||||
pgrep -x ipt2socks >/dev/null 2>&1 && echo "ipt2socks: RUNNING" || echo "ipt2socks: STOPPED"
|
||||
fi
|
||||
if [ -r /var/log/nikovpn.log ]; then
|
||||
echo "--- последние строки /var/log/nikovpn.log ---"
|
||||
|
|
@ -782,7 +754,7 @@ status() {
|
|||
tu=$(sed -n 's/.*"traffic_used": *\([0-9]*\).*/\1/p' "$TMP/me")
|
||||
tt=$(sed -n 's/.*"traffic_total": *\([0-9]*\).*/\1/p' "$TMP/me")
|
||||
td=$(sed -n 's/.*"traffic_day": *\([0-9]*\).*/\1/p' "$TMP/me")
|
||||
echo "Трафик: использовано $tu байт, за сутки $td, всего $tt"
|
||||
echo "Трафик: использовано $tu, за сутки $td, лимит $tt байт"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -795,8 +767,6 @@ uninstall() {
|
|||
/etc/init.d/nikovpn stop 2>/dev/null
|
||||
/etc/init.d/nikovpn disable 2>/dev/null
|
||||
fi
|
||||
kill $(pgrep sing-box) 2>/dev/null
|
||||
kill $(pgrep ipt2socks) 2>/dev/null
|
||||
nft delete table inet nikovpn 2>/dev/null
|
||||
rm -f /etc/nftables.d/10-nikovpn.nft
|
||||
for c in NIKOVPN NIKOVPN_TP NIKOVPN_UDP; do
|
||||
|
|
@ -828,11 +798,9 @@ install() {
|
|||
|
||||
mkdir -p "$WORK_DIR" "$TMP"
|
||||
|
||||
log "Проверяю обновления ..."
|
||||
dl "$REL_URL/versions" "$TMP/versions" || \
|
||||
dl "$BASE_URL/versions" "$TMP/versions" || \
|
||||
cp "$REPO_DIR/versions" "$TMP/versions" 2>/dev/null
|
||||
[ -s "$TMP/versions" ] || die "не могу скачать versions (нет интернета?)"
|
||||
log "Проверяю обновления с f.n1ko.dev ..."
|
||||
dl "$BASE_URL/versions" "$TMP/versions" || cp "$REPO_DIR/versions" "$TMP/versions" 2>/dev/null
|
||||
[ -s "$TMP/versions" ] || die "не могу скачать $BASE_URL/versions (нет интернета?)"
|
||||
SB_VER=""; IPT_VER=""
|
||||
while IFS='=' read -r k v; do
|
||||
case "$k" in sing-box) SB_VER="$v" ;; ipt2socks) IPT_VER="$v" ;; esac
|
||||
|
|
@ -871,14 +839,10 @@ install() {
|
|||
esac
|
||||
fi
|
||||
|
||||
# остановить старый сервис и процессы вне procd (иначе Text file busy
|
||||
# при перезаписи бинарников и занятые порты после старта)
|
||||
# остановить старый сервис перед перезаписью
|
||||
if [ -x /etc/init.d/nikovpn ]; then
|
||||
/etc/init.d/nikovpn stop 2>/dev/null
|
||||
fi
|
||||
kill $(pgrep sing-box) 2>/dev/null
|
||||
kill $(pgrep ipt2socks) 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
install_bins
|
||||
log "Генерирую конфиг ..."
|
||||
|
|
@ -891,14 +855,11 @@ install() {
|
|||
chmod +x "$WORK_DIR/install.sh"
|
||||
|
||||
log "Запускаю сервис ..."
|
||||
kill $(pgrep sing-box) 2>/dev/null
|
||||
kill $(pgrep ipt2socks) 2>/dev/null
|
||||
sleep 1
|
||||
/etc/init.d/nikovpn enable 2>/dev/null
|
||||
/etc/init.d/nikovpn start 2>/dev/null
|
||||
sleep 5
|
||||
sleep 3
|
||||
|
||||
if pgrep sing-box >/dev/null 2>&1; then
|
||||
if pgrep -x sing-box >/dev/null 2>&1; then
|
||||
log "sing-box запущен. Прозрачный прокси активен."
|
||||
else
|
||||
warn "sing-box не запустился. Смотрите: cat /var/log/nikovpn.log"
|
||||
|
|
|
|||
17
nikovpn.py
17
nikovpn.py
|
|
@ -35,7 +35,6 @@ from pathlib import Path
|
|||
from urllib.parse import parse_qs, unquote, urlsplit
|
||||
|
||||
BASE_URL = "https://f.n1ko.dev/nikovpn_openwrt"
|
||||
REL_URL = "https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/download/bins"
|
||||
API_URL = "https://vpnd.n1ko.dev/api/v1"
|
||||
WORK_DIR = "/etc/nikovpn"
|
||||
CREDS_FILE = "/root/creds"
|
||||
|
|
@ -636,10 +635,9 @@ def install_bins(rt: Router, sb_arch: str, ipt_arch: str, tunnel: str,
|
|||
if local.exists():
|
||||
push_gz(rt, local, SB_PATH, "{b} version", "sing-box")
|
||||
else:
|
||||
log(f"скачиваю sing-box ({sb_arch}) на роутере ...")
|
||||
log(f"скачиваю sing-box ({sb_arch}) на роутере с f.n1ko.dev ...")
|
||||
gz = f"/tmp/nikovpn.{os.getpid()}.sb.gz"
|
||||
if not (router_download(rt, f"{REL_URL}/sing-box-{sb_arch}.gz", gz) or
|
||||
router_download(rt, f"{BASE_URL}/bin/sing-box-{sb_arch}.gz", gz)):
|
||||
if not router_download(rt, f"{BASE_URL}/bin/sing-box-{sb_arch}.gz", gz):
|
||||
die("не удалось скачать sing-box")
|
||||
rt.run(f"gzip -dc {gz} > {SB_PATH} && chmod +x {SB_PATH}", check=True)
|
||||
if rt.run(f"{SB_PATH} version")[0] != 0:
|
||||
|
|
@ -651,10 +649,9 @@ def install_bins(rt: Router, sb_arch: str, ipt_arch: str, tunnel: str,
|
|||
if local.exists():
|
||||
push_gz(rt, local, IPT_PATH, "{b} -V", "ipt2socks")
|
||||
else:
|
||||
log(f"скачиваю ipt2socks ({ipt_arch}) на роутере ...")
|
||||
log(f"скачиваю ipt2socks ({ipt_arch}) на роутере с f.n1ko.dev ...")
|
||||
gz = f"/tmp/nikovpn.{os.getpid()}.ipt.gz"
|
||||
if not (router_download(rt, f"{REL_URL}/ipt2socks-{ipt_arch}.gz", gz) or
|
||||
router_download(rt, f"{BASE_URL}/bin/ipt2socks-{ipt_arch}.gz", gz)):
|
||||
if not router_download(rt, f"{BASE_URL}/bin/ipt2socks-{ipt_arch}.gz", gz):
|
||||
die("не удалось скачать ipt2socks")
|
||||
rt.run(f"gzip -dc {gz} > {IPT_PATH} && chmod +x {IPT_PATH}", check=True)
|
||||
if rt.run(f"{IPT_PATH} -V")[0] != 0:
|
||||
|
|
@ -821,9 +818,7 @@ def do_install(rt: Router, args, update=False):
|
|||
IPT_VER = v
|
||||
if not SB_VER:
|
||||
rc, out, _ = rt.run(
|
||||
f"(curl -fsSL {REL_URL}/versions 2>/dev/null || "
|
||||
f"wget -q -O - {REL_URL}/versions 2>/dev/null || "
|
||||
f"curl -fsSL {BASE_URL}/versions 2>/dev/null || "
|
||||
f"(curl -fsSL {BASE_URL}/versions 2>/dev/null || "
|
||||
f"wget -q -O - {BASE_URL}/versions 2>/dev/null)")
|
||||
if rc == 0:
|
||||
for line in out.decode(errors="replace").splitlines():
|
||||
|
|
@ -952,7 +947,7 @@ def do_status(rt: Router, args):
|
|||
me = json.loads(body)
|
||||
print(f"Трафик: использовано {human(me.get('traffic_used'))}, "
|
||||
f"за сутки {human(me.get('traffic_day'))}, "
|
||||
f"всего {human(me.get('traffic_total'))}")
|
||||
f"лимит {human(me.get('traffic_total'))}")
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
|
|
|
|||
17
status.sh
17
status.sh
|
|
@ -2,17 +2,12 @@
|
|||
# NikoVPN: статус VPN
|
||||
[ -f /etc/nikovpn/install.sh ] && exec /etc/nikovpn/install.sh status
|
||||
TMP=/tmp/nikovpn-status.sh
|
||||
for URL in \
|
||||
"https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/download/bins/install.sh" \
|
||||
"https://f.n1ko.dev/nikovpn_openwrt/install.sh"; do
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
[ -s "$TMP" ] && break
|
||||
rm -f "$TMP"
|
||||
done
|
||||
URL="https://f.n1ko.dev/nikovpn_openwrt/install.sh"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
if [ -s "$TMP" ]; then
|
||||
chmod +x "$TMP"
|
||||
exec "$TMP" status
|
||||
|
|
|
|||
17
uninstall.sh
17
uninstall.sh
|
|
@ -2,17 +2,12 @@
|
|||
# NikoVPN: удаление VPN (останавливает сервисы и чистит firewall)
|
||||
[ -f /etc/nikovpn/install.sh ] && exec /etc/nikovpn/install.sh uninstall
|
||||
TMP=/tmp/nikovpn-uninstall.sh
|
||||
for URL in \
|
||||
"https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/download/bins/install.sh" \
|
||||
"https://f.n1ko.dev/nikovpn_openwrt/install.sh"; do
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
[ -s "$TMP" ] && break
|
||||
rm -f "$TMP"
|
||||
done
|
||||
URL="https://f.n1ko.dev/nikovpn_openwrt/install.sh"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
if [ -s "$TMP" ]; then
|
||||
chmod +x "$TMP"
|
||||
exec "$TMP" uninstall
|
||||
|
|
|
|||
17
update.sh
17
update.sh
|
|
@ -2,17 +2,12 @@
|
|||
# NikoVPN: обновление (переустановка) — скачивает свежий install.sh с f.n1ko.dev
|
||||
[ -f /etc/nikovpn/install.sh ] && exec /etc/nikovpn/install.sh update
|
||||
TMP=/tmp/nikovpn-update.sh
|
||||
for URL in \
|
||||
"https://git.n1ko.dev/Niko/nikovpn_openwrt/releases/download/bins/install.sh" \
|
||||
"https://f.n1ko.dev/nikovpn_openwrt/install.sh"; do
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
[ -s "$TMP" ] && break
|
||||
rm -f "$TMP"
|
||||
done
|
||||
URL="https://f.n1ko.dev/nikovpn_openwrt/install.sh"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" -o "$TMP" 2>/dev/null
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q "$URL" -O "$TMP" 2>/dev/null
|
||||
fi
|
||||
if [ -s "$TMP" ]; then
|
||||
chmod +x "$TMP"
|
||||
exec "$TMP" update
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue