4 Commits 50603fd430 ... 3313086071

Autore SHA1 Messaggio Data
  MHSanaei 3313086071 fix: Swap left/right classes for client table cells 4 ore fa
  MHSanaei 03d8ad4d5a Revert "Xray Core v26.5.3" buggy version(vless reverse doesn't work) 4 ore fa
  MHSanaei a8dff126c7 outbound: reverse Sniffing 5 ore fa
  MHSanaei 74e97fec4c Xray Core v26.5.3 6 ore fa

+ 6 - 1
web/assets/js/model/inbound.js

@@ -2617,12 +2617,14 @@ Inbound.VLESSSettings.VLESS = class extends Inbound.ClientBase {
         id = RandomUtil.randomUUID(),
         flow = '',
         reverseTag = '',
+        reverseSniffing = new Sniffing(),
         email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at,
     ) {
         super(email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at);
         this.id = id;
         this.flow = flow;
         this.reverseTag = reverseTag;
+        this.reverseSniffing = reverseSniffing;
     }
 
     static fromJson(json = {}) {
@@ -2630,6 +2632,7 @@ Inbound.VLESSSettings.VLESS = class extends Inbound.ClientBase {
             json.id,
             json.flow,
             json.reverse?.tag ?? '',
+            Sniffing.fromJson(json.reverse?.sniffing || {}),
             ...Inbound.ClientBase.commonArgsFromJson(json),
         );
     }
@@ -2641,7 +2644,9 @@ Inbound.VLESSSettings.VLESS = class extends Inbound.ClientBase {
             ...this._clientBaseToJson(),
         };
         if (this.reverseTag) {
-            json.reverse = { tag: this.reverseTag };
+            json.reverse = {
+                tag: this.reverseTag,
+            };
         }
         return json;
     }

+ 61 - 2
web/assets/js/model/outbound.js

@@ -50,6 +50,13 @@ const ALPN_OPTION = {
     HTTP1: "http/1.1",
 };
 
+const SNIFFING_OPTION = {
+    HTTP: "http",
+    TLS: "tls",
+    QUIC: "quic",
+    FAKEDNS: "fakedns"
+};
+
 const OutboundDomainStrategies = [
     "AsIs",
     "UseIP",
@@ -170,6 +177,7 @@ Object.freeze(SSMethods);
 Object.freeze(TLS_FLOW_CONTROL);
 Object.freeze(UTLS_FINGERPRINT);
 Object.freeze(ALPN_OPTION);
+Object.freeze(SNIFFING_OPTION);
 Object.freeze(OutboundDomainStrategies);
 Object.freeze(WireguardDomainStrategy);
 Object.freeze(USERS_SECURITY);
@@ -196,6 +204,50 @@ class CommonClass {
     }
 }
 
+class ReverseSniffing extends CommonClass {
+    constructor(
+        enabled = false,
+        destOverride = ['http', 'tls', 'quic', 'fakedns'],
+        metadataOnly = false,
+        routeOnly = false,
+        ipsExcluded = [],
+        domainsExcluded = [],
+    ) {
+        super();
+        this.enabled = enabled;
+        this.destOverride = Array.isArray(destOverride) && destOverride.length > 0 ? destOverride : ['http', 'tls', 'quic', 'fakedns'];
+        this.metadataOnly = metadataOnly;
+        this.routeOnly = routeOnly;
+        this.ipsExcluded = Array.isArray(ipsExcluded) ? ipsExcluded : [];
+        this.domainsExcluded = Array.isArray(domainsExcluded) ? domainsExcluded : [];
+    }
+
+    static fromJson(json = {}) {
+        if (!json || Object.keys(json).length === 0) {
+            return new ReverseSniffing();
+        }
+        return new ReverseSniffing(
+            !!json.enabled,
+            json.destOverride,
+            json.metadataOnly,
+            json.routeOnly,
+            json.ipsExcluded || [],
+            json.domainsExcluded || [],
+        );
+    }
+
+    toJson() {
+        return {
+            enabled: this.enabled,
+            destOverride: this.destOverride,
+            metadataOnly: this.metadataOnly,
+            routeOnly: this.routeOnly,
+            ipsExcluded: this.ipsExcluded.length > 0 ? this.ipsExcluded : undefined,
+            domainsExcluded: this.domainsExcluded.length > 0 ? this.domainsExcluded : undefined,
+        };
+    }
+}
+
 class TcpStreamSettings extends CommonClass {
     constructor(type = 'none', host, path) {
         super();
@@ -1747,7 +1799,7 @@ Outbound.VmessSettings = class extends CommonClass {
     }
 };
 Outbound.VLESSSettings = class extends CommonClass {
-    constructor(address, port, id, flow, encryption, reverseTag = '', testpre = 0, testseed = [900, 500, 900, 256]) {
+    constructor(address, port, id, flow, encryption, reverseTag = '', reverseSniffing = new ReverseSniffing(), testpre = 0, testseed = [900, 500, 900, 256]) {
         super();
         this.address = address;
         this.port = port;
@@ -1755,6 +1807,7 @@ Outbound.VLESSSettings = class extends CommonClass {
         this.flow = flow;
         this.encryption = encryption;
         this.reverseTag = reverseTag;
+        this.reverseSniffing = reverseSniffing;
         this.testpre = testpre;
         this.testseed = testseed;
     }
@@ -1768,6 +1821,7 @@ Outbound.VLESSSettings = class extends CommonClass {
             json.flow,
             json.encryption,
             json.reverse?.tag || '',
+            ReverseSniffing.fromJson(json.reverse?.sniffing || {}),
             json.testpre || 0,
             json.testseed && json.testseed.length >= 4 ? json.testseed : [900, 500, 900, 256]
         );
@@ -1782,7 +1836,12 @@ Outbound.VLESSSettings = class extends CommonClass {
             encryption: this.encryption,
         };
         if (!ObjectUtil.isEmpty(this.reverseTag)) {
-            result.reverse = { tag: this.reverseTag };
+            const reverseSniffing = this.reverseSniffing ? this.reverseSniffing.toJson() : {};
+            const defaultReverseSniffing = new ReverseSniffing().toJson();
+            result.reverse = {
+                tag: this.reverseTag,
+                sniffing: JSON.stringify(reverseSniffing) === JSON.stringify(defaultReverseSniffing) ? {} : reverseSniffing,
+            };
         }
         // Only include Vision settings when flow is set
         if (this.flow && this.flow !== '') {

+ 2 - 2
web/html/component/aClientTable.html

@@ -94,7 +94,7 @@
       </table>
     </template>
     <div class="tr-table-box">
-      <div class="tr-table-rt">[[ SizeFormatter.sizeFormat(getSumStats(record, client.email)) ]]</div>
+      <div class="tr-table-lt">[[ SizeFormatter.sizeFormat(getSumStats(record, client.email)) ]]</div>
       <div class="tr-table-bar" v-if="!client.enable">
         <a-progress :stroke-color="themeSwitcher.isDarkTheme ? 'rgb(72 84 105)' : '#bcbcbc'" :show-info="false" :percent="statsProgress(record, client.email)" />
       </div>
@@ -104,7 +104,7 @@
       <div v-else class="infinite-bar tr-table-bar">
         <a-progress :show-info="false" :percent="100"></a-progress>
       </div>
-      <div class="tr-table-lt">
+      <div class="tr-table-rt">
         <template v-if="client.totalGB > 0">[[ client._totalGB + "GB" ]]</template>
         <span v-else class="tr-infinity-ch">&infin;</span>
       </div>

+ 35 - 0
web/html/form/outbound.html

@@ -354,6 +354,41 @@
             </template>
             <a-input v-model.trim="outbound.settings.reverseTag" :placeholder='`{{ i18n "pages.xray.outbound.reverseTagPlaceholder" }}`'></a-input>
           </a-form-item>
+          <template v-if="outbound.settings.reverseTag">
+            <a-form-item>
+              <span slot="label">
+                Reverse Sniffing
+                <a-tooltip>
+                  <template slot="title">
+                    <span>{{ i18n "pages.inbounds.noRecommendKeepDefault" }}</span>
+                  </template>
+                  <a-icon type="question-circle"></a-icon>
+                </a-tooltip>
+              </span>
+              <a-switch v-model="outbound.settings.reverseSniffing.enabled"></a-switch>
+            </a-form-item>
+            <template v-if="outbound.settings.reverseSniffing.enabled">
+              <a-form-item :wrapper-col="{span:24}">
+                <a-checkbox-group v-model="outbound.settings.reverseSniffing.destOverride">
+                  <a-checkbox v-for="key,value in SNIFFING_OPTION" :value="key">[[ value ]]</a-checkbox>
+                </a-checkbox-group>
+              </a-form-item>
+              <a-form-item label="Metadata Only">
+                <a-switch v-model="outbound.settings.reverseSniffing.metadataOnly"></a-switch>
+              </a-form-item>
+              <a-form-item label="Route Only">
+                <a-switch v-model="outbound.settings.reverseSniffing.routeOnly"></a-switch>
+              </a-form-item>
+              <a-form-item label="IPs Excluded">
+                <a-select mode="tags" v-model="outbound.settings.reverseSniffing.ipsExcluded" :style="{ width: '100%' }"
+                  :token-separators="[',']" placeholder="IP/CIDR/geoip:*/ext:*"></a-select>
+              </a-form-item>
+              <a-form-item label="Domains Excluded">
+                <a-select mode="tags" v-model="outbound.settings.reverseSniffing.domainsExcluded" :style="{ width: '100%' }"
+                  :token-separators="[',']" placeholder="domain:*/ext:*"></a-select>
+              </a-form-item>
+            </template>
+          </template>
         </template>
         <template v-if="outbound.canEnableTlsFlow()">
           <a-form-item label="Flow">