mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-10 12:17:14 +00:00
fix(sub): drop Reality parameters when a host forces plain TLS
A Host row may set Security to tls on an inbound whose own stream is Reality. The emitted link then carried security=tls next to pbk, sid, spx and the Reality dest as sni: the endpoint no longer performs a Reality handshake, so those describe a server the client will never reach, and clients that honour them fail to connect. Only the security key was rewritten at emit time, and the existing strip covered alpn/sni/fp/pcs for forceTls=none alone. Clear the Reality-only parameters before the endpoint's own TLS overrides are applied, so a host that supplies its own sni or fingerprint still wins. Closes #6424
This commit is contained in:
@@ -69,6 +69,19 @@ func applyEndpointTLSObj(e ShareEndpoint, obj map[string]any, security string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dropBaseRealityParams removes the parameters that only mean something on a
|
||||||
|
// reality link once a host forces the endpoint to plain TLS or no TLS.
|
||||||
|
func dropBaseRealityParams(params map[string]string, baseSecurity, securityToApply string) {
|
||||||
|
if baseSecurity != "reality" || securityToApply == "reality" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// sni and fp name the master's reality dest, not this endpoint's own
|
||||||
|
// certificate; the host's values are re-applied right after this.
|
||||||
|
for _, k := range []string{"pbk", "sid", "spx", "pqv", "sni", "fp"} {
|
||||||
|
delete(params, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// buildEndpointLinks renders one URL-param link per endpoint (vless/trojan/ss).
|
// buildEndpointLinks renders one URL-param link per endpoint (vless/trojan/ss).
|
||||||
// securityToApply mirrors the legacy externalProxy loop: "same" keeps the base
|
// securityToApply mirrors the legacy externalProxy loop: "same" keeps the base
|
||||||
// security, otherwise the endpoint's forceTls wins; "none" strips TLS hint
|
// security, otherwise the endpoint's forceTls wins; "none" strips TLS hint
|
||||||
@@ -87,6 +100,7 @@ func (s *SubService) buildEndpointLinks(
|
|||||||
securityToApply = e.ForceTls
|
securityToApply = e.ForceTls
|
||||||
}
|
}
|
||||||
nextParams := cloneStringMap(params)
|
nextParams := cloneStringMap(params)
|
||||||
|
dropBaseRealityParams(nextParams, baseSecurity, securityToApply)
|
||||||
applyEndpointTLSParams(e, nextParams, securityToApply)
|
applyEndpointTLSParams(e, nextParams, securityToApply)
|
||||||
applyEndpointRealityParams(e, nextParams, securityToApply)
|
applyEndpointRealityParams(e, nextParams, securityToApply)
|
||||||
applyEndpointHostPath(e, nextParams)
|
applyEndpointHostPath(e, nextParams)
|
||||||
|
|||||||
@@ -418,3 +418,27 @@ func TestSub_ExcludeFromSubTypes(t *testing.T) {
|
|||||||
t.Fatalf("host excluded from clash must not appear in GetClash:\n%s", yaml)
|
t.Fatalf("host excluded from clash must not appear in GetClash:\n%s", yaml)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A host that forces plain TLS over a Reality inbound must not leave the
|
||||||
|
// Reality identity behind: pbk/sid/spx and the Reality dest sni describe a
|
||||||
|
// handshake the endpoint no longer performs.
|
||||||
|
func TestSub_HostTlsOverRealityDropsRealityParams(t *testing.T) {
|
||||||
|
seedSubDB(t)
|
||||||
|
reality := `{"network":"tcp","security":"reality","realitySettings":{"serverNames":["master-dest.example.com"],"publicKey":"MASTERPBK","shortIds":["ab12"],"fingerprint":"chrome"}}`
|
||||||
|
ib := seedSubInbound(t, "s1", "reality-in", 4461, 1, reality)
|
||||||
|
seedHost(t, &model.Host{InboundId: ib.Id, SortOrder: 1, Remark: "H", Address: "edge.example.com", Port: 443, Security: "tls"})
|
||||||
|
|
||||||
|
links, _, _, _, err := NewSubService("").GetSubs("s1", "req.example.com")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetSubs: %v", err)
|
||||||
|
}
|
||||||
|
joined := strings.Join(links, "\n")
|
||||||
|
if !strings.Contains(joined, "security=tls") {
|
||||||
|
t.Fatalf("host forces tls, link must say so: %s", joined)
|
||||||
|
}
|
||||||
|
for _, leaked := range []string{"pbk=", "sid=", "spx=", "sni=master-dest.example.com"} {
|
||||||
|
if strings.Contains(joined, leaked) {
|
||||||
|
t.Fatalf("reality parameter %q survived a tls host override: %s", leaked, joined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user