fix: Clash proxy entries missing reality-opts, client-fingerprint, network

- Fix REALITY settings extraction: publicKey/shortIds/fingerprint are
  nested under realitySettings.settings, not directly under realitySettings
- Add network field to all proxy entries (default "tcp")
- Move non-REALITY fingerprint into else branch to avoid duplication
This commit is contained in:
root 2026-04-25 20:32:30 +08:00
parent 25cf22d161
commit 0366a21d6d
2 changed files with 32 additions and 7 deletions

View file

@ -0,0 +1,13 @@
# Fix: Clash proxy entries missing reality-opts, client-fingerprint, network
## Date: 2026-04-25
## Changes
### Bug Fixes
- `sub/subClashService.go` — Fixed REALITY settings extraction: `publicKey` is at `realitySettings.settings.publicKey`, not `realitySettings.publicKey`. `shortIds` is an array (use first element). `fingerprint` is at `realitySettings.settings.fingerprint`.
- `sub/subClashService.go` — Added `network` field to all proxy entries (default "tcp")
- `sub/subClashService.go` — Moved non-REALITY fingerprint code inside the `else` branch to avoid duplication
### Version
- `config/version` — Bumped to v1.7.2.1

View file

@ -291,10 +291,12 @@ func (s *SubClashService) buildProxyEntry(inbound *model.Inbound, client model.C
parts = append(parts, "tls: true") parts = append(parts, "tls: true")
if security == "reality" { if security == "reality" {
realitySetting, _ := stream["realitySettings"].(map[string]any) realitySetting, _ := stream["realitySettings"].(map[string]any)
if publicKey, ok := realitySetting["publicKey"].(string); ok && publicKey != "" { // publicKey and fingerprint are nested under realitySettings.settings
realityInner, _ := realitySetting["settings"].(map[string]any)
if publicKey, ok := realityInner["publicKey"].(string); ok && publicKey != "" {
realityOpts := fmt.Sprintf("reality-opts:\n public-key: %q", publicKey) realityOpts := fmt.Sprintf("reality-opts:\n public-key: %q", publicKey)
if shortId, ok := realitySetting["shortId"].(string); ok && shortId != "" { if shortIds, ok := realitySetting["shortIds"].([]any); ok && len(shortIds) > 0 {
realityOpts += fmt.Sprintf("\n short-id: %q", shortId) realityOpts += fmt.Sprintf("\n short-id: %q", fmt.Sprintf("%v", shortIds[0]))
} }
parts = append(parts, realityOpts) parts = append(parts, realityOpts)
} }
@ -304,6 +306,10 @@ func (s *SubClashService) buildProxyEntry(inbound *model.Inbound, client model.C
sni := fmt.Sprintf("%v", serverNames[0]) sni := fmt.Sprintf("%v", serverNames[0])
parts = append(parts, fmt.Sprintf("sni: %q", sni)) parts = append(parts, fmt.Sprintf("sni: %q", sni))
} }
// Fingerprint from reality settings inner
if fp, ok := realityInner["fingerprint"].(string); ok && fp != "" {
parts = append(parts, fmt.Sprintf("client-fingerprint: %q", fp))
}
} else { } else {
// TLS settings // TLS settings
tlsSetting, _ := stream["tlsSettings"].(map[string]any) tlsSetting, _ := stream["tlsSettings"].(map[string]any)
@ -317,10 +323,10 @@ func (s *SubClashService) buildProxyEntry(inbound *model.Inbound, client model.C
} }
parts = append(parts, fmt.Sprintf("alpn: [%s]", strings.Join(alpnStrs, ", "))) parts = append(parts, fmt.Sprintf("alpn: [%s]", strings.Join(alpnStrs, ", ")))
} }
} // Fingerprint for non-REALITY TLS
// Fingerprint if fp, ok := stream["fingerprint"].(string); ok && fp != "" {
if fp, ok := stream["fingerprint"].(string); ok && fp != "" { parts = append(parts, fmt.Sprintf("client-fingerprint: %q", fp))
parts = append(parts, fmt.Sprintf("client-fingerprint: %q", fp)) }
} }
} else { } else {
parts = append(parts, "tls: false") parts = append(parts, "tls: false")
@ -328,6 +334,12 @@ func (s *SubClashService) buildProxyEntry(inbound *model.Inbound, client model.C
parts = append(parts, "udp: true") parts = append(parts, "udp: true")
// Network type
if network == "" {
network = "tcp"
}
parts = append(parts, fmt.Sprintf("network: %s", network))
// Network-specific settings // Network-specific settings
switch network { switch network {
case "ws": case "ws":