fix: adopt sing-box 1.14 DNS hijacking
This commit is contained in:
+33
-17
@@ -3,7 +3,8 @@
|
||||
## Границы ответственности
|
||||
|
||||
Hysteria2 URI содержит переносимые реквизиты: auth, hostname/ports, SNI,
|
||||
`insecure`, тип obfs и obfs password. Production HY2XS выдаёт Gecko URI.
|
||||
`insecure`, тип obfs и obfs password. Новые production-установки HY2XS получают
|
||||
Gecko URI. Salamander остаётся явно согласуемым compatibility fallback.
|
||||
|
||||
`policy.json` хранит локальную инфраструктуру: `eth0`, `eth1`, TUN CIDR и MTU,
|
||||
route exclusions, таблицу 2022, marks, NFQUEUE, DNS, bandwidth и healthcheck.
|
||||
@@ -20,18 +21,24 @@ URI + policy
|
||||
├─ renderer_1_14_0
|
||||
└─ sing-box check на private candidate
|
||||
│
|
||||
unchanged ───── changed
|
||||
│ │
|
||||
▼ ├─ проверка provenance текущего config
|
||||
state.json ├─ versioned last-good backup
|
||||
├─ atomic replace
|
||||
├─ systemctl restart
|
||||
└─ bounded healthcheck
|
||||
current отсутствует ── current существует
|
||||
│ │
|
||||
│ provenance gate
|
||||
│ │
|
||||
│ unchanged ───── changed
|
||||
│ │ │
|
||||
│ ▼ ├─ versioned last-good backup
|
||||
│ state.json │
|
||||
└────────────────────────────────┼─ atomic replace
|
||||
├─ systemctl restart
|
||||
└─ bounded healthcheck
|
||||
```
|
||||
|
||||
Первое применение после чистой установки не создаёт `last-good`: предыдущего
|
||||
управляемого конфига нет. При следующих изменениях backup разрешён только если
|
||||
SHA установленного config совпадает со state этого же релиза и sing-box 1.14.0.
|
||||
Побайтовое совпадение с candidate не доказывает ownership: существующий config
|
||||
без такого state отклоняется и не «усыновляется» контроллером.
|
||||
|
||||
## Gecko и DNS
|
||||
|
||||
@@ -39,11 +46,20 @@ Renderer добавляет для Gecko `min_packet_size=512` и
|
||||
`max_packet_size=1200`. Эти параметры являются частью локального HY2XS
|
||||
compatibility profile и не читаются из URI.
|
||||
|
||||
В sing-box 1.14.0 TUN по умолчанию использует `dns_mode=hijack`, что меняет
|
||||
настройки интерфейса и platform-level interception. Проект явно задаёт
|
||||
`dns_mode=disabled` и сохраняет собственное route action `port 53 ->
|
||||
hijack-dns`. Bootstrap UDP DNS привязан к `eth0`; remote DoH использует detour
|
||||
`hy2-out`.
|
||||
Renderer явно задаёт штатный для sing-box 1.14.0 `dns_mode=hijack`. Поле
|
||||
`dns_address` не задаётся: sing-box выводит IPv4 DNS address `172.19.0.2` как
|
||||
следующий адрес после `172.19.0.1/30`, автоматически связывает его с DNS module
|
||||
и при `auto_redirect=true` устанавливает nftables DNAT для TCP/UDP 53. Поэтому
|
||||
отдельного route action `hijack-dns` в generated config нет.
|
||||
|
||||
Bootstrap UDP DNS привязан к `eth0`; remote DoH использует detour `hy2-out`.
|
||||
Собственный outbound sing-box исключается из auto-redirect по output mark, что
|
||||
необходимо подтвердить privileged Linux acceptance без bootstrap recursion.
|
||||
|
||||
Platform hijack не создаёт DNS listener на локальном LAN-адресе шлюза: трафик к
|
||||
такому адресу попадает в kernel `local` table раньше пользовательских rules.
|
||||
Если DHCP должен выдавать сам gateway как DNS server, требуется отдельный
|
||||
listener/service, который не входит в контракт 0.2.0.
|
||||
|
||||
## Endpoint routing
|
||||
|
||||
@@ -73,7 +89,7 @@ Metadata не обеспечивает доверие от root-компроме
|
||||
|
||||
## Граница установки
|
||||
|
||||
0.2.0 не содержит кода миграции 0.1.0. `debian/preinst` отклоняет in-place
|
||||
upgrade, а `postinst` отклоняет legacy policy/state или unmanaged
|
||||
`/etc/sing-box/config.json`. Same-release reinstall допускается, если state и
|
||||
config согласованы.
|
||||
0.2.0 не содержит кода миграции 0.1.0. `debian/preinst` отклоняет установку
|
||||
поверх любого другого релиза, а `postinst` отклоняет legacy policy/state или
|
||||
unmanaged `/etc/sing-box/config.json`. Same-release reinstall 0.2.0 допускается,
|
||||
если state и config согласованы.
|
||||
|
||||
@@ -59,8 +59,10 @@ obfs=salamander -> требуется obfs-password; compatibility fallback
|
||||
password без obfs -> ошибка
|
||||
```
|
||||
|
||||
Для HY2XS допустимым production-режимом считается только Gecko. Salamander не
|
||||
включается на сервере и не выбирается автоматически.
|
||||
Для новых HY2XS production-установок Gecko является режимом по умолчанию.
|
||||
Salamander полностью поддерживается как compatibility fallback, но требует
|
||||
явного совпадения режима и password на сервере и клиенте. Автоматического
|
||||
переключения между Gecko и Salamander нет.
|
||||
|
||||
Query parser применяет RFC percent-decoding, но не form decoding: сырой `+`
|
||||
сохраняется как `+`, `%2B` также превращается в `+`, а `%26`/`%3D` безопасно
|
||||
|
||||
+7
-2
@@ -7,6 +7,9 @@ In-place upgrade 0.1.0 → 0.2.0, автоматическая миграция
|
||||
отклоняет upgrade. Установка выполняется через удаление старого пакета,
|
||||
архивирование его данных и настройку 0.2.0 с нуля.
|
||||
|
||||
Повторная установка ровно 0.2.0 поверх согласованного состояния 0.2.0 не
|
||||
является миграцией и поддерживается без этого runbook.
|
||||
|
||||
Описанные действия выполнять из console/maintenance-доступа. До успешного E2E
|
||||
anti-leak guard должен оставаться в nftables.
|
||||
|
||||
@@ -62,7 +65,7 @@ systemctl daemon-reload
|
||||
проверку: архивировать указанный объект и повторить `dpkg --configure
|
||||
vpn-egressctl`.
|
||||
|
||||
## 5. Настроить новую policy и Gecko URI
|
||||
## 5. Настроить новую policy и URI
|
||||
|
||||
Редактировать новый `/etc/vpn-egress/policy.json` вручную. Из старой policy
|
||||
можно перенести осознанно проверенные локальные значения, но нельзя заменять ею
|
||||
@@ -78,7 +81,9 @@ vpn-egressctl check
|
||||
vpn-egressctl diff
|
||||
```
|
||||
|
||||
Проверить, что URI содержит `obfs=gecko`. `check` не запускает service.
|
||||
Для новой production-установки проверить, что URI содержит `obfs=gecko`.
|
||||
`obfs=salamander` допускается только для явно настроенного server-side
|
||||
compatibility fallback. `check` не запускает service.
|
||||
|
||||
## 6. Активировать защиту и config
|
||||
|
||||
|
||||
+7
-5
@@ -12,8 +12,10 @@ sudo vpn-egressctl import --stdin
|
||||
sudo vpn-egressctl import --file /run/credentials/new-hysteria2.uri
|
||||
```
|
||||
|
||||
Production URI HY2XS должен использовать Gecko. Не передавать URI через argv,
|
||||
environment, shell history, тикет или журнал.
|
||||
Для новой установки production URI HY2XS должен использовать Gecko. Salamander
|
||||
допустим как compatibility fallback только при явно совпадающей серверной
|
||||
настройке. Не передавать URI через argv, environment, shell history, тикет или
|
||||
журнал.
|
||||
|
||||
## Изменение policy
|
||||
|
||||
@@ -57,6 +59,6 @@ systemctl reset-failed vpn-egress-sync.service
|
||||
## Обновления package/engine
|
||||
|
||||
0.2.0 не объявляет совместимость с другими версиями приложения или sing-box.
|
||||
Любой следующий переход выполняется по отдельному release runbook как clean
|
||||
install. `apt upgrade` не считается допустимой процедурой обновления этого
|
||||
control plane.
|
||||
Переход на другой release выполняется по отдельному release runbook как clean
|
||||
install. Повторная установка ровно 0.2.0 допускается при согласованных state и
|
||||
config; `apt upgrade` на другой release не считается допустимой процедурой.
|
||||
|
||||
+9
-3
@@ -45,9 +45,15 @@ runtime-состояние проверяет `vpn-egressctl doctor`.
|
||||
|
||||
## DNS и TLS
|
||||
|
||||
`dns_mode=disabled` запрещает новому TUN-механизму 1.14 менять native DNS и
|
||||
platform interception. DNS контролируется явной route rule. Chrome QUIC
|
||||
parroting включён (`disable_chrome_parrot=false`); production acceptance обязан
|
||||
`dns_mode=hijack` включает native DNS integration и platform-level interception
|
||||
TCP/UDP 53. При `auto_redirect` sing-box направляет non-local DNS на автоматически
|
||||
выведенный TUN address `172.19.0.2`; явная route rule не используется. Linux не
|
||||
может этим механизмом перенаправить DNS, адресованный локальному IP самого
|
||||
шлюза. DoH/DoT также не распознаются как DNS, но проходят через общий TUN/VPN
|
||||
маршрут как обычный трафик.
|
||||
|
||||
Chrome QUIC parroting включён upstream default; поле
|
||||
`disable_chrome_parrot=false` не рендерится. Production acceptance обязан
|
||||
подтвердить совместимый RSA/ECDSA/ACME certificate, поскольку Ed25519 с этим
|
||||
режимом несовместим.
|
||||
|
||||
|
||||
+15
-7
@@ -17,19 +17,27 @@
|
||||
```
|
||||
|
||||
512/1200 совпадает с profile HY2XS и текущими upstream defaults, но рендерится
|
||||
явно. Hysteria отмечает Gecko как experimental; проект осознанно принимает его
|
||||
как единственный production obfs сервера HY2XS.
|
||||
явно. Hysteria отмечает Gecko как experimental; проект осознанно использует его
|
||||
по умолчанию для новых production-установок HY2XS. Salamander остаётся полностью
|
||||
поддержанным compatibility fallback при совпадающей серверной настройке.
|
||||
|
||||
### TUN DNS
|
||||
|
||||
Новый default `dns_mode=hijack` не используется. Renderer задаёт `disabled`,
|
||||
потому что проект уже имеет явную DNS route rule и отдельные bootstrap/DoH
|
||||
маршруты. Это решение должно подтверждаться privileged Linux acceptance.
|
||||
Renderer явно задаёт `dns_mode=hijack`. При `auto_redirect=true` sing-box
|
||||
перехватывает TCP/UDP 53 на platform level. `dns_address` намеренно отсутствует:
|
||||
sing-box выводит следующий адрес из TUN subnet (`172.19.0.2`) и автоматически
|
||||
передаёт обращения к нему в DNS module. Явная route rule `hijack-dns` поэтому
|
||||
удалена.
|
||||
|
||||
Bootstrap DNS остаётся UDP outbound с `bind_interface=eth0`, remote DoH — с
|
||||
`detour=hy2-out`. Отсутствие bootstrap loop и DNS leak является обязательным
|
||||
privileged Linux acceptance gate.
|
||||
|
||||
### Chrome QUIC parroting
|
||||
|
||||
Renderer явно задаёт `disable_chrome_parrot=false`. Серверный certificate должен
|
||||
быть RSA/ECDSA/ACME, не Ed25519.
|
||||
Renderer не задаёт `disable_chrome_parrot`: в exact 1.14.0 upstream default
|
||||
оставляет Chrome QUIC parroting включённым. Серверный certificate должен быть
|
||||
RSA/ECDSA/ACME, не Ed25519.
|
||||
|
||||
### Congestion control
|
||||
|
||||
|
||||
+31
-12
@@ -5,7 +5,8 @@
|
||||
1. Unit: URI, policy, version, renderer, redaction и metadata.
|
||||
2. Failure injection: candidate rejection, restart failure, URI/config restore,
|
||||
unmanaged config, corrupted/legacy last-good.
|
||||
3. Packaging: MPL-2.0, exact dependency, upgrade rejection и postinst guard.
|
||||
3. Packaging: MPL-2.0, exact dependency, cross-release rejection,
|
||||
same-release reinstall и postinst guard.
|
||||
4. Real binary: официальный sing-box 1.14.0 для Gecko и Salamander configs.
|
||||
5. Privileged Linux: TUN, systemd, nftables, routing и DNS.
|
||||
6. HY2XS acceptance: Gecko TCP/UDP/DNS, failures, reconnect и reboot.
|
||||
@@ -38,15 +39,33 @@ Windows — schema decoding через `format`, поскольку Windows bina
|
||||
|
||||
В disposable Incus/VM с двумя NIC проверить:
|
||||
|
||||
1. чистую установку и отказ in-place upgrade;
|
||||
2. Gecko config и отсутствие last-good после первого apply;
|
||||
3. table 2022, rule 9000/32768, marks и NFQUEUE 100;
|
||||
4. bootstrap DNS через `eth0`, DoH через `hy2-out`;
|
||||
5. TCP/UDP/DNS с workload за `eth1`;
|
||||
6. отсутствие прямого WAN при остановленном sing-box;
|
||||
7. credential failure и same-release rollback;
|
||||
8. отказ legacy/mismatched metadata;
|
||||
9. A-record change и reboot recovery.
|
||||
1. собрать package и выполнить чистую установку;
|
||||
2. повторно установить ровно 0.2.0 поверх согласованного состояния;
|
||||
3. подтвердить отказ переходов 0.1.x → 0.2.0 и другой release → 0.2.0;
|
||||
4. применить Gecko config и подтвердить отсутствие `last-good` после первого
|
||||
apply;
|
||||
5. проверить table 2022, rule 9000/32768, marks и NFQUEUE 100;
|
||||
6. до установления HY2 разрешить hostname endpoint через `bootstrap-dns` по
|
||||
`eth0`, без recursion в `172.19.0.2`;
|
||||
7. подтвердить DoH `remote-dns` через `hy2-out`;
|
||||
8. с хоста выполнить `getent hosts example.com`, `dig @8.8.8.8 example.com` и
|
||||
`dig +tcp @8.8.8.8 example.com`;
|
||||
9. повторить оба `dig` с workload за `eth1` и через `tcpdump`/nft counters
|
||||
подтвердить отсутствие реального TCP/UDP 53 через `eth0`;
|
||||
10. при наличии `systemd-resolved` проверить DNS и route-only domain `~.` для
|
||||
`tun-sb0`; отдельно повторить запуск без доступного `resolvectl`;
|
||||
11. проверить TCP/UDP и внешний VPN IP с workload за `eth1`;
|
||||
12. подтвердить отсутствие прямого WAN при остановленном sing-box;
|
||||
13. проверить credential failure и same-release rollback;
|
||||
14. проверить отказ legacy/mismatched metadata и unmanaged identical config;
|
||||
15. проверить смену A-record, reconnect, stop/start и reboot recovery;
|
||||
16. после stop убедиться в очистке sing-box nftables/resolved state, после start
|
||||
— в полном восстановлении.
|
||||
|
||||
Server-side Gecko E2E выполняет владелец HY2XS. Salamander проверяется только на
|
||||
disposable test server и не добавляется в production server configuration.
|
||||
Server-side Gecko E2E выполняется с production-compatible HY2XS. Salamander E2E
|
||||
выполняется на disposable server, явно настроенном в compatibility-режим; это не
|
||||
автоматический fallback и не default новой production-установки.
|
||||
|
||||
Platform hijack не обслуживает DNS, направленный на локальный LAN IP gateway.
|
||||
Такой сценарий допустим только после добавления отдельного DNS listener и не
|
||||
входит в acceptance версии 0.2.0.
|
||||
|
||||
+12
-3
@@ -12,17 +12,19 @@ vpn-egressctl status --json
|
||||
Установлена не exact `1.14.0` либо отсутствуют `with_quic`/`with_gvisor`.
|
||||
Конфигурация не изменялась. Не обходить version gate.
|
||||
|
||||
## In-place upgrades are not supported
|
||||
## Cross-release upgrades are not supported
|
||||
|
||||
Пакет 0.2.0 устанавливается поверх старого релиза. Старый package остаётся
|
||||
Пакет 0.2.0 устанавливается поверх другого релиза. Старый package остаётся
|
||||
установленным; выполнить clean-install runbook из `docs/migration.md`.
|
||||
Повторная установка ровно 0.2.0 поддерживается, если state и config согласованы.
|
||||
|
||||
## State from another release / unmanaged configuration
|
||||
|
||||
Обнаружены сохранённые файлы 0.1.0 или конфиг вне управления 0.2.0. Остановить
|
||||
sing-box, убедиться в наличии guard, переместить старые данные в защищённый архив
|
||||
и повторить `dpkg --configure vpn-egressctl`. Не редактировать старый state так,
|
||||
чтобы обойти проверку.
|
||||
чтобы обойти проверку. Даже побайтово идентичный candidate не делает unmanaged
|
||||
config принадлежащим этому релизу.
|
||||
|
||||
## sing-box rejected generated configuration
|
||||
|
||||
@@ -54,3 +56,10 @@ Backup и metadata рассогласованы или повреждены. А
|
||||
|
||||
Проверить DNS, Gecko password, auth, SNI, certificate, UDP path и nftables.
|
||||
Успешный локальный healthcheck не заменяет forwarding E2E с `eth1`.
|
||||
|
||||
## DNS hijack не обслуживает LAN IP шлюза
|
||||
|
||||
`dns_mode=hijack` перехватывает TCP/UDP 53 только к non-local destination. Если
|
||||
LAN-клиент обращается к адресу самого gateway, например `10.20.0.1:53`, нужен
|
||||
отдельный DNS listener/service. Не добавлять `dns_address` вручную и не
|
||||
возвращать route rule как workaround: это меняет проверенный контракт renderer.
|
||||
|
||||
Reference in New Issue
Block a user