diff --git a/util/genLink.go b/util/genLink.go index 3ac6e39..6f5615d 100644 --- a/util/genLink.go +++ b/util/genLink.go @@ -13,6 +13,11 @@ import ( var InboundTypeWithLink = []string{"socks", "http", "mixed", "shadowsocks", "naive", "hysteria", "hysteria2", "anytls", "tuic", "vless", "trojan", "vmess"} +type LinkParam struct { + Key string + Value string +} + func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname string) []string { inbound, err := i.MarshalFull() if err != nil { @@ -30,7 +35,9 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri } var Addrs []map[string]interface{} - json.Unmarshal(i.Addrs, &Addrs) + if err := json.Unmarshal(i.Addrs, &Addrs); err != nil { + return []string{} + } if len(Addrs) == 0 { Addrs = append(Addrs, map[string]interface{}{ "server": hostname, @@ -63,13 +70,13 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri switch i.Type { case "socks": - return socksLink(userConfig["socks"], *inbound, Addrs) + return socksLink(userConfig["socks"], Addrs) case "http": - return httpLink(userConfig["http"], *inbound, Addrs) + return httpLink(userConfig["http"], Addrs) case "mixed": return append( - socksLink(userConfig["socks"], *inbound, Addrs), - httpLink(userConfig["http"], *inbound, Addrs)..., + socksLink(userConfig["socks"], Addrs), + httpLink(userConfig["http"], Addrs)..., ) case "shadowsocks": return shadowsocksLink(userConfig, *inbound, Addrs) @@ -96,8 +103,12 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri func prepareTls(t *model.Tls) map[string]interface{} { var iTls, oTls map[string]interface{} - json.Unmarshal(t.Client, &oTls) - json.Unmarshal(t.Server, &iTls) + if err := json.Unmarshal(t.Client, &oTls); err != nil { + return nil + } + if err := json.Unmarshal(t.Server, &iTls); err != nil { + return nil + } for k, v := range iTls { switch k { @@ -107,8 +118,8 @@ func prepareTls(t *model.Tls) map[string]interface{} { reality := v.(map[string]interface{}) clientReality := oTls["reality"].(map[string]interface{}) clientReality["enabled"] = reality["enabled"] - if short_ids, hasSIds := reality["short_id"].([]interface{}); hasSIds && len(short_ids) > 0 { - clientReality["short_id"] = short_ids[common.RandomInt(len(short_ids))] + if shortIDs, hasSIds := reality["short_id"].([]interface{}); hasSIds && len(shortIDs) > 0 { + clientReality["short_id"] = shortIDs[common.RandomInt(len(shortIDs))] } oTls["reality"] = clientReality } @@ -116,7 +127,7 @@ func prepareTls(t *model.Tls) map[string]interface{} { return oTls } -func socksLink(userConfig map[string]interface{}, inbound map[string]interface{}, addrs []map[string]interface{}) []string { +func socksLink(userConfig map[string]interface{}, addrs []map[string]interface{}) []string { var links []string for _, addr := range addrs { links = append(links, fmt.Sprintf("socks5://%s:%s@%s:%d", userConfig["username"], userConfig["password"], addr["server"].(string), uint(addr["server_port"].(float64)))) @@ -124,9 +135,9 @@ func socksLink(userConfig map[string]interface{}, inbound map[string]interface{} return links } -func httpLink(userConfig map[string]interface{}, inbound map[string]interface{}, addrs []map[string]interface{}) []string { +func httpLink(userConfig map[string]interface{}, addrs []map[string]interface{}) []string { var links []string - var protocol string = "http" + protocol := "http" for _, addr := range addrs { if addr["tls"] != nil { protocol = "https" @@ -177,27 +188,27 @@ func naiveLink( var links []string for _, addr := range addrs { - params := map[string]string{} - params["padding"] = "1" + var params []LinkParam + params = append(params, LinkParam{"padding", "1"}) if tls, ok := addr["tls"].(map[string]interface{}); ok { if sni, ok := tls["server_name"].(string); ok { - params["peer"] = sni + params = append(params, LinkParam{"peer", sni}) } if alpn, ok := tls["alpn"].([]interface{}); ok { alpnList := make([]string, len(alpn)) for i, v := range alpn { alpnList[i] = v.(string) } - params["alpn"] = strings.Join(alpnList, ",") + params = append(params, LinkParam{"alpn", strings.Join(alpnList, ",")}) } if insecure, ok := tls["insecure"].(bool); ok && insecure { - params["insecure"] = "1" + params = append(params, LinkParam{"insecure", "1"}) } } if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { - params["tfo"] = "1" + params = append(params, LinkParam{"tfo", "1"}) } else { - params["tfo"] = "0" + params = append(params, LinkParam{"tfo", "0"}) } port, _ := addr["server_port"].(float64) @@ -216,35 +227,37 @@ func hysteriaLink( var links []string for _, addr := range addrs { - params := map[string]string{} + var params []LinkParam if upmbps, ok := inbound["up_mbps"].(float64); ok { - params["downmbps"] = fmt.Sprintf("%.0f", upmbps) + params = append(params, LinkParam{"downmbps", fmt.Sprintf("%.0f", upmbps)}) } if downmbps, ok := inbound["down_mbps"].(float64); ok { - params["upmbps"] = fmt.Sprintf("%.0f", downmbps) + params = append(params, LinkParam{"upmbps", fmt.Sprintf("%.0f", downmbps)}) } if auth, ok := userConfig["auth_str"].(string); ok { - params["auth"] = auth + params = append(params, LinkParam{"auth", auth}) } if tls, ok := addr["tls"].(map[string]interface{}); ok { getTlsParams(¶ms, tls, "insecure") } if obfs, ok := inbound["obfs"].(string); ok { - params["obfs"] = obfs + params = append(params, LinkParam{"obfs", obfs}) } if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { - params["fastopen"] = "1" + params = append(params, LinkParam{"fastopen", "1"}) } else { - params["fastopen"] = "0" + params = append(params, LinkParam{"fastopen", "0"}) } var outJson map[string]interface{} - json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson) + if err := json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson); err != nil { + return []string{} // Handle error + } if mport, ok := outJson["server_ports"].([]interface{}); ok { mportList := make([]string, len(mport)) for i, v := range mport { mportList[i] = v.(string) } - params["mport"] = strings.Join(mportList, ",") + params = append(params, LinkParam{"mport", strings.Join(mportList, ",")}) } port, _ := addr["server_port"].(float64) @@ -265,37 +278,39 @@ func hysteria2Link( var links []string for _, addr := range addrs { - params := map[string]string{} + var params []LinkParam if upmbps, ok := inbound["up_mbps"].(float64); ok { - params["downmbps"] = fmt.Sprintf("%.0f", upmbps) + params = append(params, LinkParam{"downmbps", fmt.Sprintf("%.0f", upmbps)}) } if downmbps, ok := inbound["down_mbps"].(float64); ok { - params["upmbps"] = fmt.Sprintf("%.0f", downmbps) + params = append(params, LinkParam{"upmbps", fmt.Sprintf("%.0f", downmbps)}) } if tls, ok := addr["tls"].(map[string]interface{}); ok { getTlsParams(¶ms, tls, "insecure") } if obfs, ok := inbound["obfs"].(map[string]interface{}); ok { if obfsType, ok := obfs["type"].(string); ok { - params["obfs"] = obfsType + params = append(params, LinkParam{"obfs", obfsType}) } if obfsPassword, ok := obfs["password"].(string); ok { - params["obfs-password"] = obfsPassword + params = append(params, LinkParam{"obfs-password", obfsPassword}) } } if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { - params["fastopen"] = "1" + params = append(params, LinkParam{"fastopen", "1"}) } else { - params["fastopen"] = "0" + params = append(params, LinkParam{"fastopen", "0"}) } var outJson map[string]interface{} - json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson) + if err := json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson); err != nil { + return []string{} // Handle error + } if mport, ok := outJson["server_ports"].([]interface{}); ok { mportList := make([]string, len(mport)) for i, v := range mport { mportList[i] = v.(string) } - params["mport"] = strings.Join(mportList, ",") + params = append(params, LinkParam{"mport", strings.Join(mportList, ",")}) } port, _ := addr["server_port"].(float64) @@ -315,7 +330,7 @@ func anytlsLink( var links []string for _, addr := range addrs { - params := map[string]string{} + var params []LinkParam if tls, ok := addr["tls"].(map[string]interface{}); ok { getTlsParams(¶ms, tls, "insecure") } @@ -339,12 +354,12 @@ func tuicLink( var links []string for _, addr := range addrs { - params := map[string]string{} + var params []LinkParam if tls, ok := addr["tls"].(map[string]interface{}); ok { getTlsParams(¶ms, tls, "insecure") } if congestionControl, ok := inbound["congestion_control"].(string); ok { - params["congestion_control"] = congestionControl + params = append(params, LinkParam{"congestion_control", congestionControl}) } port, _ := addr["server_port"].(float64) @@ -365,11 +380,12 @@ func vlessLink( var links []string for _, addr := range addrs { - params := baseParams + params := make([]LinkParam, len(baseParams)) + copy(params, baseParams) if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { getTlsParams(¶ms, tls, "allowInsecure") if flow, ok := userConfig["flow"].(string); ok { - params["flow"] = flow + params = append(params, LinkParam{"flow", flow}) } } port, _ := addr["server_port"].(float64) @@ -390,7 +406,8 @@ func trojanLink( var links []string for _, addr := range addrs { - params := baseParams + params := make([]LinkParam, len(baseParams)) + copy(params, baseParams) if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { getTlsParams(¶ms, tls, "allowInsecure") } @@ -409,58 +426,58 @@ func vmessLink( addrs []map[string]interface{}) []string { uuid, _ := userConfig["uuid"].(string) - trasportParams := getTransportParams(inbound["transport"]) + transportParams := getTransportParams(inbound["transport"]) var links []string baseParams := map[string]interface{}{ - "v": 2, + "v": "2", "id": uuid, "aid": 0, } - if trasportParams["type"] == "http" || trasportParams["type"] == "tcp" { + + var net, typ, host, path string + for _, p := range transportParams { + switch p.Key { + case "type": + net = p.Value + case "host": + host = p.Value + case "path": + path = p.Value + } + } + + if net == "http" || net == "tcp" { baseParams["net"] = "tcp" - if trasportParams["type"] == "http" { - baseParams["type"] = "http" + if net == "http" { + typ = "http" } } else { - baseParams["net"] = trasportParams["type"] + baseParams["net"] = net } for _, addr := range addrs { - obj := baseParams - obj["add"], _ = addr["server"].(string) - port, _ := addr["server_port"].(float64) - obj["port"] = uint(port) - obj["ps"], _ = addr["remark"].(string) - if trasportParams["host"] != "" { - obj["host"] = trasportParams["host"] - } - if trasportParams["path"] != "" { - obj["path"] = trasportParams["path"] - } - if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { - obj["tls"] = "tls" - if insecure, ok := tls["insecure"].(bool); ok && insecure { - obj["allowInsecure"] = 1 - } - if sni, ok := tls["server_name"].(string); ok { - obj["sni"] = sni - } - if alpn, ok := tls["alpn"].([]interface{}); ok { - alpnList := make([]string, len(alpn)) - for i, v := range alpn { - alpnList[i] = v.(string) - } - obj["alpn"] = strings.Join(alpnList, ",") - } - if utls, ok := tls["utls"].(map[string]interface{}); ok { - obj["fp"], _ = utls["fingerprint"].(string) - } - } else { - obj["tls"] = "none" + obj := make(map[string]interface{}) + for k, v := range baseParams { + obj[k] = v } - jsonStr, _ := json.MarshalIndent(obj, "", " ") + obj["add"], _ = addr["server"].(string) + port, _ := addr["server_port"].(float64) + obj["port"] = fmt.Sprintf("%.0f", port) + obj["ps"], _ = addr["remark"].(string) + if typ != "" { + obj["type"] = typ + } + if host != "" { + obj["host"] = host + } + if path != "" { + obj["path"] = path + } + populateVmessTlsParams(obj, addr["tls"]) + + jsonStr, _ := json.Marshal(obj) uri := fmt.Sprintf("vmess://%s", toBase64(jsonStr)) links = append(links, uri) @@ -468,19 +485,43 @@ func vmessLink( return links } -func toBase64(d []byte) string { - return base64.StdEncoding.EncodeToString([]byte(d)) +func populateVmessTlsParams(obj map[string]interface{}, tlsConfig interface{}) { + if tlsMap, ok := tlsConfig.(map[string]interface{}); ok && tlsMap["enabled"].(bool) { + obj["tls"] = "tls" + var tlsParams []LinkParam + getTlsParams(&tlsParams, tlsMap, "allowInsecure") + for _, p := range tlsParams { + switch p.Key { + case "security": + // ignore, as "tls" is already set + case "allowInsecure": + obj["allowInsecure"] = 1 + case "sni": + obj["sni"] = p.Value + case "fp": + obj["fp"] = p.Value + case "alpn": + obj["alpn"] = p.Value + } + } + } else { + obj["tls"] = "none" + } } -func addParams(uri string, params map[string]string, remark string) string { +func toBase64(d []byte) string { + return base64.StdEncoding.EncodeToString(d) +} + +func addParams(uri string, params []LinkParam, remark string) string { URL, _ := url.Parse(uri) var q []string - for k, v := range params { - switch k { + for _, p := range params { + switch p.Key { case "mport", "alpn": - q = append(q, fmt.Sprintf("%s=%s", k, v)) + q = append(q, fmt.Sprintf("%s=%s", p.Key, p.Value)) default: - q = append(q, fmt.Sprintf("%s=%s", k, url.QueryEscape(v))) + q = append(q, fmt.Sprintf("%s=%s", p.Key, url.QueryEscape(p.Value))) } } URL.RawQuery = strings.Join(q, "&") @@ -488,80 +529,87 @@ func addParams(uri string, params map[string]string, remark string) string { return URL.String() } -func getTransportParams(t interface{}) map[string]string { - params := map[string]string{} +func getTransportParams(t interface{}) []LinkParam { + var params []LinkParam trasport, _ := t.(map[string]interface{}) - if transportType, ok := trasport["type"].(string); ok { - params["type"] = transportType + var transportType string + if tt, ok := trasport["type"].(string); ok { + transportType = tt } else { - params["type"] = "tcp" + transportType = "tcp" + } + params = append(params, LinkParam{"type", transportType}) + if transportType == "tcp" { return params } - switch params["type"] { + + switch transportType { case "http": if host, ok := trasport["host"].([]interface{}); ok { var hosts []string for _, v := range host { hosts = append(hosts, v.(string)) } - params["host"] = strings.Join(hosts, ",") + params = append(params, LinkParam{"host", strings.Join(hosts, ",")}) } if path, ok := trasport["path"].(string); ok { - params["path"] = path + params = append(params, LinkParam{"path", path}) } case "ws": if path, ok := trasport["path"].(string); ok { - params["path"] = path + params = append(params, LinkParam{"path", path}) } if headers, ok := trasport["headers"].(map[string]interface{}); ok { if host, ok := headers["Host"].(string); ok { - params["host"] = host + params = append(params, LinkParam{"host", host}) } } case "grpc": if serviceName, ok := trasport["service_name"].(string); ok { - params["serviceName"] = serviceName + params = append(params, LinkParam{"serviceName", serviceName}) } case "httpupgrade": if host, ok := trasport["host"].(string); ok { - params["host"] = host + params = append(params, LinkParam{"host", host}) } if path, ok := trasport["path"].(string); ok { - params["path"] = path + params = append(params, LinkParam{"path", path}) } } return params } -func getTlsParams(params *map[string]string, tls map[string]interface{}, insecureKey string) { +func getTlsParams(params *[]LinkParam, tls map[string]interface{}, insecureKey string) { if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) { - (*params)["security"] = "reality" + *params = append(*params, LinkParam{"security", "reality"}) if pbk, ok := reality["public_key"].(string); ok { - (*params)["pbk"] = pbk + *params = append(*params, LinkParam{"pbk", pbk}) } if sid, ok := reality["short_id"].(string); ok { - (*params)["sid"] = sid + *params = append(*params, LinkParam{"sid", sid}) } } else { - (*params)["security"] = "tls" + *params = append(*params, LinkParam{"security", "tls"}) if insecure, ok := tls["insecure"].(bool); ok && insecure { - (*params)[insecureKey] = "1" + *params = append(*params, LinkParam{insecureKey, "1"}) } if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni { - (*params)["disable_sni"] = "1" + *params = append(*params, LinkParam{"disable_sni", "1"}) } } if utls, ok := tls["utls"].(map[string]interface{}); ok { - (*params)["fp"], _ = utls["fingerprint"].(string) + if fingerprint, ok := utls["fingerprint"].(string); ok { + *params = append(*params, LinkParam{"fp", fingerprint}) + } } if sni, ok := tls["server_name"].(string); ok { - (*params)["sni"] = sni + *params = append(*params, LinkParam{"sni", sni}) } if alpn, ok := tls["alpn"].([]interface{}); ok { alpnList := make([]string, len(alpn)) for i, v := range alpn { alpnList[i] = v.(string) } - (*params)["alpn"] = strings.Join(alpnList, ",") + *params = append(*params, LinkParam{"alpn", strings.Join(alpnList, ",")}) } }