From 62423cacd14a7c4675b3718777200a93b14fcbf6 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 30 Sep 2026 17:27:10 +0200 Subject: [PATCH] feat(xray): update xray-core to v26.9.30 and adapt panel Bump xtls/xray-core to b26a91de4f (v26.9.30) and the three binary pins (DockerInit.sh, release.yml Linux + Windows) in lockstep. No deleted symbols; the sing and sing-shadowsocks indirect deps drop out with the SS2022 rewrite. XDNS finalmask (#6718) replaced its string lists with objects: domains are {name, types, edns0, lenLimit, labelLimit} and client resolvers {type, settings.addr}. The loader no longer parses the old lists, so a single stored xdns mask keeps the whole core from starting. The new leaf package internal/util/maskcompat converts them: "name[:type]" becomes a domain and "name[:type]+udp://addr" a domain plus a udp resolver. A bare name maps to TXT, the type legacy clients queried by default, and each converted domain keeps the 1232-byte EDNS0 the old code always used (without it the server caps answers at 512). It runs from: - the XdnsFinalmaskObjectsFix seeder, over inbound streams, hosts, the xray template, the global sub-JSON mask and cached subscription outbounds; - inbound save (normalizeStreamSettings) and GetXrayConfig, for rows that never went through the seeder; - both link importers, since fm= from an older panel carries the lists. The finalmask form edits the object shape (every key needs a registered field, or the finalmask watch drops it on save) and lifts legacy masks on open. The udp-mask golden fixture moves to the object shape, which TestGoldenStreamFixturesBuildInXray now builds through the core. The wire format changed as well, so pre-upgrade clients need the new core. WireGuard outbound (#6771) dropped settings.domainStrategy and the remoteDNS "local" mode. The endpoint lookup now follows sockopt.domainStrategy and in-tunnel targets the outbound's targetStrategy. The old key is silently ignored, which undid the IPv4-first endpoint lookup the WARP outbound depends on (#5205), and "local" now panics the core at startup because remoteDNS goes through netip.MustParseAddr. The WireguardDomainStrategyFix seeder moves a stored family preference to both keys (a value already set wins) and turns "local" into targetStrategy; the outbound form lifts legacy rows the same way and drops its select, the WARP modal writes the new placement, and the inbound form loses a field the server never read. ValidateOutboundConfig now refuses a non-IP remoteDNS entry, which conf.Build() lets through, on template save and for outbound subscriptions. Noise finalmask items accept type "exp" (#6862), a tag expression. The form offers it for noise items only: header-custom items go through the core's PraseByteSlice, which refuses it. TUN gained autoSystemDnsToGateway (Linux) and autoSystemWfpBlockLeak (Windows). Both pass through the settings schema so a value set in JSON survives the next form save. MASQUE (inbound, outbound, transport) and the XDRIVE transport are new protocols the panel does not offer yet; their new loader refusals only cover configs the panel never generates. The FakeDNS IPv6 pool default, the SS2022 rewrite (same gRPC account; emails are now deduped case-insensitively, as the panel already does), the restored udphop interval default and the rest change no panel-facing config. --- .github/workflows/release.yml | 4 +- DockerInit.sh | 2 +- .../xray/forms/transport/FinalMaskForm.tsx | 158 ++++++++++-- frontend/src/lib/xray/inbound-form-adapter.ts | 25 +- .../src/lib/xray/outbound-form-adapter.ts | 78 ++++-- frontend/src/lib/xray/outbound-link-parser.ts | 3 + .../src/lib/xray/stream-wire-normalize.ts | 15 ++ frontend/src/lib/xray/xdns-mask.ts | 81 ++++++ .../inbounds/form/protocols/wireguard.tsx | 17 +- .../xray/outbounds/protocols/wireguard.tsx | 14 +- .../src/pages/xray/overrides/WarpModal.tsx | 55 ++-- frontend/src/schemas/forms/outbound-form.ts | 2 - frontend/src/schemas/primitives/options.ts | 8 - frontend/src/schemas/protocols/inbound/tun.ts | 3 + .../schemas/protocols/inbound/wireguard.ts | 10 - .../schemas/protocols/outbound/wireguard.ts | 10 - .../test/__snapshots__/finalmask.test.ts.snap | 23 +- frontend/src/test/finalmask-form.test.tsx | 29 +++ .../golden/fixtures/finalmask/udp-mask.json | 7 +- frontend/src/test/inbound-from-db.test.ts | 20 ++ .../src/test/outbound-form-adapter.test.ts | 68 +++++ .../src/test/outbound-form-modal.test.tsx | 75 +++++- .../src/test/outbound-link-parser.test.ts | 20 ++ frontend/src/test/warp-change-ip.test.ts | 13 +- go.mod | 4 +- go.sum | 8 +- internal/database/db.go | 235 +++++++++++++++++- ...ireguard_domain_strategy_migration_test.go | 147 +++++++++++ .../database/xdns_finalmask_migration_test.go | 116 +++++++++ internal/util/link/outbound.go | 3 + internal/util/link/outbound_test.go | 19 ++ internal/util/maskcompat/xdns.go | 107 ++++++++ internal/util/maskcompat/xdns_test.go | 101 ++++++++ internal/web/service/inbound.go | 22 ++ .../service/inbound_finalmask_xdns_test.go | 91 +++++++ internal/web/service/xray.go | 4 + internal/xray/api.go | 30 ++- internal/xray/outbound_validation_test.go | 25 ++ 38 files changed, 1487 insertions(+), 165 deletions(-) create mode 100644 frontend/src/lib/xray/xdns-mask.ts create mode 100644 frontend/src/test/finalmask-form.test.tsx create mode 100644 internal/database/wireguard_domain_strategy_migration_test.go create mode 100644 internal/database/xdns_finalmask_migration_test.go create mode 100644 internal/util/maskcompat/xdns.go create mode 100644 internal/util/maskcompat/xdns_test.go create mode 100644 internal/web/service/inbound_finalmask_xdns_test.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7561ad472..9b03a24a3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -115,7 +115,7 @@ jobs: cd x-ui/bin # Download dependencies - Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.9.9/" + Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.9.30/" if [ "${{ matrix.platform }}" == "amd64" ]; then fetch ${Xray_URL}Xray-linux-64.zip unzip Xray-linux-64.zip @@ -300,7 +300,7 @@ jobs: cd x-ui\bin # Download Xray for Windows - $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.9.9/" + $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.9.30/" Invoke-WebRequest @retry -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip" Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath . Remove-Item "Xray-windows-64.zip" diff --git a/DockerInit.sh b/DockerInit.sh index 82a9abb83..d00dc19e6 100755 --- a/DockerInit.sh +++ b/DockerInit.sh @@ -33,7 +33,7 @@ if [ -z "$MTG_MULTI_VER" ]; then fi mkdir -p build/bin cd build/bin -curl -sfLRO "https://github.com/XTLS/Xray-core/releases/download/v26.9.9/Xray-linux-${ARCH}.zip" +curl -sfLRO "https://github.com/XTLS/Xray-core/releases/download/v26.9.30/Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip" rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat mv xray "xray-linux-${FNAME}" diff --git a/frontend/src/lib/xray/forms/transport/FinalMaskForm.tsx b/frontend/src/lib/xray/forms/transport/FinalMaskForm.tsx index d6ae08f1c..4029e62dd 100644 --- a/frontend/src/lib/xray/forms/transport/FinalMaskForm.tsx +++ b/frontend/src/lib/xray/forms/transport/FinalMaskForm.tsx @@ -18,6 +18,7 @@ import type { NamePath } from 'antd/es/form/interface'; import { RandomUtil } from '@/utils'; import { activateOnKey } from '@/utils/a11y'; import { OutboundProtocols, UTLS_FINGERPRINT } from '@/schemas/primitives'; +import { upgradeLegacyXdnsMasks, XDNS_LEGACY_EDNS0 } from '@/lib/xray/xdns-mask'; const UTLS_FINGERPRINT_OPTIONS = Object.values(UTLS_FINGERPRINT).map((value) => ({ value, @@ -244,28 +245,34 @@ export default function FinalMaskForm({ }: FinalMaskFormProps) { const base = asPath(name); - // Migrate legacy TCP mask shapes once on mount so configs saved before - // #6334 (fragment ranges) and #6487 (xmc profiles) render in the list UI. + // Migrate legacy mask shapes once on mount so configs saved before #6334 (fragment + // ranges), #6487 (xmc profiles) and #6718 (xdns objects) render in the list UI. const migratedRef = useRef(false); useEffect(() => { if (migratedRef.current) return; migratedRef.current = true; const tcp = form.getFieldValue([...base, 'tcp']); - if (!Array.isArray(tcp)) return; - let anyChanged = false; - const next = tcp.map((mask) => { - if (!mask || typeof mask !== 'object') return mask; - const m = mask as Record; - if (m.type !== 'fragment' && m.type !== 'xmc') return mask; - if (!m.settings || typeof m.settings !== 'object') return mask; - const settings = m.settings as Record; - const { next: migrated, changed } = - m.type === 'fragment' ? migrateFragmentSettings(settings) : migrateXmcSettings(settings); - if (!changed) return mask; - anyChanged = true; - return { ...m, settings: migrated }; - }); - if (anyChanged) form.setFieldValue([...base, 'tcp'], next); + if (Array.isArray(tcp)) { + let anyChanged = false; + const next = tcp.map((mask) => { + if (!mask || typeof mask !== 'object') return mask; + const m = mask as Record; + if (m.type !== 'fragment' && m.type !== 'xmc') return mask; + if (!m.settings || typeof m.settings !== 'object') return mask; + const settings = m.settings as Record; + const { next: migrated, changed } = + m.type === 'fragment' ? migrateFragmentSettings(settings) : migrateXmcSettings(settings); + if (!changed) return mask; + anyChanged = true; + return { ...m, settings: migrated }; + }); + if (anyChanged) form.setFieldValue([...base, 'tcp'], next); + } + const udp = form.getFieldValue([...base, 'udp']); + if (Array.isArray(udp)) { + const { next, changed } = upgradeLegacyXdnsMasks(udp); + if (changed) form.setFieldValue([...base, 'udp'], next); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -958,11 +965,7 @@ function UdpMaskItem({ ); } if (type === 'xdns') { - return ( - - + + + + + + + +