mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 23:27:14 +00:00
fix(link): restore mKCP seed and headerType on share-link import (#6480)
* fix(link): restore mKCP seed and headerType on share-link import applyTransport / applyTransportParams ignored kcp query params that applyKcpShareParams emits, so re-imported outbounds lost seed and header and could not talk to the inbound. Mirror those fields (plus mtu/tti) into kcpSettings in both Go and TS importers. Fixes #6476 * fix(link): restore mKCP header/seed via finalmask mkcp-legacy * fix(link): split mKCP header and seed into separate masks on import Both importers folded a share link's headerType and seed into one mkcp-legacy mask {header, value}. xray-core's MkcpLegacy.Build ignores value once header is set (and reads it as the fake DNS domain for header=dns), so an imported outbound carried the header mask but no AES-128-GCM seed while the emitting inbound has both, and could not connect — the failure #6476 reports, now for every link carrying both params. Emit one mask per field, seed first: the finalmask array's first item is the innermost layer, which puts the header around the cipher as legacy mKCP did. Also bound mtu/tti to KCPConfig.Build's accepted ranges (mtu >= 21, tti 10..1000, decimal digits only on both importers) so a pasted link cannot fail the whole Xray config load, and look header types up as own properties so a prototype key such as "constructor" is not mapped. --------- Co-authored-by: mrchatam <287639636+mrchatam@users.noreply.github.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -266,6 +266,67 @@ describe('parseVlessLink', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mKCP share params', () => {
|
||||
// The emitter flattens one mkcp-legacy mask per field into headerType/seed; a merged
|
||||
// mask drops the seed in xray-core (MkcpLegacy.Build), so import rebuilds them separately.
|
||||
type Mask = { type: string; settings: { header: string; value: string } };
|
||||
const parse = (link: string) => {
|
||||
const out = link.startsWith('trojan://') ? parseTrojanLink(link) : parseVlessLink(link);
|
||||
expect(out).not.toBeNull();
|
||||
const stream = out!.streamSettings as Record<string, unknown>;
|
||||
const kcp = stream.kcpSettings as { mtu: number; tti: number };
|
||||
const udp = (stream.finalmask as { udp?: Mask[] } | undefined)?.udp ?? [];
|
||||
return {
|
||||
kcp: { mtu: kcp.mtu, tti: kcp.tti },
|
||||
masks: udp.map((m) => [m.type, m.settings.header, m.settings.value]),
|
||||
};
|
||||
};
|
||||
|
||||
it.each([
|
||||
[
|
||||
'vless header and seed become two masks, seed first',
|
||||
'vless://11111111-2222-4333-8444-555555555555@h.com:443?type=kcp&headerType=wechat-video&seed=secret-seed&mtu=1400&tti=50&security=none#kcp1',
|
||||
{ mtu: 1400, tti: 50 },
|
||||
[
|
||||
['mkcp-legacy', '', 'secret-seed'],
|
||||
['mkcp-legacy', 'wechat', ''],
|
||||
],
|
||||
],
|
||||
[
|
||||
'trojan header only adds no seed mask',
|
||||
'trojan://pw@h.com:443?type=kcp&headerType=srtp&security=none#kcp-tj',
|
||||
{ mtu: 1350, tti: 20 },
|
||||
[['mkcp-legacy', 'srtp', '']],
|
||||
],
|
||||
[
|
||||
'seed only adds no header mask',
|
||||
'vless://uuid@h.com:443?type=kcp&headerType=none&seed=abc123&security=none',
|
||||
{ mtu: 1350, tti: 20 },
|
||||
[['mkcp-legacy', '', 'abc123']],
|
||||
],
|
||||
[
|
||||
'mtu/tti outside KCPConfig.Build bounds keep the defaults',
|
||||
'vless://uuid@h.com:443?type=kcp&mtu=10&tti=5000&security=none',
|
||||
{ mtu: 1350, tti: 20 },
|
||||
[],
|
||||
],
|
||||
[
|
||||
'non-decimal mtu keeps the default like the Go importer',
|
||||
'vless://uuid@h.com:443?type=kcp&mtu=1.5&tti=1e2&security=none',
|
||||
{ mtu: 1350, tti: 20 },
|
||||
[],
|
||||
],
|
||||
[
|
||||
'a prototype key is not a header type',
|
||||
'vless://uuid@h.com:443?type=kcp&headerType=constructor&seed=abc&security=none',
|
||||
{ mtu: 1350, tti: 20 },
|
||||
[],
|
||||
],
|
||||
])('%s', (_name, link, kcp, masks) => {
|
||||
expect(parse(link)).toEqual({ kcp, masks });
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseTrojanLink', () => {
|
||||
it('parses a trojan:// link with ws + tls', () => {
|
||||
const link =
|
||||
|
||||
Reference in New Issue
Block a user