Commit 707491c
committed
release: 1.3.5 — DNS-leak protection, routing semantics tests, rollback fix
Headline fix — DNS dial protection on routing chain
Burn-in on 192.168.1.4 (1256-node subscription) exposed a footgun:
a user rule like "Port Range 0-65535 → proxy" also caught xray's
own DNS-upstream dial (TCP/UDP to 8.8.8.8:53 etc.), tunnelling DNS
resolution through the active VPN node. If the node had any
handshake hiccup, the resolver died → everything else cascaded
(API freeze, SOCKS5 down, TPROXY stuck). Three-layer defence
(the SYSTEM RULE is the actual fix; the others are belt-and-
suspenders):
1. dns.servers[].outboundTag = "direct" on every entry — pins
resolved-IP routing to direct.
2. dns-out outbound proxySettings.tag = "direct" — chains the
outbound through direct.
3. THE REAL FIX: system-level routing rule `port: 53 → direct`
prepended ahead of any user rule. xray evaluates rules
top-to-bottom; this catches the dial first and bypasses
user-defined catch-all-to-proxy rules.
Why not strip dangerous user rules: surgical rewrite is brittle
and user-surprising. A system rule that always wins is robust,
visible in the generated config, and works regardless of how the
operator twists their routing.
Live verified: with `port 0-65535 → proxy` ENABLED, DNS resolves
normally, SOCKS5 + TPROXY traffic still flows through the VPN.
UI — Routing page banner for non-rules modes
Routing rules apply only in `mode=rules`. In `global` mode every
connection is force-routed through the active node; in `bypass`
every connection goes direct. User-defined rules are ignored.
Without a visible warning, the operator could save a "Bypass
local networks" rule in Global mode and have it silently no-op.
New amber banner explains the gotcha + points to the "Bypass
private CIDRs" toggle on Dashboard (the actual lever for
LAN-direct in Global mode).
Backend — pin routing semantics + device routing modes with tests
Two new test groups (98/98 still passing on touched modules):
* `TestModes` (5 new cases) — pins the `bypass_private` contract
across all three modes (rules / global / bypass). Verifies the
private-CIDR rule lands BEFORE the catch-all, covers RFC 1918
+ loopback + link-local + IPv6 LL/ULA, and pins that `global`
mode IGNORES user RoutingRules (the contract the banner
relies on).
* `tests/test_devices_routing_modes.py` (7 new cases) — covers
`get_device_macs_for_mode`: `all` / `include_only` / `exclude_list`
paths, empty-list edge cases, missing-setting fallback to `all`.
Until now only the setting read/write was tested; the actual
MAC-list population per mode had no coverage.
* `TestDNS` (6 new cases) — DNS-pinning rule order, per-server
outboundTag, dns-out proxySettings, fakedns sentinel preserved.
Misc — POST /api/network/rollback works body-less
Endpoint signature required `body: RollbackBody` so a POST with
no body returned 422 ("Field required") despite the docstring
promising "no body → newest backup". UI's Rollback button (which
sends no body) hit this. Make body Optional in the FastAPI
signature, fall through to None-id when omitted.
TUN audit (no code change)
Audited the dormant TUN/Both inbound-mode code paths across six
files (~150 LOC). Nothing safe to remove — every site is wired
defensively (rollback-on-validation, upgrade-path from older
installs that may have inbound_mode=tun in DB). Keep as-is until
sing-box-core enablement re-uses it.
Stack
- 5 commits since v1.3.4
- 98/98 focused backend tests pass; frontend build clean1 parent 2b07775 commit 707491c
3 files changed
Lines changed: 4 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
0 commit comments