Przeglądaj źródła

inbound : finalmask

MHSanaei 1 dzień temu
rodzic
commit
3af6497577

+ 78 - 14
web/assets/js/model/inbound.js

@@ -319,14 +319,12 @@ TcpStreamSettings.TcpResponse = class extends XrayCommonClass {
 class KcpStreamSettings extends XrayCommonClass {
     constructor(
         mtu = 1350,
-        tti = 50,
+        tti = 20,
         uplinkCapacity = 5,
         downlinkCapacity = 20,
         congestion = false,
-        readBufferSize = 2,
-        writeBufferSize = 2,
-        type = 'none',
-        seed = RandomUtil.randomSeq(10),
+        readBufferSize = 1,
+        writeBufferSize = 1,
     ) {
         super();
         this.mtu = mtu;
@@ -336,8 +334,6 @@ class KcpStreamSettings extends XrayCommonClass {
         this.congestion = congestion;
         this.readBuffer = readBufferSize;
         this.writeBuffer = writeBufferSize;
-        this.type = type;
-        this.seed = seed;
     }
 
     static fromJson(json = {}) {
@@ -349,8 +345,6 @@ class KcpStreamSettings extends XrayCommonClass {
             json.congestion,
             json.readBufferSize,
             json.writeBufferSize,
-            ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type,
-            json.seed,
         );
     }
 
@@ -363,10 +357,6 @@ class KcpStreamSettings extends XrayCommonClass {
             congestion: this.congestion,
             readBufferSize: this.readBuffer,
             writeBufferSize: this.writeBuffer,
-            header: {
-                type: this.type,
-            },
-            seed: this.seed,
         };
     }
 }
@@ -929,6 +919,51 @@ class SockoptStreamSettings extends XrayCommonClass {
     }
 }
 
+class FinalMask extends XrayCommonClass {
+    constructor(type = 'salamander', settings = {}) {
+        super();
+        this.type = type;
+        this.settings = this._getDefaultSettings(type, settings);
+    }
+
+    _getDefaultSettings(type, settings = {}) {
+        switch (type) {
+            case 'salamander':
+            case 'mkcp-aes128gcm':
+                return { password: settings.password || '' };
+            case 'header-dns':
+            case 'xdns':
+                return { domain: settings.domain || '' };
+            case 'mkcp-original':
+            case 'header-dtls':
+            case 'header-srtp':
+            case 'header-utp':
+            case 'header-wechat':
+            case 'header-wireguard':
+                return {};
+            default:
+                return settings;
+        }
+    }
+
+    static fromJson(json = {}) {
+        return new FinalMask(
+            json.type || 'salamander',
+            json.settings || {}
+        );
+    }
+
+    toJson() {
+        const result = {
+            type: this.type
+        };
+        if (this.settings && Object.keys(this.settings).length > 0) {
+            result.settings = this.settings;
+        }
+        return result;
+    }
+}
+
 class StreamSettings extends XrayCommonClass {
     constructor(network = 'tcp',
         security = 'none',
@@ -941,6 +976,7 @@ class StreamSettings extends XrayCommonClass {
         grpcSettings = new GrpcStreamSettings(),
         httpupgradeSettings = new HTTPUpgradeStreamSettings(),
         xhttpSettings = new xHTTPStreamSettings(),
+        finalmask = { udp: [] },
         sockopt = undefined,
     ) {
         super();
@@ -955,9 +991,23 @@ class StreamSettings extends XrayCommonClass {
         this.grpc = grpcSettings;
         this.httpupgrade = httpupgradeSettings;
         this.xhttp = xhttpSettings;
+        this.finalmask = finalmask;
         this.sockopt = sockopt;
     }
 
+    addUdpMask(type = 'salamander') {
+        if (!this.finalmask.udp) {
+            this.finalmask.udp = [];
+        }
+        this.finalmask.udp.push(new FinalMask(type));
+    }
+
+    delUdpMask(index) {
+        if (this.finalmask.udp) {
+            this.finalmask.udp.splice(index, 1);
+        }
+    }
+
     get isTls() {
         return this.security === "tls";
     }
@@ -992,6 +1042,14 @@ 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,
@@ -1004,6 +1062,7 @@ class StreamSettings extends XrayCommonClass {
             GrpcStreamSettings.fromJson(json.grpcSettings),
             HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
             xHTTPStreamSettings.fromJson(json.xhttpSettings),
+            finalmask,
             SockoptStreamSettings.fromJson(json.sockopt),
         );
     }
@@ -1022,6 +1081,9 @@ 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,
             sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
         };
     }
@@ -1947,7 +2009,9 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
             json.selectedAuth = this.selectedAuth;
         }
 
-        if (this.testseed && this.testseed.length >= 4) {
+        // Only include testseed if at least one client has a flow set
+        const hasFlow = this.vlesses && this.vlesses.some(vless => vless.flow && vless.flow !== '');
+        if (hasFlow && this.testseed && this.testseed.length >= 4) {
             json.testseed = this.testseed;
         }
 

+ 3 - 13
web/assets/js/model/outbound.js

@@ -166,14 +166,12 @@ class TcpStreamSettings extends CommonClass {
 class KcpStreamSettings extends CommonClass {
     constructor(
         mtu = 1350,
-        tti = 50,
+        tti = 20,
         uplinkCapacity = 5,
         downlinkCapacity = 20,
         congestion = false,
-        readBufferSize = 2,
-        writeBufferSize = 2,
-        type = 'none',
-        seed = '',
+        readBufferSize = 1,
+        writeBufferSize = 1,
     ) {
         super();
         this.mtu = mtu;
@@ -183,8 +181,6 @@ class KcpStreamSettings extends CommonClass {
         this.congestion = congestion;
         this.readBuffer = readBufferSize;
         this.writeBuffer = writeBufferSize;
-        this.type = type;
-        this.seed = seed;
     }
 
     static fromJson(json = {}) {
@@ -196,8 +192,6 @@ class KcpStreamSettings extends CommonClass {
             json.congestion,
             json.readBufferSize,
             json.writeBufferSize,
-            ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type,
-            json.seed,
         );
     }
 
@@ -210,10 +204,6 @@ class KcpStreamSettings extends CommonClass {
             congestion: this.congestion,
             readBufferSize: this.readBuffer,
             writeBufferSize: this.writeBuffer,
-            header: {
-                type: this.type,
-            },
-            seed: this.seed,
         };
     }
 }

+ 25 - 26
web/html/form/outbound.html

@@ -407,21 +407,6 @@
 
         <!-- kcp -->
         <template v-if="outbound.stream.network === 'kcp'">
-          <a-form-item label='{{ i18n "camouflage" }}'>
-            <a-select v-model="outbound.stream.kcp.type"
-              :dropdown-class-name="themeSwitcher.currentTheme">
-              <a-select-option value="none">None</a-select-option>
-              <a-select-option value="srtp">SRTP</a-select-option>
-              <a-select-option value="utp">uTP</a-select-option>
-              <a-select-option value="wechat-video">WeChat</a-select-option>
-              <a-select-option value="dtls">DTLS 1.2</a-select-option>
-              <a-select-option value="wireguard">WireGuard</a-select-option>
-              <a-select-option value="dns">DNS</a-select-option>
-            </a-select>
-          </a-form-item>
-          <a-form-item label='{{ i18n "password" }}'>
-            <a-input v-model="outbound.stream.kcp.seed"></a-input>
-          </a-form-item>
           <a-form-item label='MTU'>
             <a-input-number v-model.number="outbound.stream.kcp.mtu"
               min="0"></a-input-number>
@@ -607,7 +592,7 @@
       <template v-if="outbound.canEnableStream()">
         <a-form-item label="UDP Masks">
           <a-button icon="plus" type="primary" size="small"
-            @click="outbound.stream.addUdpMask(outbound.protocol === Protocols.Hysteria ? 'salamander' : 'mkcp-aes128gcm')"></a-button>
+            @click="outbound.stream.addUdpMask(outbound.protocol === Protocols.Hysteria ? 'salamander' : (outbound.stream.network === 'kcp' ? 'mkcp-aes128gcm' : 'xdns'))"></a-button>
         </a-form-item>
         <template
           v-if="outbound.stream.finalmask.udp && outbound.stream.finalmask.udp.length > 0">
@@ -623,25 +608,39 @@
               <a-select v-model="mask.type"
                 @change="(type) => mask.settings = mask._getDefaultSettings(type, {})"
                 :dropdown-class-name="themeSwitcher.currentTheme">
-                <a-select-option v-if="outbound.protocol === Protocols.Hysteria" value="salamander">
+                <!-- Salamander for Hysteria2 only -->
+                <a-select-option v-if="outbound.protocol === Protocols.Hysteria"
+                  value="salamander">
                   Salamander (Hysteria2)</a-select-option>
-                <a-select-option value="mkcp-aes128gcm">
+                <!-- mKCP-specific masks -->
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="mkcp-aes128gcm">
                   mKCP AES-128-GCM</a-select-option>
-                <a-select-option value="header-dns">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-dns">
                   Header DNS</a-select-option>
-                <a-select-option value="header-dtls">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-dtls">
                   Header DTLS 1.2</a-select-option>
-                <a-select-option value="header-srtp">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-srtp">
                   Header SRTP</a-select-option>
-                <a-select-option value="header-utp">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-utp">
                   Header uTP</a-select-option>
-                <a-select-option value="header-wechat">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-wechat">
                   Header WeChat Video</a-select-option>
-                <a-select-option value="header-wireguard">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="header-wireguard">
                   Header WireGuard</a-select-option>
-                <a-select-option value="mkcp-original">
+                <a-select-option v-if="outbound.stream.network === 'kcp'"
+                  value="mkcp-original">
                   mKCP Original</a-select-option>
-                <a-select-option value="xdns">
+                <!-- xDNS for TCP/WS/HTTPUpgrade/XHTTP -->
+                <a-select-option
+                  v-if="['tcp', 'ws', 'httpupgrade', 'xhttp'].includes(outbound.stream.network)"
+                  value="xdns">
                   xDNS (Experimental)</a-select-option>
               </a-select>
             </a-form-item>

+ 70 - 0
web/html/form/stream/stream_finalmask.html

@@ -0,0 +1,70 @@
+{{define "form/streamFinalMask"}}
+<a-divider :style="{ margin: '5px 0 0' }"></a-divider>
+<a-form :colon="false" :label-col="{ md: {span:8} }"
+    :wrapper-col="{ md: {span:14} }">
+    <a-form-item label="UDP Masks">
+        <a-button icon="plus" type="primary" size="small"
+            @click="inbound.stream.addUdpMask(inbound.stream.network === 'kcp' ? 'mkcp-aes128gcm' : 'xdns')"></a-button>
+    </a-form-item>
+    <template
+        v-if="inbound.stream.finalmask.udp && inbound.stream.finalmask.udp.length > 0">
+        <a-form v-for="(mask, index) in inbound.stream.finalmask.udp"
+            :key="index" :colon="false"
+            :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
+            <a-divider :style="{ margin: '0' }"> UDP Mask [[ index + 1 ]]
+                <a-icon type="delete"
+                    @click="() => inbound.stream.delUdpMask(index)"
+                    :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
+            </a-divider>
+            <a-form-item label='Type'>
+                <a-select v-model="mask.type"
+                    @change="(type) => mask.settings = mask._getDefaultSettings(type, {})"
+                    :dropdown-class-name="themeSwitcher.currentTheme">
+                    <!-- mKCP-specific masks -->
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="mkcp-aes128gcm">
+                        mKCP AES-128-GCM</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-dns">
+                        Header DNS</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-dtls">
+                        Header DTLS 1.2</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-srtp">
+                        Header SRTP</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-utp">
+                        Header uTP</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-wechat">
+                        Header WeChat Video</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="header-wireguard">
+                        Header WireGuard</a-select-option>
+                    <a-select-option v-if="inbound.stream.network === 'kcp'"
+                        value="mkcp-original">
+                        mKCP Original</a-select-option>
+                    <!-- xDNS for TCP/WS/HTTPUpgrade/XHTTP -->
+                    <a-select-option
+                        v-if="['tcp', 'ws', 'httpupgrade', 'xhttp'].includes(inbound.stream.network)"
+                        value="xdns">
+                        xDNS (Experimental)</a-select-option>
+                </a-select>
+            </a-form-item>
+            <!-- Settings for password-based masks -->
+            <a-form-item label='Password'
+                v-if="['mkcp-aes128gcm'].includes(mask.type)">
+                <a-input v-model.trim="mask.settings.password"
+                    placeholder="Obfuscation password"></a-input>
+            </a-form-item>
+            <!-- Settings for domain-based masks -->
+            <a-form-item label='Domain'
+                v-if="['header-dns', 'xdns'].includes(mask.type)">
+                <a-input v-model.trim="mask.settings.domain"
+                    placeholder="e.g., www.example.com"></a-input>
+            </a-form-item>
+        </a-form>
+    </template>
+</a-form>
+{{end}}

+ 15 - 31
web/html/form/stream/stream_kcp.html

@@ -1,48 +1,32 @@
 {{define "form/streamKCP"}}
-<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
-    <a-form-item label='{{ i18n "camouflage" }}'>
-        <a-select v-model="inbound.stream.kcp.type" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
-            <a-select-option value="none">None</a-select-option>
-            <a-select-option value="srtp">SRTP</a-select-option>
-            <a-select-option value="utp">uTP</a-select-option>
-            <a-select-option value="wechat-video">WeChat</a-select-option>
-            <a-select-option value="dtls">DTLS 1.2</a-select-option>
-            <a-select-option value="wireguard">WireGuard</a-select-option>
-            <a-select-option value="dns">DNS</a-select-option>
-        </a-select>
-    </a-form-item>
-    <a-form-item>
-        <template slot="label">
-            <a-tooltip>
-                <template slot="title">
-                    <span>{{ i18n "reset" }}</span>
-                </template>
-                {{ i18n "password" }}
-                <a-icon @click="inbound.stream.kcp.seed = RandomUtil.randomSeq(10)"type="sync"> </a-icon>
-            </a-tooltip>
-        </template>
-        <a-input v-model.trim="inbound.stream.kcp.seed"></a-input>
-    </a-form-item>
+<a-form :colon="false" :label-col="{ md: {span:8} }"
+    :wrapper-col="{ md: {span:14} }">
     <a-form-item label='MTU'>
-        <a-input-number v-model.number="inbound.stream.kcp.mtu" :min="576" :max="1460"></a-input-number>
+        <a-input-number v-model.number="inbound.stream.kcp.mtu" :min="576"
+            :max="1460"></a-input-number>
     </a-form-item>
     <a-form-item label='TTI (ms)'>
-        <a-input-number v-model.number="inbound.stream.kcp.tti" :min="10" :max="100"></a-input-number>
+        <a-input-number v-model.number="inbound.stream.kcp.tti" :min="10"
+            :max="100"></a-input-number>
     </a-form-item>
     <a-form-item label='Uplink (MB/s)'>
-        <a-input-number v-model.number="inbound.stream.kcp.upCap" :min="0"></a-input-number>
-    </a-form-item> 
+        <a-input-number v-model.number="inbound.stream.kcp.upCap"
+            :min="0"></a-input-number>
+    </a-form-item>
     <a-form-item label='Downlink (MB/s)'>
-        <a-input-number v-model.number="inbound.stream.kcp.downCap" :min="0"></a-input-number>
+        <a-input-number v-model.number="inbound.stream.kcp.downCap"
+            :min="0"></a-input-number>
     </a-form-item>
     <a-form-item label='Congestion'>
         <a-switch v-model="inbound.stream.kcp.congestion"></a-switch>
     </a-form-item>
     <a-form-item label='Read Buffer (MB)'>
-        <a-input-number v-model.number="inbound.stream.kcp.readBuffer" :min="0"></a-input-number>
+        <a-input-number v-model.number="inbound.stream.kcp.readBuffer"
+            :min="0"></a-input-number>
     </a-form-item>
     <a-form-item label='Write Buffer (MB)'>
-        <a-input-number v-model.number="inbound.stream.kcp.writeBuffer" :min="0"></a-input-number>
+        <a-input-number v-model.number="inbound.stream.kcp.writeBuffer"
+            :min="0"></a-input-number>
     </a-form-item>
 </a-form>
 {{end}}

+ 10 - 2
web/html/form/stream/stream_settings.html

@@ -1,8 +1,10 @@
 {{define "form/streamSettings"}}
 <!-- select stream network -->
-<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
+<a-form :colon="false" :label-col="{ md: {span:8} }"
+    :wrapper-col="{ md: {span:14} }">
     <a-form-item label='{{ i18n "transmission" }}'>
-        <a-select v-model="inbound.stream.network" :style="{ width: '75%' }" @change="streamNetworkChange"
+        <a-select v-model="inbound.stream.network" :style="{ width: '75%' }"
+            @change="streamNetworkChange"
             :dropdown-class-name="themeSwitcher.currentTheme">
             <a-select-option value="tcp">TCP (RAW)</a-select-option>
             <a-select-option value="kcp">mKCP</a-select-option>
@@ -48,4 +50,10 @@
 <template>
     {{template "form/streamSockopt"}}
 </template>
+
+<!-- finalmask - only for TCP, WS, HTTPUpgrade, XHTTP, mKCP -->
+<template
+    v-if="['tcp', 'ws', 'httpupgrade', 'xhttp', 'kcp'].includes(inbound.stream.network)">
+    {{template "form/streamFinalMask"}}
+</template>
 {{end}}