From e8d2973be77317b345e540b32fe04fca97dbf101 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 2 Feb 2026 17:50:30 +0100 Subject: [PATCH] Finalmask: Add XICMP --- web/assets/js/model/inbound.js | 74 +- web/assets/js/model/outbound.js | 59 +- web/html/form/stream/stream_finalmask.html | 14 + web/html/modals/inbound_info_modal.html | 888 +++++++++++---------- 4 files changed, 552 insertions(+), 483 deletions(-) diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js index 3f3f8831..9bc93c30 100644 --- a/web/assets/js/model/inbound.js +++ b/web/assets/js/model/inbound.js @@ -967,7 +967,7 @@ class SockoptStreamSettings extends XrayCommonClass { } } -class FinalMask extends XrayCommonClass { +class UdpMask extends XrayCommonClass { constructor(type = 'salamander', settings = {}) { super(); this.type = type; @@ -982,6 +982,8 @@ class FinalMask extends XrayCommonClass { case 'header-dns': case 'xdns': return { domain: settings.domain || '' }; + case 'xicmp': + return { ip: settings.ip || '', id: settings.id ?? 0 }; case 'mkcp-original': case 'header-dtls': case 'header-srtp': @@ -995,20 +997,35 @@ class FinalMask extends XrayCommonClass { } static fromJson(json = {}) { - return new FinalMask( + return new UdpMask( json.type || 'salamander', json.settings || {} ); } toJson() { - const result = { - type: this.type + return { + type: this.type, + settings: (this.settings && Object.keys(this.settings).length > 0) ? this.settings : undefined }; - if (this.settings && Object.keys(this.settings).length > 0) { - result.settings = this.settings; - } - return result; + } +} + +class FinalMaskStreamSettings extends XrayCommonClass { + constructor(udp = []) { + super(); + this.udp = Array.isArray(udp) ? udp.map(u => new UdpMask(u.type, u.settings)) : [new UdpMask(udp.type, udp.settings)]; + } + + static fromJson(json = {}) { + return new FinalMaskStreamSettings(json.udp || []); + } + + toJson() { + return { + udp: this.udp.map(udp => udp.toJson()) + }; + } } @@ -1024,7 +1041,7 @@ class StreamSettings extends XrayCommonClass { grpcSettings = new GrpcStreamSettings(), httpupgradeSettings = new HTTPUpgradeStreamSettings(), xhttpSettings = new xHTTPStreamSettings(), - finalmask = { udp: [] }, + finalmask = new FinalMaskStreamSettings(), sockopt = undefined, ) { super(); @@ -1044,10 +1061,7 @@ class StreamSettings extends XrayCommonClass { } addUdpMask(type = 'salamander') { - if (!this.finalmask.udp) { - this.finalmask.udp = []; - } - this.finalmask.udp.push(new FinalMask(type)); + this.finalmask.udp.push(new UdpMask(type)); } delUdpMask(index) { @@ -1056,6 +1070,10 @@ class StreamSettings extends XrayCommonClass { } } + get hasFinalMask() { + return this.finalmask.udp && this.finalmask.udp.length > 0; + } + get isTls() { return this.security === "tls"; } @@ -1090,14 +1108,6 @@ class StreamSettings extends XrayCommonClass { } static fromJson(json = {}) { - let finalmask = { udp: [] }; - if (json.finalmask) { - if (Array.isArray(json.finalmask)) { - finalmask.udp = json.finalmask.map(mask => FinalMask.fromJson(mask)); - } else if (json.finalmask.udp) { - finalmask.udp = json.finalmask.udp.map(mask => FinalMask.fromJson(mask)); - } - } return new StreamSettings( json.network, json.security, @@ -1110,7 +1120,7 @@ class StreamSettings extends XrayCommonClass { GrpcStreamSettings.fromJson(json.grpcSettings), HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings), xHTTPStreamSettings.fromJson(json.xhttpSettings), - finalmask, + FinalMaskStreamSettings.fromJson(json.finalmask), SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -1129,9 +1139,7 @@ class StreamSettings extends XrayCommonClass { grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined, - finalmask: (this.finalmask.udp && this.finalmask.udp.length > 0) ? { - udp: this.finalmask.udp.map(mask => mask.toJson()) - } : undefined, + finalmask: this.hasFinalMask ? this.finalmask.toJson() : undefined, sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, }; } @@ -1302,14 +1310,6 @@ class Inbound extends XrayCommonClass { return null; } - get kcpType() { - return this.stream.kcp.type; - } - - get kcpSeed() { - return this.stream.kcp.seed; - } - get serviceName() { return this.stream.grpc.serviceName; } @@ -1386,8 +1386,6 @@ class Inbound extends XrayCommonClass { } } else if (network === 'kcp') { const kcp = this.stream.kcp; - obj.type = kcp.type; - obj.path = kcp.seed; } else if (network === 'ws') { const ws = this.stream.ws; obj.path = ws.path; @@ -1450,8 +1448,6 @@ class Inbound extends XrayCommonClass { break; case "kcp": const kcp = this.stream.kcp; - params.set("headerType", kcp.type); - params.set("seed", kcp.seed); break; case "ws": const ws = this.stream.ws; @@ -1555,8 +1551,6 @@ class Inbound extends XrayCommonClass { break; case "kcp": const kcp = this.stream.kcp; - params.set("headerType", kcp.type); - params.set("seed", kcp.seed); break; case "ws": const ws = this.stream.ws; @@ -1636,8 +1630,6 @@ class Inbound extends XrayCommonClass { break; case "kcp": const kcp = this.stream.kcp; - params.set("headerType", kcp.type); - params.set("seed", kcp.seed); break; case "ws": const ws = this.stream.ws; diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 3e0dd0d4..fc110b4e 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -568,7 +568,7 @@ class SockoptStreamSettings extends CommonClass { } } -class FinalMask extends CommonClass { +class UdpMask extends CommonClass { constructor(type = 'salamander', settings = {}) { super(); this.type = type; @@ -596,21 +596,35 @@ class FinalMask extends CommonClass { } static fromJson(json = {}) { - return new FinalMask( + return new UdpMask( json.type || 'salamander', json.settings || {} ); } toJson() { - const result = { - type: this.type + return { + type: this.type, + settings: (this.settings && Object.keys(this.settings).length > 0) ? this.settings : undefined }; - // Only include settings if they exist and are not empty - if (this.settings && Object.keys(this.settings).length > 0) { - result.settings = this.settings; - } - return result; + } +} + +class FinalMaskStreamSettings extends CommonClass { + constructor(udp = []) { + super(); + this.udp = Array.isArray(udp) ? udp.map(u => new UdpMask(u.type, u.settings)) : [new UdpMask(udp.type, udp.settings)]; + } + + static fromJson(json = {}) { + return new FinalMaskStreamSettings(json.udp || []); + } + + toJson() { + return { + udp: this.udp.map(udp => udp.toJson()) + }; + } } @@ -627,7 +641,7 @@ class StreamSettings extends CommonClass { httpupgradeSettings = new HttpUpgradeStreamSettings(), xhttpSettings = new xHTTPStreamSettings(), hysteriaSettings = new HysteriaStreamSettings(), - finalmask = { udp: [] }, + finalmask = new FinalMaskStreamSettings(), sockopt = undefined, ) { super(); @@ -647,10 +661,7 @@ class StreamSettings extends CommonClass { } addUdpMask(type = 'salamander') { - if (!this.finalmask.udp) { - this.finalmask.udp = []; - } - this.finalmask.udp.push(new FinalMask(type)); + this.finalmask.udp.push(new UdpMask(type)); } delUdpMask(index) { @@ -659,6 +670,10 @@ class StreamSettings extends CommonClass { } } + get hasFinalMask() { + return this.finalmask.udp && this.finalmask.udp.length > 0; + } + get isTls() { return this.security === 'tls'; } @@ -676,16 +691,6 @@ class StreamSettings extends CommonClass { } static fromJson(json = {}) { - let finalmask = { udp: [] }; - if (json.finalmask) { - if (Array.isArray(json.finalmask)) { - // Legacy format: direct array (backward compatibility) - finalmask.udp = json.finalmask.map(mask => FinalMask.fromJson(mask)); - } else if (json.finalmask.udp) { - // New format: object with udp array - finalmask.udp = json.finalmask.udp.map(mask => FinalMask.fromJson(mask)); - } - } return new StreamSettings( json.network, json.security, @@ -698,7 +703,7 @@ class StreamSettings extends CommonClass { HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), xHTTPStreamSettings.fromJson(json.xhttpSettings), HysteriaStreamSettings.fromJson(json.hysteriaSettings), - finalmask, + FinalMaskStreamSettings.fromJson(json.finalmask), SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -717,9 +722,7 @@ class StreamSettings extends CommonClass { httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined, hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined, - finalmask: (this.finalmask.udp && this.finalmask.udp.length > 0) ? { - udp: this.finalmask.udp.map(mask => mask.toJson()) - } : undefined, + finalmask: this.hasFinalMask ? this.finalmask.toJson() : undefined, sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, }; } diff --git a/web/html/form/stream/stream_finalmask.html b/web/html/form/stream/stream_finalmask.html index 4ed7d6a1..35962dfa 100644 --- a/web/html/form/stream/stream_finalmask.html +++ b/web/html/form/stream/stream_finalmask.html @@ -45,6 +45,9 @@ mKCP Original + + xICMP (Experimental) + + + + + + + diff --git a/web/html/modals/inbound_info_modal.html b/web/html/modals/inbound_info_modal.html index 72023e75..1ab187ee 100644 --- a/web/html/modals/inbound_info_modal.html +++ b/web/html/modals/inbound_info_modal.html @@ -1,5 +1,8 @@ {{define "modals/inboundInfoModal"}} - + @@ -26,7 +29,8 @@
-