Some checks failed
Windows project source guards / test (push) Failing after 1m8s
`proxy-dns` был DoH к 8.8.8.8/1.1.1.1/9.9.9.9 через outbound `proxy`. Узел перенаправляет на свой resolver только DNS на порт 53, а зашифрованный запрос проходит мимо: клиент получал настоящий origin управляемого имени и шёл к нему через тот же узел, получая региональный отказ. Через Hysteria 2 sing-box отдаёт ядру уже готовый IP, поэтому подменить адрес на узле было нечем. `proxy-dns` теперь перебирает два транспорта до resolver'а узла: udp, затем tcp для сетей, где UDP через прокси не проходит. Прежний тихий откат на `bootstrap-dns` убран — после шестисекундного таймаута он уводил резолв наружу из туннеля. `bootstrap-dns` и `direct-doh` не тронуты: они поднимают туннель и обязаны пережить подмену DNS провайдером. Точечный отказ DoT на 853 возвращает приложения на 53, который перехватывает `hijack-dns`. Встроенный DoH приложений на 443 перехвату не поддаётся — это записано в docs/sing-box/runtime-config.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
67 lines
3 KiB
Python
67 lines
3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
YANDEX_MUSIC_PROCESSES = {"Яндекс Музыка.exe", "yandexmusic.exe"}
|
|
|
|
|
|
class YandexMusicDirectTemplateTests(unittest.TestCase):
|
|
def test_all_singbox_templates_route_yandex_music_direct_first(self) -> None:
|
|
template_dir = ROOT / "data" / "templates" / "sing-box"
|
|
|
|
for path in sorted(template_dir.glob("*.json")):
|
|
with self.subTest(template=path.name):
|
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
rules = payload["route"]["rules"]
|
|
direct_index = next(
|
|
index
|
|
for index, rule in enumerate(rules)
|
|
if set(rule.get("process_name", [])) == YANDEX_MUSIC_PROCESSES
|
|
)
|
|
direct_rule = rules[direct_index]
|
|
|
|
self.assertEqual(direct_rule.get("action"), "route")
|
|
self.assertEqual(direct_rule.get("outbound"), "direct")
|
|
self.assertTrue(
|
|
all(
|
|
rule.get("action") in {"sniff", "hijack-dns"}
|
|
or rule.get("outbound") == "block"
|
|
# Точечный отказ DoT — тоже обработка протокола: он
|
|
# возвращает приложение на 53, который перехватывает
|
|
# hijack-dns.
|
|
or (rule.get("action") == "reject" and rule.get("port") == 853)
|
|
for rule in rules[:direct_index]
|
|
),
|
|
"Only protocol handling and narrow block rules may precede Yandex Music direct",
|
|
)
|
|
|
|
def test_all_xray_templates_route_yandex_music_direct_first(self) -> None:
|
|
template_dir = ROOT / "data" / "templates" / "xray"
|
|
|
|
for path in sorted(template_dir.glob("*.json")):
|
|
with self.subTest(template=path.name):
|
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
rules = payload["routing"]["rules"]
|
|
direct_index = next(
|
|
index
|
|
for index, rule in enumerate(rules)
|
|
if set(rule.get("process", [])) == YANDEX_MUSIC_PROCESSES
|
|
)
|
|
direct_rule = rules[direct_index]
|
|
|
|
self.assertEqual(direct_rule.get("type"), "field")
|
|
self.assertEqual(set(direct_rule.get("process", [])), YANDEX_MUSIC_PROCESSES)
|
|
self.assertEqual(direct_rule.get("network"), "tcp,udp")
|
|
self.assertEqual(direct_rule.get("outboundTag"), "direct")
|
|
self.assertTrue(
|
|
all(rule.get("outboundTag") == "block" for rule in rules[:direct_index]),
|
|
"Only narrow block rules may precede Yandex Music direct",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|