package core import ( "encoding/json" "fmt" ) const DefaultSocksPort = 10808 // GenerateXrayConfig generates a full JSON config for xray-core. // Xray acts as backend: listens SOCKS5 on a local port, connects to the remote server. func GenerateXrayConfig(link *ProxyLink, socksPort int) (string, error) { if socksPort == 0 { socksPort = DefaultSocksPort } config := map[string]any{ "log": map[string]any{ "loglevel": "warning", }, "inbounds": []any{ buildSocksInbound(socksPort), }, "outbounds": []any{ buildProxyOutbound(link), buildDirectOutbound(), }, } data, err := json.MarshalIndent(config, "", " ") if err != nil { return "", fmt.Errorf("failed to marshal xray config: %w", err) } return string(data), nil } func buildSocksInbound(port int) map[string]any { return map[string]any{ "port": port, "listen": "127.0.0.1", "protocol": "socks", "settings": map[string]any{ "auth": "noauth", "udp": true, }, "tag": "socks-in", } } func buildProxyOutbound(link *ProxyLink) map[string]any { outbound := map[string]any{ "tag": "proxy", "protocol": link.Protocol, } switch link.Protocol { case "trojan": outbound["settings"] = buildTrojanSettings(link) case "vless": outbound["settings"] = buildVlessSettings(link) } outbound["streamSettings"] = buildStreamSettings(link) return outbound } func buildTrojanSettings(link *ProxyLink) map[string]any { return map[string]any{ "servers": []any{ map[string]any{ "address": link.Address, "port": link.Port, "password": link.Credential, }, }, } } func buildVlessSettings(link *ProxyLink) map[string]any { user := map[string]any{ "id": link.Credential, "encryption": "none", } if link.Flow != "" { user["flow"] = link.Flow } return map[string]any{ "vnext": []any{ map[string]any{ "address": link.Address, "port": link.Port, "users": []any{user}, }, }, } } func buildStreamSettings(link *ProxyLink) map[string]any { stream := map[string]any{ "network": link.Transport, } // Security if link.Security != "" && link.Security != "none" { stream["security"] = link.Security } // Transport-specific settings switch link.Transport { case "grpc": stream["grpcSettings"] = map[string]any{ "serviceName": link.ServiceName, } case "xhttp": xhttp := map[string]any{ "path": defaultIfEmpty(link.Path, "/"), } if link.Host != "" { xhttp["host"] = link.Host } stream["xhttpSettings"] = xhttp case "ws": ws := map[string]any{ "path": defaultIfEmpty(link.Path, "/"), } if link.Host != "" { ws["headers"] = map[string]any{ "Host": link.Host, } } stream["wsSettings"] = ws case "h2", "http": h2 := map[string]any{ "path": defaultIfEmpty(link.Path, "/"), } if link.Host != "" { h2["host"] = []string{link.Host} } stream["httpSettings"] = h2 } // Security-specific settings switch link.Security { case "reality": stream["realitySettings"] = map[string]any{ "publicKey": link.PublicKey, "shortId": link.ShortId, "serverName": link.Sni, "fingerprint": link.Fingerprint, } case "tls": tls := map[string]any{ "fingerprint": link.Fingerprint, } if link.Sni != "" { tls["serverName"] = link.Sni } stream["tlsSettings"] = tls } return stream } func buildDirectOutbound() map[string]any { return map[string]any{ "tag": "direct", "protocol": "freedom", } } func defaultIfEmpty(s, def string) string { if s == "" { return def } return s }