Refine routing defaults for global and device fallbacks
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 17s
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 17s
This commit is contained in:
86
README.md
86
README.md
@@ -18,7 +18,7 @@
|
||||
▼
|
||||
iptables mangle PREROUTING → цепочка VPN_PROXY_TPROXY
|
||||
│
|
||||
├─ ipset vpn_direct_bypass (dst IP) → RETURN ← bypass-кэш ядра
|
||||
├─ ipset vpn_direct_bypass (dst IP) → RETURN ← опциональный bypass-кэш
|
||||
├─ приватные CIDR (RFC1918, ...) → RETURN
|
||||
└─ TCP/UDP → TPROXY :7895
|
||||
│
|
||||
@@ -32,6 +32,12 @@ iptables mangle PREROUTING → цепочка VPN_PROXY_TPROXY
|
||||
direct VPN out block
|
||||
```
|
||||
|
||||
ПК-приложения, которым нужен VPN явно:
|
||||
|
||||
```
|
||||
Windows app → ProxiFyre/Proxifier → gateway:8080 → sing-box mixed-in → global rules → default VPN
|
||||
```
|
||||
|
||||
**Node.js API-сервер** (`src/server/index.js`) работает внутри того же контейнера:
|
||||
управляет процессом sing-box, парсит его логи, экспортирует REST API и SSE-стримы для веб-интерфейса.
|
||||
|
||||
@@ -43,7 +49,7 @@ iptables mangle PREROUTING → цепочка VPN_PROXY_TPROXY
|
||||
| ---------------- | ------------------------------------------------------------- |
|
||||
| Контейнер | Docker, `network_mode: host`, `CAP_NET_ADMIN` + `CAP_NET_RAW` |
|
||||
| Перехват трафика | iptables TProxy + iproute2 policy routing |
|
||||
| Bypass-кэш | ipset `hash:ip` с TTL |
|
||||
| Bypass-кэш | опциональный ipset `hash:ip` с TTL |
|
||||
| VPN-ядро | sing-box (VLESS/VLESS-Reality/VMess/Trojan/Hysteria2/SS) |
|
||||
| API-сервер | Node.js 18, plain `http` (без фреймворков) |
|
||||
| Веб-интерфейс | React 18 + Vite 7, SPA |
|
||||
@@ -65,7 +71,7 @@ ip route replace local 0.0.0.0/0 dev lo table 100
|
||||
iptables -t mangle -N VPN_PROXY_TPROXY
|
||||
-m addrtype --dst-type LOCAL → RETURN # ответы самого sing-box
|
||||
-m mark --mark 1 → RETURN # уже помеченные пакеты
|
||||
-m set --match-set vpn_direct_bypass → RETURN # bypass-кэш (см. ниже)
|
||||
-m set --match-set vpn_direct_bypass → RETURN # только если DIRECT_BYPASS_CACHE=true
|
||||
-d 10.0.0.0/8, 192.168.0.0/16, ... → RETURN # приватные адреса
|
||||
-p tcp → TPROXY :7895 mark 1
|
||||
-p udp → TPROXY :7895 mark 1
|
||||
@@ -82,10 +88,12 @@ ipset-кэш намеренно **не** очищается — записи и
|
||||
| Приоритет | Условие | Действие |
|
||||
| --------- | ------------------------------------------- | ---------------------------------------- |
|
||||
| 1 | `ip_is_private: true` | `direct` (защита LAN) |
|
||||
| 2 | Правила по устройствам (source IP) | `direct` / `vpn` / `block` |
|
||||
| 3 | Кастомные правила пользователя | `direct` / `vpn` / `block` |
|
||||
| 4 | `rule_set: [geoip-ru, geosite-category-ru]` | `direct` (если `ROUTING_RU_DIRECT=true`) |
|
||||
| 5 | Всё остальное (`final`) | выбранный VPN-outbound |
|
||||
| 2 | Global custom rules | `direct` / VPN / `block` для всех inbound |
|
||||
| 3 | `rule_set: [geoip-ru, geosite-category-ru]` | `direct` |
|
||||
| 4 | Device defaults для `tproxy-in` | `direct` / VPN / `block` |
|
||||
| 5 | Proxy default для `mixed-in` | по умолчанию VPN |
|
||||
| 6 | Transparent default для unknown devices | по умолчанию `direct` |
|
||||
| 7 | Всё остальное (`final`) | `direct` |
|
||||
|
||||
Конфиг генерируется динамически через `buildGatewayConfig()` из подписки + сохранённых правил. Перед применением выполняется `sing-box check`.
|
||||
|
||||
@@ -97,7 +105,9 @@ ipset-кэш намеренно **не** очищается — записи и
|
||||
|
||||
## Direct Bypass Cache (ipset)
|
||||
|
||||
Оптимизация для прямого трафика: IP-адреса, которые sing-box уже отправил напрямую, кэшируются в ядре и больше не проходят через userspace.
|
||||
Оптимизация выключена по умолчанию: `DIRECT_BYPASS_CACHE=false`. Причина — dst-IP cache обходит sing-box до проверки global rules, а значит может нарушить требования вида `AI → VPN` или `blocked → block`.
|
||||
|
||||
Если явно включить `DIRECT_BYPASS_CACHE=true`, IP-адреса, которые sing-box уже отправил напрямую, кэшируются в ядре и больше не проходят через userspace.
|
||||
|
||||
**Цепочка событий:**
|
||||
|
||||
@@ -121,16 +131,54 @@ ipset-кэш намеренно **не** очищается — записи и
|
||||
4. Запись истекает через TTL (по умолчанию 1 час).
|
||||
|
||||
```
|
||||
DIRECT_BYPASS_CACHE=false # безопасное значение по умолчанию
|
||||
DIRECT_BYPASS_SET=vpn_direct_bypass # имя ipset
|
||||
DIRECT_BYPASS_TTL=3600 # TTL в секундах
|
||||
```
|
||||
|
||||
## Профили устройств
|
||||
|
||||
Управляются из UI на вкладке **Маршрутизация** и сохраняются в `devices.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultTransparentMode": "direct",
|
||||
"proxyDefaultMode": "vpn",
|
||||
"devices": [
|
||||
{
|
||||
"id": "gaming-pc",
|
||||
"name": "Gaming PC",
|
||||
"ip": "192.168.1.50",
|
||||
"mac": "",
|
||||
"mode": "direct",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "phone",
|
||||
"name": "Phone",
|
||||
"ip": "192.168.1.60",
|
||||
"mode": "vpn",
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Mode | Что делает |
|
||||
| -------- | ----------------------------------------------------------------- |
|
||||
| `direct` | fallback устройства после global rules → `direct` |
|
||||
| `vpn` | fallback устройства после global rules → выбранный VPN |
|
||||
| `block` | fallback устройства после global rules → `block` |
|
||||
| `rules` | не задаёт fallback устройства; используется transparent default |
|
||||
|
||||
`mixed-in` не зависит от режима устройства: если приложение явно пошло на `gateway:8080`, сначала применяются global rules, затем `proxyDefaultMode` (по умолчанию VPN).
|
||||
|
||||
---
|
||||
|
||||
## Кастомные правила маршрутизации
|
||||
|
||||
Управляются из вкладки **Правила**. Сохраняются в `custom-rules.json`.
|
||||
Правила применяются в порядке отображения в UI — **first match wins**.
|
||||
Управляются из вкладки **Маршрутизация**. Сохраняются в `custom-rules.json`.
|
||||
Правила применяются в порядке отображения в UI — **first match wins**. Custom rules являются global rules: они применяются для `tproxy-in`, `mixed-in`, ПК, телефона и unknown devices до любых fallback-режимов.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
| ---------------- | ---------------------------- | ------------------------------------------- |
|
||||
@@ -189,7 +237,7 @@ Node.js читает stderr sing-box и извлекает трафик двум
|
||||
1. `[router]`-строка → имя правила сохраняется с TTL 500 мс
|
||||
2. Следующая строка с `-->` подхватывает имя в поле `matchedRule`
|
||||
3. Тип трафика: `direct` / `vpn` / `block` по outbound
|
||||
4. Direct + IPv4 → добавление в ipset bypass-кэш
|
||||
4. Direct + IPv4 → добавление в ipset bypass-кэш, только если `DIRECT_BYPASS_CACHE=true`
|
||||
|
||||
### Группировка и сортировка
|
||||
|
||||
@@ -205,9 +253,11 @@ Node.js читает stderr sing-box и извлекает трафик двум
|
||||
Вкладка **Проверка** позволяет узнать, по какому правилу пойдёт трафик к хосту/IP/порту — без реального подключения. Node.js (`routeMatcher.js`) симулирует ту же логику, что и sing-box:
|
||||
|
||||
1. private IP → direct
|
||||
2. custom rules (first-match)
|
||||
3. geoip-ru / geosite-category-ru → "вероятно direct" (без локальной БД точно неизвестно)
|
||||
4. final → VPN
|
||||
2. global custom rules
|
||||
3. geoip-ru / geosite-category-ru → direct
|
||||
4. `tproxy-in` + device default
|
||||
5. `mixed-in` + proxy default
|
||||
6. final → direct
|
||||
|
||||
---
|
||||
|
||||
@@ -237,9 +287,12 @@ UI доступен на `http://<gateway-ip>:3456`.
|
||||
| `DATA_DIR` | `/var/lib/vpn-proxy` | Директория данных (volume) |
|
||||
| `ROUTING_RU_DIRECT` | `true` | geoip-ru/geosite-ru → direct |
|
||||
| `LOG_LEVEL` | `info` | Уровень логов sing-box |
|
||||
| `DIRECT_BYPASS_CACHE` | `false` | Включить dst-IP bypass cache; по умолчанию выключен |
|
||||
| `DIRECT_BYPASS_SET` | `vpn_direct_bypass` | Имя ipset bypass-кэша |
|
||||
| `DIRECT_BYPASS_TTL` | `3600` | TTL записей (секунды) |
|
||||
| `PROXY_BIND_IP` | `127.0.0.1` | Bind для HTTP/SOCKS; `0.0.0.0` для LAN |
|
||||
| `PROXY_FIREWALL` | `true` | Закрыть `PROXY_PORT` не из allowed CIDR |
|
||||
| `PROXY_ALLOWED_CIDRS` | `10.0.0.0/8 172.16.0.0/12 192.168.0.0/16` | Кто может подключаться к mixed proxy |
|
||||
|
||||
---
|
||||
|
||||
@@ -252,6 +305,7 @@ UI доступен на `http://<gateway-ip>:3456`.
|
||||
| `POST` | `/api/apply` | Применить сервер (`{ selectedTag }`) |
|
||||
| `GET` | `/api/servers` | Список серверов из кэша |
|
||||
| `GET/PUT` | `/api/rules` | Кастомные правила |
|
||||
| `GET/PUT` | `/api/devices` | Профили устройств и default fallback |
|
||||
| `GET/PUT` | `/api/rule-sets` | Кастомные remote rule-set |
|
||||
| `POST` | `/api/singbox/start` | Запустить sing-box |
|
||||
| `POST` | `/api/singbox/stop` | Остановить sing-box |
|
||||
@@ -259,8 +313,8 @@ UI доступен на `http://<gateway-ip>:3456`.
|
||||
| `POST` | `/api/bypass` | `{ enabled }` — bypass mode |
|
||||
| `GET` | `/api/direct-cache` | Состояние ipset bypass-кэша |
|
||||
| `DELETE` | `/api/direct-cache` | Сбросить bypass-кэш |
|
||||
| `POST` | `/api/route-check` | Симулировать маршрут |
|
||||
| `GET` | `/api/ping` | TCP-пинг до хоста |
|
||||
| `POST` | `/api/route/check` | Симулировать маршрут |
|
||||
| `POST` | `/api/servers/ping` | TCP-пинг до хоста |
|
||||
| `GET` | `/api/logs/stream` | SSE системных логов |
|
||||
| `GET` | `/api/traffic/stream` | SSE трафика |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user