Files
singbox_glue/docs/architecture.md
T

3.9 KiB
Raw Blame History

Архитектура

Границы ответственности

Hysteria2 URI содержит только переносимые реквизиты VPN:

  • authentication;
  • hostname и port/port ranges;
  • SNI и insecure;
  • salamander и obfs password.

policy.json содержит локальную инфраструктурную политику:

  • eth0 — upstream;
  • eth1 — VPN LAN;
  • tun-sb0, 172.19.0.1/30, MTU 1400;
  • TUN routes, nftables marks и rule/table indexes;
  • bootstrap DNS и DoH через hy2-out;
  • bandwidth hints и healthcheck.

Renderer не патчит существующий JSON. Полная конфигурация каждый раз строится из typed model. Это устраняет config drift и исторические endpoint /32.

Поток применения

URI + policy
    │
    ├─ strict parsing / schema validation
    ├─ exact sing-box version and build-tag gate
    ├─ deterministic render
    ├─ secure candidate in /etc/sing-box
    └─ sing-box check -c candidate
             │
             ▼
       redacted comparison
             │
     unchanged ─────── changed
         │                │
         ▼                ├─ last-good backup
      no restart          ├─ atomic replace
                          ├─ systemctl restart
                          └─ bounded healthcheck
                                  │
                             fail ┴ success
                              │       │
                              ▼       ▼
                         rollback    state.json

Все операции изменения сериализованы flock-совместимой блокировкой. Поэтому ручной import и запоздалый event от systemd.path не могут применять два candidate одновременно.

Почему endpoint IP не нужен

Outbound сохраняет DNS hostname и содержит bind_interface=eth0. В 1.13.19 route.auto_detect_interface не применяется к outbound с явным bind_interface. Bootstrap DNS также привязан к eth0. Endpoint IP поэтому не является частью TUN policy.

После смены A-записи следующая Hysteria2-сессия разрешает имя заново через bootstrap-dns. doctor дополнительно проверяет, что текущие A-записи не попали в exclusions.

Файловая модель

/etc/vpn-egress/
├── policy.json            root:root 0600
└── hysteria2.uri          root:root 0600

/var/lib/vpn-egress/
├── state.json             без секретов, 0600
├── last-good.json         содержит secrets, 0600
└── backups/               ограниченная история, 0700/0600

/etc/sing-box/
└── config.json            root:root 0600

Service sing-box уже имеет CAP_DAC_READ_SEARCH, поэтому сохраняется текущая рабочая модель root:root 0600.

Guard читает имена интерфейсов из того же policy и устанавливает всю nftables таблицу одной batch-транзакцией. Если новый ruleset некорректен, nft не оставляет систему с частично заменённой таблицей.

Версионная граница

В коде существует только renderer_1_13_19.py. Renderer для 1.14 не является пустой заготовкой: он появится только в отдельной миграции после аудита схемы, маршрутизации и полных интеграционных тестов.