Browse Source

[feature] add grpc multiMode

MHSanaei 1 year ago
parent
commit
607c5d3598

+ 0 - 2
go.sum

@@ -9,8 +9,6 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P
 github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
 github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ=
-github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
 github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q=
 github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
 github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=

+ 2 - 1
logger/logger.go

@@ -1,8 +1,9 @@
 package logger
 
 import (
-	"github.com/op/go-logging"
 	"os"
+
+	"github.com/op/go-logging"
 )
 
 var logger *logging.Logger

+ 58 - 38
web/assets/js/model/xray.js

@@ -440,18 +440,26 @@ class QuicStreamSettings extends XrayCommonClass {
 }
 
 class GrpcStreamSettings extends XrayCommonClass {
-    constructor(serviceName="") {
+    constructor(
+        serviceName="",
+        multiMode=false
+        ) {
         super();
         this.serviceName = serviceName;
+        this.multiMode = multiMode;
     }
 
     static fromJson(json={}) {
-        return new GrpcStreamSettings(json.serviceName);
+        return new GrpcStreamSettings(
+            json.serviceName,
+            json.multiMode
+            );
     }
 
     toJson() {
         return {
             serviceName: this.serviceName,
+            multiMode: this.multiMode
         }
     }
 }
@@ -1246,67 +1254,73 @@ class Inbound extends XrayCommonClass {
         if (this.protocol !== Protocols.VMESS) {
             return '';
         }
+        let obj = {
+            v: '2',
+            ps: remark,
+            add: address,
+            port: this.port,
+            id: this.settings.vmesses[clientIndex].id,
+            aid: this.settings.vmesses[clientIndex].alterId,
+            net: this.stream.network,
+            type: 'none',
+            tls: this.stream.security,
+        };
         let network = this.stream.network;
-        let type = 'none';
-        let host = '';
-        let path = '';
         if (network === 'tcp') {
             let tcp = this.stream.tcp;
-            type = tcp.type;
-            if (type === 'http') {
+            obj.type = tcp.type;
+            if (tcp.type === 'http') {
                 let request = tcp.request;
-                path = request.path.join(',');
+                obj.path = request.path.join(',');
                 let index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
                 if (index >= 0) {
-                    host = request.headers[index].value;
+                    obj.host = request.headers[index].value;
                 }
             }
         } else if (network === 'kcp') {
             let kcp = this.stream.kcp;
-            type = kcp.type;
-            path = kcp.seed;
+            obj.type = kcp.type;
+            obj.path = kcp.seed;
         } else if (network === 'ws') {
             let ws = this.stream.ws;
-            path = ws.path;
+            obj.path = ws.path;
             let index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host');
             if (index >= 0) {
-                host = ws.headers[index].value;
+                obj.host = ws.headers[index].value;
             }
         } else if (network === 'http') {
-            network = 'h2';
-            path = this.stream.http.path;
-            host = this.stream.http.host.join(',');
+            obj.net = 'h2';
+            obj.path = this.stream.http.path;
+            obj.host = this.stream.http.host.join(',');
         } else if (network === 'quic') {
-            type = this.stream.quic.type;
-            host = this.stream.quic.security;
-            path = this.stream.quic.key;
+            obj.type = this.stream.quic.type;
+            obj.host = this.stream.quic.security;
+            obj.path = this.stream.quic.key;
         } else if (network === 'grpc') {
-            path = this.stream.grpc.serviceName;
+            obj.path = this.stream.grpc.serviceName;
+            if (this.stream.grpc.multiMode){
+                obj.type = 'multi'
+            }
         }
 
         if (this.stream.security === 'tls') {
             if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
-                address = this.stream.tls.server;
+                obj.add = this.stream.tls.server;
+            }
+            if (!ObjectUtil.isEmpty(this.stream.tls.settings.serverName)){
+                obj.sni = this.stream.tls.settings.serverName;
+            }
+            if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)){
+                obj.fp = this.stream.tls.settings.fingerprint;
+            }
+            if (this.stream.tls.alpn.length>0){
+                obj.alpn = this.stream.tls.alpn.join(',');
+            }
+            if (this.stream.tls.settings.allowInsecure){
+                obj.allowInsecure = this.stream.tls.settings.allowInsecure;
             }
         }
         
-        let obj = {
-            v: '2',
-            ps: remark,
-            add: address,
-            port: this.port,
-            id: this.settings.vmesses[clientIndex].id,
-            aid: this.settings.vmesses[clientIndex].alterId,
-            net: network,
-            type: type,
-            host: host,
-            path: path,
-            tls: this.stream.security,
-            sni: this.stream.tls.settings.serverName,
-            fp: this.stream.tls.settings.fingerprint,
-            alpn: this.stream.tls.alpn.join(','),
-            allowInsecure: this.stream.tls.settings.allowInsecure,
-        };
         return 'vmess://' + base64(JSON.stringify(obj, null, 2));
     }
 
@@ -1359,6 +1373,9 @@ class Inbound extends XrayCommonClass {
             case "grpc":
                 const grpc = this.stream.grpc;
                 params.set("serviceName", grpc.serviceName);
+                if(grpc.multiMode){
+                    params.set("mode", "multi");
+                }
                 break;
         }
 
@@ -1476,6 +1493,9 @@ class Inbound extends XrayCommonClass {
             case "grpc":
                 const grpc = this.stream.grpc;
                 params.set("serviceName", grpc.serviceName);
+                if(grpc.multiMode){
+                    params.set("mode", "multi");
+                }
                 break;
         }
 

+ 2 - 1
web/global/global.go

@@ -2,8 +2,9 @@ package global
 
 import (
 	"context"
-	"github.com/robfig/cron/v3"
 	_ "unsafe"
+
+	"github.com/robfig/cron/v3"
 )
 
 var webServer WebServer

+ 3 - 0
web/html/xui/form/stream/stream_grpc.html

@@ -3,5 +3,8 @@
     <a-form-item label="ServiceName">
         <a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
     </a-form-item>
+    <a-form-item label="Multi Mode">
+        <a-switch v-model="inbound.stream.grpc.multiMode"></a-switch>
+    </a-form-item>
 </a-form>
 {{end}}

+ 1 - 0
web/html/xui/inbound_info_modal.html

@@ -41,6 +41,7 @@
             
             <template v-if="inbound.isGrpc">
                 <tr><td>grpc serviceName</td><td><a-tag color="green">[[ inbound.serviceName ]]</a-tag></td></tr>
+                <tr><td>grpc multiMode</td><td><a-tag color="green">[[ inbound.stream.grpc.multiMode ]]</a-tag></td></tr>
             </template>
             </table>
         </td></tr>

+ 45 - 45
web/service/sub.go

@@ -102,80 +102,89 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string {
 }
 
 func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
-	address := s.address
 	if inbound.Protocol != model.VMess {
 		return ""
 	}
+	obj := map[string]interface{}{
+		"v":    "2",
+		"ps":   email,
+		"add":  s.address,
+		"port": inbound.Port,
+		"type": "none",
+	}
 	var stream map[string]interface{}
 	json.Unmarshal([]byte(inbound.StreamSettings), &stream)
 	network, _ := stream["network"].(string)
-	typeStr := "none"
-	host := ""
-	path := ""
-	sni := ""
-	fp := ""
-	var alpn []string
-	allowInsecure := false
+	obj["net"] = network
 	switch network {
 	case "tcp":
 		tcp, _ := stream["tcpSettings"].(map[string]interface{})
 		header, _ := tcp["header"].(map[string]interface{})
-		typeStr, _ = header["type"].(string)
+		typeStr, _ := header["type"].(string)
+		obj["type"] = typeStr
 		if typeStr == "http" {
 			request := header["request"].(map[string]interface{})
 			requestPath, _ := request["path"].([]interface{})
-			path = requestPath[0].(string)
+			obj["path"] = requestPath[0].(string)
 			headers, _ := request["headers"].(map[string]interface{})
-			host = searchHost(headers)
+			obj["host"] = searchHost(headers)
 		}
 	case "kcp":
 		kcp, _ := stream["kcpSettings"].(map[string]interface{})
 		header, _ := kcp["header"].(map[string]interface{})
-		typeStr, _ = header["type"].(string)
-		path, _ = kcp["seed"].(string)
+		obj["type"], _ = header["type"].(string)
+		obj["path"], _ = kcp["seed"].(string)
 	case "ws":
 		ws, _ := stream["wsSettings"].(map[string]interface{})
-		path = ws["path"].(string)
+		obj["path"] = ws["path"].(string)
 		headers, _ := ws["headers"].(map[string]interface{})
-		host = searchHost(headers)
+		obj["host"] = searchHost(headers)
 	case "http":
-		network = "h2"
+		obj["net"] = "h2"
 		http, _ := stream["httpSettings"].(map[string]interface{})
-		path, _ = http["path"].(string)
-		host = searchHost(http)
+		obj["path"], _ = http["path"].(string)
+		obj["host"] = searchHost(http)
 	case "quic":
 		quic, _ := stream["quicSettings"].(map[string]interface{})
 		header := quic["header"].(map[string]interface{})
-		typeStr, _ = header["type"].(string)
-		host, _ = quic["security"].(string)
-		path, _ = quic["key"].(string)
+		obj["type"], _ = header["type"].(string)
+		obj["host"], _ = quic["security"].(string)
+		obj["path"], _ = quic["key"].(string)
 	case "grpc":
 		grpc, _ := stream["grpcSettings"].(map[string]interface{})
-		path = grpc["serviceName"].(string)
+		obj["path"] = grpc["serviceName"].(string)
+		if grpc["multiMode"].(bool) {
+			obj["type"] = "multi"
+		}
 	}
 
 	security, _ := stream["security"].(string)
+	obj["tls"] = security
 	if security == "tls" {
 		tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
 		alpns, _ := tlsSetting["alpn"].([]interface{})
-		for _, a := range alpns {
-			alpn = append(alpn, a.(string))
+		if len(alpns) > 0 {
+			var alpn []string
+			for _, a := range alpns {
+				alpn = append(alpn, a.(string))
+			}
+			obj["alpn"] = strings.Join(alpn, ",")
 		}
 		tlsSettings, _ := searchKey(tlsSetting, "settings")
 		if tlsSetting != nil {
 			if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
-				sni, _ = sniValue.(string)
+				obj["sni"], _ = sniValue.(string)
 			}
 			if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
-				fp, _ = fpValue.(string)
+				obj["fp"], _ = fpValue.(string)
 			}
 			if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
-				allowInsecure, _ = insecure.(bool)
+				obj["allowInsecure"], _ = insecure.(bool)
 			}
 		}
 		serverName, _ := tlsSetting["serverName"].(string)
 		if serverName != "" {
-			address = serverName
+			obj["add"] = serverName
 		}
 	}
 
@@ -187,24 +196,9 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
 			break
 		}
 	}
+	obj["id"] = clients[clientIndex].ID
+	obj["aid"] = clients[clientIndex].AlterIds
 
-	obj := map[string]interface{}{
-		"v":             "2",
-		"ps":            email,
-		"add":           address,
-		"port":          inbound.Port,
-		"id":            clients[clientIndex].ID,
-		"aid":           clients[clientIndex].AlterIds,
-		"net":           network,
-		"type":          typeStr,
-		"host":          host,
-		"path":          path,
-		"tls":           security,
-		"sni":           sni,
-		"fp":            fp,
-		"alpn":          strings.Join(alpn, ","),
-		"allowInsecure": allowInsecure,
-	}
 	jsonStr, _ := json.MarshalIndent(obj, "", "  ")
 	return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
 }
@@ -266,6 +260,9 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
 	case "grpc":
 		grpc, _ := stream["grpcSettings"].(map[string]interface{})
 		params["serviceName"] = grpc["serviceName"].(string)
+		if grpc["multiMode"].(bool) {
+			params["mode"] = "multi"
+		}
 	}
 
 	security, _ := stream["security"].(string)
@@ -444,6 +441,9 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
 	case "grpc":
 		grpc, _ := stream["grpcSettings"].(map[string]interface{})
 		params["serviceName"] = grpc["serviceName"].(string)
+		if grpc["multiMode"].(bool) {
+			params["mode"] = "multi"
+		}
 	}
 
 	security, _ := stream["security"].(string)