Hysteria2: заглушка байт в байт как у nginx
$(cat …) срезал последний перевод строки, и страница masquerade была на байт короче той, что отдаёт nginx. Читаю файл целиком (установщик и kit net masq on), запасная запись страницы – без лишнего перевода строки.
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
* Раздельная маршрутизация: `kit net split on` – и через VPN идёт только список популярных иностранных сервисов (нейросети, видео, соцсети, мессенджеры, GitHub, Google и другие), а всё остальное напрямую. Правила приезжают вместе с подпиской, домашним ничего настраивать не нужно: приложения на Mihomo (Clash Verge, FlClash, Mihomo Party) берут их из подписки, Happ – заголовком, приложения на JSON-подписке Xray – из конфига. DNS не течёт, проверено клиентами Mihomo и Xray. Список в `/etc/kit-sub/rules.yaml`, проверка по базам категорий `kit net split check`, после правки `kit net split apply`, он входит в `kit backup`. Идея и первый набросок – [VasilevVitalii](https://github.com/VasilevVitalii), спасибо. У v2rayN, Karing, Hiddify и приложений с обычным списком ссылок подписка прежняя.
|
* Раздельная маршрутизация: `kit net split on` – и через VPN идёт только список популярных иностранных сервисов (нейросети, видео, соцсети, мессенджеры, GitHub, Google и другие), а всё остальное напрямую. Правила приезжают вместе с подпиской, домашним ничего настраивать не нужно: приложения на Mihomo (Clash Verge, FlClash, Mihomo Party) берут их из подписки, Happ – заголовком, приложения на JSON-подписке Xray – из конфига. DNS не течёт, проверено клиентами Mihomo и Xray. Список в `/etc/kit-sub/rules.yaml`, проверка по базам категорий `kit net split check`, после правки `kit net split apply`, он входит в `kit backup`. Идея и первый набросок – [VasilevVitalii](https://github.com/VasilevVitalii), спасибо. У v2rayN, Karing, Hiddify и приложений с обычным списком ссылок подписка прежняя.
|
||||||
* Исправил `--restore` на сервер с другим IP: ссылки части протоколов (адреса в таблице `hosts` панели и в настройках kit-sub) оставались со старым IP, а проверка панели после запуска могла ложно сообщить «Панель не отвечает», если панель стартует не сразу. А файлы настроек из копии `--restore` теперь читает строго по списку, как охранник на входе: лишнее имя – и копия не принимается, ничего не меняется. Охранник теперь смотрит и в лицо: каждое значение проверяется по своему формату (порт – цифры, путь – буквы и цифры, адрес – адрес), а странное – повод не пустить копию, а не молча что-то поправить.
|
* Исправил `--restore` на сервер с другим IP: ссылки части протоколов (адреса в таблице `hosts` панели и в настройках kit-sub) оставались со старым IP, а проверка панели после запуска могла ложно сообщить «Панель не отвечает», если панель стартует не сразу. А файлы настроек из копии `--restore` теперь читает строго по списку, как охранник на входе: лишнее имя – и копия не принимается, ничего не меняется. Охранник теперь смотрит и в лицо: каждое значение проверяется по своему формату (порт – цифры, путь – буквы и цифры, адрес – адрес), а странное – повод не пустить копию, а не молча что-то поправить.
|
||||||
* Исправил `kit backup`: из `/root` он падал с «No such file or directory», работал только из `/`. Теперь работает откуда угодно. Если токен API панели в `/etc/x-ui/install-result.env` не подошёл (так бывает после обновления с 1.0), `kit` сам выпускает новый и сохраняет его, а если панель всё же не отвечает – говорит по-человечески (код ответа и вероятная причина), а не «Unsupported HTTP version in response».
|
* Исправил `kit backup`: из `/root` он падал с «No such file or directory», работал только из `/`. Теперь работает откуда угодно. Если токен API панели в `/etc/x-ui/install-result.env` не подошёл (так бывает после обновления с 1.0), `kit` сам выпускает новый и сохраняет его, а если панель всё же не отвечает – говорит по-человечески (код ответа и вероятная причина), а не «Unsupported HTTP version in response».
|
||||||
* Сайт-заглушка теперь у каждого сервера своя: при установке она собирается из двадцати тем и пяти вёрсток со случайным названием, текстами и цветами. Пекарня, переводчик или мастерская по велосипедам – как повезёт. Раньше у многих серверов был один и тот же «облачный» сосед.
|
* Сайт-заглушка теперь у каждого сервера своя: при установке она собирается из двадцати тем и пяти вёрсток со случайным названием, текстами и цветами. Пекарня, переводчик или мастерская по велосипедам – как повезёт. Раньше у многих серверов был один и тот же «облачный» сосед. Hysteria2 показывает ту же страницу байт в байт: раньше теряла по дороге последний перевод строки – мелочь, а близнецы должны быть одинаковыми.
|
||||||
* `kit-sub` на своём порту (`--multi-port`) отвечает по HTTP/1.1 и с `Server: nginx` без лишнего пробела, а на бессмыслицу вместо запроса – честным `400 Bad Request` со строкой статуса. Ещё он говорит `Connection: keep-alive` и соглашается на `http/1.1` при знакомстве по TLS. Как настоящий nginx, а не его двоюродный брат.
|
* `kit-sub` на своём порту (`--multi-port`) отвечает по HTTP/1.1 и с `Server: nginx` без лишнего пробела, а на бессмыслицу вместо запроса – честным `400 Bad Request` со строкой статуса. Ещё он говорит `Connection: keep-alive` и соглашается на `http/1.1` при знакомстве по TLS. Как настоящий nginx, а не его двоюродный брат.
|
||||||
* Исправил `kit net masq on`: Hysteria2 после него переставала слушать порт до перезапуска панели, а `kit net fp` и `kit net on` спотыкались о то же. Панель меняет подключение на ходу, а ядро такую правку не принимает. Теперь `kit` проверяет порты после каждой правки и, если что-то закрылось, перезапускает ядро и честно об этом говорит. А `kit check` научился смотреть, запущено ли ядро Xray и слушает ли каждое подключение свой порт, TCP и UDP отдельно: nginx на 443/tcp больше не выдаёт себя за Hysteria2 на 443/udp.
|
* Исправил `kit net masq on`: Hysteria2 после него переставала слушать порт до перезапуска панели, а `kit net fp` и `kit net on` спотыкались о то же. Панель меняет подключение на ходу, а ядро такую правку не принимает. Теперь `kit` проверяет порты после каждой правки и, если что-то закрылось, перезапускает ядро и честно об этом говорит. А `kit check` научился смотреть, запущено ли ядро Xray и слушает ли каждое подключение свой порт, TCP и UDP отдельно: nginx на 443/tcp больше не выдаёт себя за Hysteria2 на 443/udp.
|
||||||
* `--restore` на новый IP, где Let's Encrypt не выдал сертификат (лимит или закрытый порт 80), раньше говорил «Готово», а ядро Xray не запускалось: подключения ждали сертификат, которого нет. Теперь я ставлю самоподписанный, закрепляю его отпечаток в ссылках и прямо говорю об этом. А если ядро всё же не поднялось, «Готово» не будет: покажу, где смотреть. Копию с пустой папкой сертификата `--restore` теперь отклоняет сразу, а не на полпути установки.
|
* `--restore` на новый IP, где Let's Encrypt не выдал сертификат (лимит или закрытый порт 80), раньше говорил «Готово», а ядро Xray не запускалось: подключения ждали сертификат, которого нет. Теперь я ставлю самоподписанный, закрепляю его отпечаток в ссылках и прямо говорю об этом. А если ядро всё же не поднялось, «Готово» не будет: покажу, где смотреть. Копию с пустой папкой сертификата `--restore` теперь отклоняет сразу, а не на полпути установки.
|
||||||
|
|||||||
+3
-2
@@ -691,7 +691,8 @@ main() {
|
|||||||
install -d -m 755 /var/www/kit
|
install -d -m 755 /var/www/kit
|
||||||
[[ -s /var/www/kit/index.html ]] || stub_site >/var/www/kit/index.html
|
[[ -s /var/www/kit/index.html ]] || stub_site >/var/www/kit/index.html
|
||||||
chmod 644 /var/www/kit/index.html
|
chmod 644 /var/www/kit/index.html
|
||||||
STUB_HTML=$(cat /var/www/kit/index.html)
|
# Байт в байт как у nginx: $(…) срезал бы последний перевод строки, и длина ответа Hysteria2 отличалась бы.
|
||||||
|
STUB_HTML=$(cat /var/www/kit/index.html; printf x); STUB_HTML=${STUB_HTML%x}
|
||||||
local p
|
local p
|
||||||
for p in "${PROTOS[@]}"; do "proto_$p"; done
|
for p in "${PROTOS[@]}"; do "proto_$p"; done
|
||||||
# Первый пользователь – сразу на всех протоколах (как «kit user add»).
|
# Первый пользователь – сразу на всех протоколах (как «kit user add»).
|
||||||
@@ -1413,7 +1414,7 @@ setup_nginx() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
install -d -m 755 /var/www/kit
|
install -d -m 755 /var/www/kit
|
||||||
[[ -f /var/www/kit/index.html ]] || { if [[ -n ${STUB_HTML:-} ]]; then printf '%s\n' "$STUB_HTML"; else stub_site; fi; } >/var/www/kit/index.html
|
[[ -f /var/www/kit/index.html ]] || { if [[ -n ${STUB_HTML:-} ]]; then printf '%s' "$STUB_HTML"; else stub_site; fi; } >/var/www/kit/index.html
|
||||||
|
|
||||||
# Маршруты – из текущих подключений панели: сайты REALITY, пути WebSocket, сервисы gRPC.
|
# Маршруты – из текущих подключений панели: сайты REALITY, пути WebSocket, сервисы gRPC.
|
||||||
local list reality_sni xhttp_sni mt_sni steal_domain locs="" kind path port
|
local list reality_sni xhttp_sni mt_sni steal_domain locs="" kind path port
|
||||||
|
|||||||
+2
-1
@@ -1764,7 +1764,8 @@ hy_masq() { # on|off
|
|||||||
id=$(api GET inbounds/list | jq -r '[.[] | select(.protocol == "hysteria")][0].id // empty')
|
id=$(api GET inbounds/list | jq -r '[.[] | select(.protocol == "hysteria")][0].id // empty')
|
||||||
[[ -n $id ]] || die "На сервере нет Hysteria2."
|
[[ -n $id ]] || die "На сервере нет Hysteria2."
|
||||||
if [[ $act == on ]]; then
|
if [[ $act == on ]]; then
|
||||||
page=$(cat /var/www/kit/index.html 2>/dev/null || true)
|
# Байт в байт как у nginx (с последним переводом строки).
|
||||||
|
page=$(cat /var/www/kit/index.html 2>/dev/null && printf x || true); page=${page%x}
|
||||||
# Страницы нет только у старых установок с отдельными портами – тогда простая страница без названия.
|
# Страницы нет только у старых установок с отдельными портами – тогда простая страница без названия.
|
||||||
[[ -n $page ]] || page='<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Welcome</title></head><body style="font-family:sans-serif;text-align:center;margin-top:20vh"><h1>Welcome</h1><p>This site is being updated. Please check back soon.</p></body></html>'
|
[[ -n $page ]] || page='<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Welcome</title></head><body style="font-family:sans-serif;text-align:center;margin-top:20vh"><h1>Welcome</h1><p>This site is being updated. Please check back soon.</p></body></html>'
|
||||||
inbound_patch "$id" '.streamSettings |= ((if type == "string" then fromjson else . end) | .hysteriaSettings.masquerade = {type: "string", content: $c, statusCode: 200, headers: {"content-type": "text/html; charset=utf-8"}})' --arg c "$page" \
|
inbound_patch "$id" '.streamSettings |= ((if type == "string" then fromjson else . end) | .hysteriaSettings.masquerade = {type: "string", content: $c, statusCode: 200, headers: {"content-type": "text/html; charset=utf-8"}})' --arg c "$page" \
|
||||||
|
|||||||
@@ -73,5 +73,28 @@ class Stub(unittest.TestCase):
|
|||||||
self.assertLess(ends.count(top), N * 0.08, (top, ends.count(top)))
|
self.assertLess(ends.count(top), N * 0.08, (top, ends.count(top)))
|
||||||
|
|
||||||
|
|
||||||
|
class SamePage(unittest.TestCase):
|
||||||
|
"""Hysteria2 (masquerade) отдаёт заглушку байт в байт как nginx – с последним переводом строки."""
|
||||||
|
|
||||||
|
def read(self, line, var):
|
||||||
|
import tempfile
|
||||||
|
d = tempfile.mkdtemp()
|
||||||
|
f = os.path.join(d, "index.html")
|
||||||
|
with open(f, "wb") as fh:
|
||||||
|
fh.write(b"<html>\n<p>x</p>\n\n")
|
||||||
|
line = line.replace("/var/www/kit/index.html", f)
|
||||||
|
r = subprocess.run(["bash", "-c", line + '\nprintf %s "$' + var + '"'], capture_output=True)
|
||||||
|
return r.stdout
|
||||||
|
|
||||||
|
def test_installer(self):
|
||||||
|
line = re.search(r"^ STUB_HTML=\$\(cat /var/www/kit/index\.html.*$", src, re.M).group(0)
|
||||||
|
self.assertEqual(self.read(line, "STUB_HTML"), b"<html>\n<p>x</p>\n\n")
|
||||||
|
|
||||||
|
def test_kit_masq(self):
|
||||||
|
kit = open(os.path.join(root, "scripts", "kit.sh"), encoding="utf-8").read()
|
||||||
|
line = re.search(r"^ page=\$\(cat /var/www/kit/index\.html.*$", kit, re.M).group(0)
|
||||||
|
self.assertEqual(self.read(line, "page"), b"<html>\n<p>x</p>\n\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user