diff --git a/sub/subService.go b/sub/subService.go index 818f193b..31c3db1d 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -435,34 +435,37 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { } } + // Extract Reality params unconditionally so they're available when + // externalProxy overrides security to "reality" via forceTls. + realitySetting, _ := stream["realitySettings"].(map[string]any) + realitySettings, _ := searchKey(realitySetting, "settings") + if realitySetting != nil { + if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { + sNames, _ := sniValue.([]any) + params["sni"] = sNames[random.Num(len(sNames))].(string) + } + if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { + params["pbk"], _ = pbkValue.(string) + } + if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { + shortIds, _ := sidValue.([]any) + params["sid"] = shortIds[random.Num(len(shortIds))].(string) + } + if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { + if fp, ok := fpValue.(string); ok && len(fp) > 0 { + params["fp"] = fp + } + } + if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok { + if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 { + params["pqv"] = pqv + } + } + params["spx"] = "/" + random.Seq(15) + } + if security == "reality" { params["security"] = "reality" - realitySetting, _ := stream["realitySettings"].(map[string]any) - realitySettings, _ := searchKey(realitySetting, "settings") - if realitySetting != nil { - if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { - sNames, _ := sniValue.([]any) - params["sni"] = sNames[random.Num(len(sNames))].(string) - } - if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { - params["pbk"], _ = pbkValue.(string) - } - if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { - shortIds, _ := sidValue.([]any) - params["sid"] = shortIds[random.Num(len(shortIds))].(string) - } - if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { - if fp, ok := fpValue.(string); ok && len(fp) > 0 { - params["fp"] = fp - } - } - if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok { - if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 { - params["pqv"] = pqv - } - } - params["spx"] = "/" + random.Seq(15) - } if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { params["flow"] = clients[clientIndex].Flow @@ -489,6 +492,14 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { } else { params["security"] = security } + + // Allow externalProxy to override SNI (useful when the + // inbound has extra serverNames for fallback routing that + // should not appear in subscription links). + if sni, ok := ep["sni"].(string); ok && len(sni) > 0 { + params["sni"] = sni + } + url, _ := url.Parse(link) q := url.Query() @@ -627,34 +638,37 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string } } + // Extract Reality params unconditionally so they're available when + // externalProxy overrides security to "reality" via forceTls. + realitySetting, _ := stream["realitySettings"].(map[string]any) + realitySettings, _ := searchKey(realitySetting, "settings") + if realitySetting != nil { + if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { + sNames, _ := sniValue.([]any) + params["sni"] = sNames[random.Num(len(sNames))].(string) + } + if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { + params["pbk"], _ = pbkValue.(string) + } + if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { + shortIds, _ := sidValue.([]any) + params["sid"] = shortIds[random.Num(len(shortIds))].(string) + } + if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { + if fp, ok := fpValue.(string); ok && len(fp) > 0 { + params["fp"] = fp + } + } + if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok { + if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 { + params["pqv"] = pqv + } + } + params["spx"] = "/" + random.Seq(15) + } + if security == "reality" { params["security"] = "reality" - realitySetting, _ := stream["realitySettings"].(map[string]any) - realitySettings, _ := searchKey(realitySetting, "settings") - if realitySetting != nil { - if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { - sNames, _ := sniValue.([]any) - params["sni"] = sNames[random.Num(len(sNames))].(string) - } - if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { - params["pbk"], _ = pbkValue.(string) - } - if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { - shortIds, _ := sidValue.([]any) - params["sid"] = shortIds[random.Num(len(shortIds))].(string) - } - if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { - if fp, ok := fpValue.(string); ok && len(fp) > 0 { - params["fp"] = fp - } - } - if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok { - if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 { - params["pqv"] = pqv - } - } - params["spx"] = "/" + random.Seq(15) - } if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { params["flow"] = clients[clientIndex].Flow @@ -681,6 +695,14 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string } else { params["security"] = security } + + // Allow externalProxy to override SNI (useful when the + // inbound has extra serverNames for fallback routing that + // should not appear in subscription links). + if sni, ok := ep["sni"].(string); ok && len(sni) > 0 { + params["sni"] = sni + } + url, _ := url.Parse(link) q := url.Query() @@ -848,6 +870,14 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st } else { params["security"] = security } + + // Allow externalProxy to override SNI (useful when the + // inbound has extra serverNames for fallback routing that + // should not appear in subscription links). + if sni, ok := ep["sni"].(string); ok && len(sni) > 0 { + params["sni"] = sni + } + url, _ := url.Parse(link) q := url.Query() diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js index b6059cf7..111ee1ae 100644 --- a/web/assets/js/model/inbound.js +++ b/web/assets/js/model/inbound.js @@ -1738,7 +1738,7 @@ class Inbound extends XrayCommonClass { 'o': '', }; if (ObjectUtil.isArrEmpty(this.stream.externalProxy)) { - let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar); + let r = orderChars.split('').map(char => orders[char]).filter(x => x && x.length > 0).join(separationChar); result.push({ remark: r, link: this.genLink(addr, port, 'same', r, client) @@ -1746,7 +1746,7 @@ class Inbound extends XrayCommonClass { } else { this.stream.externalProxy.forEach((ep) => { orders['o'] = ep.remark; - let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar); + let r = orderChars.split('').map(char => orders[char]).filter(x => x && x.length > 0).join(separationChar); result.push({ remark: r, link: this.genLink(ep.dest, ep.port, ep.forceTls, r, client)