steer: туннели в warp.up лучшим первым, запасной порт при привязке точки, без мёртвых функций
warp.up писался в порядке номеров туннелей, хотя комментарий обещал «лучший первым», а порядок читают все, кому нужен один туннель: _st_warp_first, мост Telegram (warp.lst — первый живой) и движок (devices в spec решают ничьи в пределах допуска prefer: latency). Разведка теперь отдаёт ключ качества (разряд запаса, потери, круг), и _st_warp_order ставит туннели по нему. Если ни один туннель не разведан заново, порядок прежний: перестановка по дрожанию пинга меняла бы spec и перезапускала движок на каждом «Применить». Второй найденный порт из warp.ports стал запасным: не дала точка рукопожатия при окончательной привязке — тот же адрес пробуется на нём, прежде чем туннель сдаётся. _st_warp_handshake, _st_warp_hs_epoch и _st_warp_colo нигде не вызывались — убраны.
This commit is contained in:
1 parent
404ba5f7db
commit
069d93f463
1 file changed
+83
-26
+83
-26
@@ -4847,7 +4847,7 @@ ST_CRON_CMD="/etc/init.d/steer enabled && { for i in zmwarp zmwarp2 zmwarp3; do
|
|||||||
# страница, его ключи и точка переживают обновление. У каждого своя регистрация: одни ключи
|
# страница, его ключи и точка переживают обновление. У каждого своя регистрация: одни ключи
|
||||||
# на трёх устройствах Cloudflare считает одним клиентом.
|
# на трёх устройствах Cloudflare считает одним клиентом.
|
||||||
ST_WARP_N=3
|
ST_WARP_N=3
|
||||||
ST_WARP_UP="$ST_DIR/warp.up" # поднятые туннели «интерфейс колония», лучший первым
|
ST_WARP_UP="$ST_DIR/warp.up" # поднятые туннели «интерфейс колония», лучший первым (_st_warp_order)
|
||||||
# Российские колонии Cloudflare: выход у них внутри страны, за теми же ТСПУ, что и без туннеля, —
|
# Российские колонии Cloudflare: выход у них внутри страны, за теми же ТСПУ, что и без туннеля, —
|
||||||
# через них не снимается ни геоблок, ни остальные блокировки. Берутся только в запас.
|
# через них не снимается ни геоблок, ни остальные блокировки. Берутся только в запас.
|
||||||
ST_RU_COLOS="DME SVX LED KJA REN OVB KZN AER VVO"
|
ST_RU_COLOS="DME SVX LED KJA REN OVB KZN AER VVO"
|
||||||
@@ -5140,19 +5140,6 @@ _st_warp_zone() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_st_warp_hs_epoch() { awg show "$ST_WARP_IF" latest-handshakes 2>/dev/null | awk '{print $2}' | head -n1; }
|
|
||||||
|
|
||||||
_st_warp_handshake() { # ждать рукопожатия до 10 с
|
|
||||||
local i=0 hs
|
|
||||||
while [ "$i" -lt 10 ]; do
|
|
||||||
hs=$(_st_warp_hs_epoch)
|
|
||||||
[ -n "$hs" ] && [ "$hs" != 0 ] && return 0
|
|
||||||
ping -c1 -W1 -I "$ST_WARP_IF" 1.1.1.1 >/dev/null 2>&1
|
|
||||||
i=$((i + 1))
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_st_warp_is_ru() { case " $ST_RU_COLOS " in *" $1 "*) return 0 ;; esac; return 1; }
|
_st_warp_is_ru() { case " $ST_RU_COLOS " in *" $1 "*) return 0 ;; esac; return 1; }
|
||||||
|
|
||||||
# ── несколько туннелей ──
|
# ── несколько туннелей ──
|
||||||
@@ -5229,9 +5216,9 @@ _st_colo_of() { # ИНТЕРФЕЙС
|
|||||||
sed -n 's/^colo=//p' | head -n1)
|
sed -n 's/^colo=//p' | head -n1)
|
||||||
[ -n "$c" ] && echo "$c"
|
[ -n "$c" ] && echo "$c"
|
||||||
}
|
}
|
||||||
_st_warp_colo() { _st_colo_of "$ST_WARP_IF"; }
|
|
||||||
|
|
||||||
# Какие порты провайдер выпускает к WARP — один раз, дальше из файла.
|
# Какие порты провайдер выпускает к WARP — один раз, дальше из файла. Ищутся два: разведка
|
||||||
|
# ведёт все адреса первым, второй — запасной при окончательной привязке точки (_st_warp_up).
|
||||||
_st_warp_ports() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА АДРЕС
|
_st_warp_ports() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА АДРЕС
|
||||||
local f="$ST_DIR/warp.ports" ok="" p
|
local f="$ST_DIR/warp.ports" ok="" p
|
||||||
[ -s "$f" ] && { cat "$f"; return 0; }
|
[ -s "$f" ] && { cat "$f"; return 0; }
|
||||||
@@ -5245,10 +5232,16 @@ _st_warp_ports() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА АДРЕС
|
|||||||
echo "$ok"
|
echo "$ok"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Разведка для одного туннеля. Печатает «адрес порт колония» лучшей точки. Занятая колония —
|
# Разведка для одного туннеля. Печатает «адрес порт колония ключ» лучшей точки. Занятая
|
||||||
# запас (другой адрес в той же колонии лучше никакого), российская — последний запас.
|
# колония — запас (другой адрес в той же колонии лучше никакого), российская — последний запас.
|
||||||
|
#
|
||||||
|
# Ключ — качество точки одним числом, меньше — лучше: разряд запаса (0 — наружная колония,
|
||||||
|
# своя или занятая соседом; 1 — колония не узналась; 2 — российская; 3 — HTTPS не проходит),
|
||||||
|
# за ним потери и круг. По нему _st_warp_order ставит туннели в warp.up лучшим первым. Занятая
|
||||||
|
# колония в разряде не отличается от свободной: «занята соседом» важно, когда точку выбирают
|
||||||
|
# для одного туннеля, а сравнивать туннели между собой — это уже только связь.
|
||||||
_st_warp_scan() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА ЗАНЯТЫЕ_КОЛОНИИ ЗАНЯТЫЕ_АДРЕСА
|
_st_warp_scan() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА ЗАНЯТЫЕ_КОЛОНИИ ЗАНЯТЫЕ_АДРЕСА
|
||||||
local dev="$1" peer="$2" busy=" $3 " busyip=" $4 " r="$ST_RUN/scan.$1" cand ip ports port loss rtt colo pick f
|
local dev="$1" peer="$2" busy=" $3 " busyip=" $4 " r="$ST_RUN/scan.$1" cand ip ports port loss rtt colo pick f cls
|
||||||
mkdir -p "$ST_RUN"
|
mkdir -p "$ST_RUN"
|
||||||
: > "$r"; : > "$r.same"; : > "$r.nc"; : > "$r.ru"; : > "$r.notls"
|
: > "$r"; : > "$r.same"; : > "$r.nc"; : > "$r.ru"; : > "$r.notls"
|
||||||
# Якоря .1 первыми: на них указывает сам engage.cloudflareclient.com; случайные — за
|
# Якоря .1 первыми: на них указывает сам engage.cloudflareclient.com; случайные — за
|
||||||
@@ -5295,7 +5288,9 @@ _st_warp_scan() { # ИНТЕРФЕЙС КЛЮЧ_УЗЛА ЗАНЯТЫЕ_КОЛО
|
|||||||
# не понимает модификаторов у ключей, см. brb/warp.sh).
|
# не понимает модификаторов у ключей, см. brb/warp.sh).
|
||||||
for f in "$r" "$r.same" "$r.nc" "$r.ru" "$r.notls"; do
|
for f in "$r" "$r.same" "$r.nc" "$r.ru" "$r.notls"; do
|
||||||
[ -s "$f" ] || continue
|
[ -s "$f" ] || continue
|
||||||
pick=$(awk '{ printf "%d\t%s %s %s\n", $1 * 100000 + $2, $3, $4, $5 }' "$f" | sort -n | head -n1 | cut -f2)
|
case "$f" in *.nc) cls=1 ;; *.ru) cls=2 ;; *.notls) cls=3 ;; *) cls=0 ;; esac
|
||||||
|
pick=$(awk -v c="$cls" '{ k = c * 100000000 + $1 * 100000 + $2; printf "%d\t%s %s %s %d\n", k, $3, $4, $5, k }' "$f" |
|
||||||
|
sort -n | head -n1 | cut -f2)
|
||||||
case "$f" in
|
case "$f" in
|
||||||
*.same) echo " другой колонии нет — та же, но через другой адрес" >&2 ;;
|
*.same) echo " другой колонии нет — та же, но через другой адрес" >&2 ;;
|
||||||
*.ru) echo " наружных колоний нет — беру российскую: блокировки через неё не снимаются" >&2 ;;
|
*.ru) echo " наружных колоний нет — беру российскую: блокировки через неё не снимаются" >&2 ;;
|
||||||
@@ -5314,13 +5309,56 @@ _st_warp_alive_if() { # ИНТЕРФЕЙС — рукопожатие не ст
|
|||||||
}
|
}
|
||||||
_st_warp_ready_if() { ifstatus "$1" 2>/dev/null | grep -q '"up": true' && awg show "$1" peers 2>/dev/null | grep -q .; }
|
_st_warp_ready_if() { ifstatus "$1" 2>/dev/null | grep -q '"up": true' && awg show "$1" peers 2>/dev/null | grep -q .; }
|
||||||
|
|
||||||
|
# Порядок туннелей в warp.up — лучший первым. Порядок здесь не для красоты: его читают все,
|
||||||
|
# кому из нескольких туннелей нужен один или кто перебирает их по очереди.
|
||||||
|
# - _st_warp_first: через первый живой пробуются сервисы, качаются списки, идёт самопроверка.
|
||||||
|
# - Мост Telegram (warp.lst, см. _st_tgws_warp): берёт первый живой туннель из списка и к
|
||||||
|
# следующему переходит, только когда тот не дал даже TCP, — порядок для него и есть выбор.
|
||||||
|
# - Движок (devices в spec, prefer: latency): туннели он меряет сам, но замеры в пределах
|
||||||
|
# допуска (50 мс) считает равными и из равных берёт стоящий выше, — порядок решает ничьи, а
|
||||||
|
# когда замерить не вышло ни одного, выбор идёт просто по порядку.
|
||||||
|
#
|
||||||
|
# Ключ — от разведки (см. _st_warp_scan). У туннеля, оставленного живым, свежего замера нет, и
|
||||||
|
# дальше два случая.
|
||||||
|
# - Разведки не было ни у одного — туннели остаются на прежних местах. Переставлять их по
|
||||||
|
# трём пингам значило бы на каждом «Применить» и каждом прогоне автообхода тасовать список
|
||||||
|
# по дрожанию задержки, а новый порядок — это другой spec и перезапуск движка с обрывом
|
||||||
|
# соединений ради ничего.
|
||||||
|
# - Хоть один разведан заново — список всё равно меняется, и оставленным меряется то же, что
|
||||||
|
# мерила разведка (потери и круг тремя пингами изнутри живого туннеля, сессию это не
|
||||||
|
# трогает), с разрядом запаса 0: колония у них узналась и она не российская, иначе туннель
|
||||||
|
# ушёл бы в разведку. Без замера новичка не с чем было бы сравнить.
|
||||||
|
# При равных ключах держится порядок строк, то есть номеров туннелей.
|
||||||
|
_st_warp_order() { # ФАЙЛ «интерфейс колония ключ|-» -> тот же файл «интерфейс колония»
|
||||||
|
local f="$1" i c k pos=0 fresh=0
|
||||||
|
grep -q ' [0-9][0-9]*$' "$f" && fresh=1
|
||||||
|
: > "$f.key"
|
||||||
|
while read -r i c k; do
|
||||||
|
[ -n "$i" ] || continue
|
||||||
|
pos=$((pos + 1))
|
||||||
|
if [ "$fresh" = 0 ]; then
|
||||||
|
# Прежнее место; туннеля, которого в прошлом списке не было, — в хвост по номеру.
|
||||||
|
k=$(awk -v i="$i" '$1 == i { print NR; exit }' "$ST_WARP_UP" 2>/dev/null)
|
||||||
|
[ -n "$k" ] || k=$((100 + pos))
|
||||||
|
elif [ "$k" = - ]; then
|
||||||
|
set -- $(_st_warp_probe "$i")
|
||||||
|
k=$(($1 * 100000 + $2))
|
||||||
|
fi
|
||||||
|
# Ключ и номер строки — нулями до одной ширины, чтобы простой sort сравнил их как числа
|
||||||
|
# (busybox sort не понимает модификаторов у ключей, см. brb/warp.sh).
|
||||||
|
printf '%012d %03d %s %s\n' "$k" "$pos" "$i" "$c" >> "$f.key"
|
||||||
|
done < "$f"
|
||||||
|
sort "$f.key" | awk '{ print $3, $4 }' > "$f"
|
||||||
|
rm -f "$f.key"
|
||||||
|
}
|
||||||
|
|
||||||
# Поднять туннели. repick — не держаться прежних точек, подобрать заново.
|
# Поднять туннели. repick — не держаться прежних точек, подобрать заново.
|
||||||
#
|
#
|
||||||
# Сначала ключи и интерфейсы ВСЕХ туннелей одним reload, и только потом разведка на живых
|
# Сначала ключи и интерфейсы ВСЕХ туннелей одним reload, и только потом разведка на живых
|
||||||
# интерфейсах через `awg set`: запись в uci с ifup посреди разведки делала `network reload`, и
|
# интерфейсах через `awg set`: запись в uci с ifup посреди разведки делала `network reload`, и
|
||||||
# netifd перезапускал соседние туннели (на стенде так пропадал уже подобранный первый).
|
# netifd перезапускал соседние туннели (на стенде так пропадал уже подобранный первый).
|
||||||
_st_warp_up() { # [repick]
|
_st_warp_up() { # [repick]
|
||||||
local repick="$1" n i peer got busy="" busyip="" ru=0 c ready="" w need=0 colos=""
|
local repick="$1" n i peer got busy="" busyip="" ru=0 c ready="" w need=0 colos="" alt p
|
||||||
_st_install_awg || return 1
|
_st_install_awg || return 1
|
||||||
# Какие порты провайдер выпускает, меняется: при подборе заново спрашиваем снова.
|
# Какие порты провайдер выпускает, меняется: при подборе заново спрашиваем снова.
|
||||||
[ "$repick" = repick ] && rm -f "$ST_DIR/warp.ports"
|
[ "$repick" = repick ] && rm -f "$ST_DIR/warp.ports"
|
||||||
@@ -5365,7 +5403,9 @@ _st_warp_up() { # [repick]
|
|||||||
# держаться за неё только потому, что туннель жив, — значит оставить геоблок навсегда
|
# держаться за неё только потому, что туннель жив, — значит оставить геоблок навсегда
|
||||||
# (на тестовом роутере так и вышло: HEL, DME, HEL). Такой туннель разводится заново.
|
# (на тестовом роутере так и вышло: HEL, DME, HEL). Такой туннель разводится заново.
|
||||||
if [ "$repick" != repick ] && _st_warp_alive_if "$i" && c="$(_st_colo_of "$i")" && ! _st_warp_is_ru "$c"; then
|
if [ "$repick" != repick ] && _st_warp_alive_if "$i" && c="$(_st_colo_of "$i")" && ! _st_warp_is_ru "$c"; then
|
||||||
got="$(uci -q get "network.${i}_peer.endpoint_host") $(uci -q get "network.${i}_peer.endpoint_port") $c"
|
# Ключа качества нет («-»): свежего замера у оставленного туннеля нет, его место в
|
||||||
|
# warp.up решает _st_warp_order.
|
||||||
|
got="$(uci -q get "network.${i}_peer.endpoint_host") $(uci -q get "network.${i}_peer.endpoint_port") $c -"
|
||||||
_rb_say "WARP $n работает: колония $c"
|
_rb_say "WARP $n работает: колония $c"
|
||||||
else
|
else
|
||||||
echo " WARP $n: разведка"
|
echo " WARP $n: разведка"
|
||||||
@@ -5375,8 +5415,24 @@ _st_warp_up() { # [repick]
|
|||||||
# endpoint` нового рукопожатия не начинает — нужен тот же сброс узла, что в
|
# endpoint` нового рукопожатия не начинает — нужен тот же сброс узла, что в
|
||||||
# разведке, иначе туннель полминуты молчит и идёт не в ту колонию.
|
# разведке, иначе туннель полминуты молчит и идёт не в ту колонию.
|
||||||
if ! _st_warp_link "$i" "$peer" "$1" "$2"; then
|
if ! _st_warp_link "$i" "$peer" "$1" "$2"; then
|
||||||
_rb_warn "WARP $n: выбранная точка $1:$2 не ответила повторно"
|
# Запасной порт — второй найденный в warp.ports. Разведка ведёт все адреса
|
||||||
continue
|
# ОДНИМ портом, первым выпущенным, и точка, ответившая на нём минуту назад,
|
||||||
|
# может замолчать именно на нём: провайдер режет UDP к WARP по портам, и не
|
||||||
|
# всегда с первой минуты. Адрес тот же, значит и колония та же — она за
|
||||||
|
# адресом, не за портом; ключ качества остаётся от разведки.
|
||||||
|
alt=""
|
||||||
|
for p in $(cat "$ST_DIR/warp.ports" 2>/dev/null); do
|
||||||
|
[ "$p" = "$2" ] && continue
|
||||||
|
_st_stopped && break
|
||||||
|
_st_warp_link "$i" "$peer" "$1" "$p" && { alt="$p"; break; }
|
||||||
|
done
|
||||||
|
if [ -z "$alt" ]; then
|
||||||
|
_rb_warn "WARP $n: выбранная точка $1:$2 не ответила повторно"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
_rb_say "WARP $n: точка $1:$2 не ответила повторно, беру запасной порт $alt"
|
||||||
|
got="$1 $alt $3 $4"
|
||||||
|
set -- $got
|
||||||
fi
|
fi
|
||||||
_rb_say "WARP $n работает: $1:$2, колония $3"
|
_rb_say "WARP $n работает: $1:$2, колония $3"
|
||||||
else
|
else
|
||||||
@@ -5387,8 +5443,7 @@ _st_warp_up() { # [repick]
|
|||||||
set -- $got
|
set -- $got
|
||||||
busy="$busy $3"; busyip="$busyip $1"
|
busy="$busy $3"; busyip="$busyip $1"
|
||||||
_st_warp_is_ru "$3" && ru=1
|
_st_warp_is_ru "$3" && ru=1
|
||||||
colos="${colos:+$colos, }$3"
|
echo "$i $3 ${4:--}" >> "$ST_WARP_UP.tmp"
|
||||||
echo "$i $3" >> "$ST_WARP_UP.tmp"
|
|
||||||
# В uci — для следующей загрузки. Без reload: живой интерфейс уже на этой точке.
|
# В uci — для следующей загрузки. Без reload: живой интерфейс уже на этой точке.
|
||||||
uci set "network.${i}_peer.endpoint_host=$1"
|
uci set "network.${i}_peer.endpoint_host=$1"
|
||||||
uci set "network.${i}_peer.endpoint_port=$2"
|
uci set "network.${i}_peer.endpoint_port=$2"
|
||||||
@@ -5400,7 +5455,9 @@ _st_warp_up() { # [repick]
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
uci commit network
|
uci commit network
|
||||||
|
_st_warp_order "$ST_WARP_UP.tmp"
|
||||||
mv "$ST_WARP_UP.tmp" "$ST_WARP_UP"
|
mv "$ST_WARP_UP.tmp" "$ST_WARP_UP"
|
||||||
|
colos="$(awk '{ printf "%s%s", (NR > 1 ? ", " : ""), $2 }' "$ST_WARP_UP")"
|
||||||
# Не поднявшиеся — погасить: висящий без рукопожатия туннель движок принял бы за живой.
|
# Не поднявшиеся — погасить: висящий без рукопожатия туннель движок принял бы за живой.
|
||||||
for n in $ready; do
|
for n in $ready; do
|
||||||
i="$(_st_wif "$n")"
|
i="$(_st_wif "$n")"
|
||||||
|
|||||||
Reference in new issue
Block a user