diff --git a/go.mod b/go.mod index 53dd58f..4f8b0c9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/hiddify/ray2sing -go 1.21.1 +go 1.21.4 + +toolchain go1.22.3 require ( github.com/sagernet/sing v0.4.1 @@ -11,15 +13,15 @@ require ( require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/miekg/dns v1.1.59 // indirect + github.com/miekg/dns v1.1.61 // indirect github.com/sagernet/sing-dns v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/tools v0.22.0 // indirect ) -replace github.com/sagernet/sing-box => github.com/hiddify/hiddify-sing-box v1.8.9-0.20240717205631-60d55deb81f9 +replace github.com/sagernet/sing-box => github.com/hiddify/hiddify-sing-box v1.8.9-0.20240724225257-adf55aaf0721 diff --git a/go.sum b/go.sum index 353dd30..3f7e1a5 100644 --- a/go.sum +++ b/go.sum @@ -2,19 +2,20 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/hiddify/hiddify-sing-box v1.8.9-0.20240717205631-60d55deb81f9 h1:01JjBBilkGSza9eEVRN6XK7JDABbeDWgbYQN+/6j+tc= -github.com/hiddify/hiddify-sing-box v1.8.9-0.20240717205631-60d55deb81f9/go.mod h1:AlbX8EFeSVKjitRnpX2Zv6oD3IGhOFXiPq+4P71Io54= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/hiddify/hiddify-sing-box v1.8.9-0.20240724225257-adf55aaf0721 h1:yt0l4Hhjto9o3k/rWNEQRGEh4bZEDgEDBvyUpA/2wSY= +github.com/hiddify/hiddify-sing-box v1.8.9-0.20240724225257-adf55aaf0721/go.mod h1:6+sp+GwVbdHDne/axYdOYBBZL1aXqVty27KqhQM175U= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= @@ -36,22 +37,22 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= +golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 3dc6396..65d0d30 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ var examples = map[string][]string{ }, "vless": { "vless://25da296e-1d96-48ae-9867-4342796cd742@172.67.149.95:443?encryption=none&fp=chrome&host=vless.229feb8b52a0e7e117ea76f8b591bcb3.workers.dev&path=%2F%3Fed%3D2048&security=tls&sni=vless.229feb8b52a0e7e117ea76f8b591bcb3.workers.dev&type=ws#رایگان | VLESS | @Helix_Servers | US🇺🇸 | 0️⃣1️⃣", + "vless://25da296e-1d96-48ae-9867-4342796cd742@172.67.149.95:443?encryption=none&fp=chrome&host=vless.229feb8b52a0e7e117ea76f8b591bcb3.workers.dev&path=%2F%3Fed%3D2048&security=tls&sni=vless.229feb8b52a0e7e117ea76f8b591bcb3.workers.dev&type=ws&core=xray#رایگان | VLESS | @Helix_Servers | US🇺🇸 | 0️⃣1️⃣", }, "vmess": { "vmess://eyJhZGQiOiI1MS4xNjEuMTMwLjE3MyIsImFpZCI6IjAiLCJhbHBuIjoiIiwiZnAiOiIiLCJob3N0IjoiIiwiaWQiOiJkNDNlZTVlMy0xYjA3LTU2ZDctYjJlYS04ZDIyYzQ0ZmRjNjYiLCJuZXQiOiJ0Y3AiLCJwYXRoIjoiIiwicG9ydCI6IjgwODAiLCJzY3kiOiJjaGFjaGEyMC1wb2x5MTMwNSIsInNuaSI6IiIsInRscyI6IiIsInR5cGUiOiJub25lIiwidiI6IjIiLCJwcyI6Ilx1MDYzMVx1MDYyN1x1MDZjY1x1MDZhZlx1MDYyN1x1MDY0NiB8IFZNRVNTIHwgQFdhdGFzaGlfVlBOIHwgQVVcdWQ4M2NcdWRkZTZcdWQ4M2NcdWRkZmEgfCAwXHVmZTBmXHUyMGUzMVx1ZmUwZlx1MjBlMyJ9", diff --git a/ray2sing/convert.go b/ray2sing/convert.go index 6b22041..e5d36b0 100644 --- a/ray2sing/convert.go +++ b/ray2sing/convert.go @@ -35,6 +35,12 @@ var configTypes = map[string]ParserFunc{ "http://": HttpSingbox, "https://": HttpsSingbox, } +var xrayConfigTypes = map[string]ParserFunc{ + "vmess://": VmessXray, + "vless://": VlessXray, + "trojan://": TrojanXray, + "direct://": DirectXray, +} func processSingleConfig(config string) (outbound *T.Outbound, err error) { defer func() { @@ -47,9 +53,17 @@ func processSingleConfig(config string) (outbound *T.Outbound, err error) { }() var configSingbox *T.Outbound - for k, v := range configTypes { - if strings.HasPrefix(config, k) { - configSingbox, err = v(config) + if strings.Contains(config, "&core=xray") { + for k, v := range xrayConfigTypes { + if strings.HasPrefix(config, k) { + configSingbox, err = v(config) + } + } + } else { + for k, v := range configTypes { + if strings.HasPrefix(config, k) { + configSingbox, err = v(config) + } } } diff --git a/ray2sing/xraycommon.go b/ray2sing/xraycommon.go new file mode 100644 index 0000000..a2f594c --- /dev/null +++ b/ray2sing/xraycommon.go @@ -0,0 +1,204 @@ +package ray2sing + +import ( + E "github.com/sagernet/sing/common/exceptions" + + "strings" +) + +func getTLSOptionsXray(decoded map[string]string) map[string]any { + if !(decoded["tls"] == "tls" || decoded["security"] == "tls") { + return nil + } + serverName := decoded["sni"] + if serverName == "" { + serverName = decoded["add"] + } + alpn := []string{"h2", "http/1.1"} + if alpnlink, ok := decoded["alpn"]; ok && alpnlink != "" { + alpn = strings.Split(alpnlink, ",") + } + + fp := decoded["fp"] + if fp == "" { + // fp = "chrome" + } + + return map[string]any{ + "serverName": serverName, + "rejectUnknownSni": false, + "allowInsecure": decoded["insecure"] == "true", + "alpn": alpn, + // "minVersion": "1.2", + // "maxVersion": "1.3", + // "disableSystemRoot": false, + // "enableSessionResumption": true, + "fingerprint": fp, + } +} +func getRealityOptionsXray(decoded map[string]string) map[string]any { + if !(decoded["security"] == "reality") { + return nil + } + serverName := decoded["sni"] + if serverName == "" { + serverName = decoded["add"] + } + // alpn := []string{"h2", "http/1.1"} + // if alpnlink, ok := decoded["alpn"]; ok && alpnlink != "" { + // alpn = strings.Split(alpnlink, ",") + // } + + fp := decoded["fp"] + if fp == "" { + // fp = "chrome" + } + + return map[string]any{ + "serverName": serverName, + "fingerprint": fp, + "shortId": decoded["sid"], + "spiderX": decoded["spx"], + "publicKey": decoded["pbk"], + } +} + +func getMuxOptionsXray(decoded map[string]string) map[string]any { + if decoded["mux"] == "" { + return nil + } + return map[string]any{ + "enabled": true, + "concurrency": toInt(decoded["mux"]), + // "xudpConcurrency": 16, + // "xudpProxyUDP443": "reject" + } +} +func getsplithttp(decoded map[string]string) map[string]any { + path := decoded["path"] + if path == "" { + path = "/" + } + + return map[string]any{ + "path": path, + "host": decoded["host"], + "headers": map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + }, + // "maxUploadSize": 1000000, + // "maxConcurrentUploads": 10 + } +} +func gethttpupgrade(decoded map[string]string) map[string]any { + path := decoded["path"] + if path == "" { + path = "/" + } + + return map[string]any{ + "path": path, + "host": decoded["host"], + "headers": map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + }, + } +} +func getwebsocket(decoded map[string]string) map[string]any { + path := decoded["path"] + if path == "" { + path = "/" + } + + return map[string]any{ + "path": path, + "host": decoded["host"], + "headers": map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + }, + } +} + +func geth2(decoded map[string]string) map[string]any { + path := decoded["path"] + if path == "" { + path = "/" + } + + return map[string]any{ + "path": path, + "host": strings.Split(decoded["host"], ","), + "headers": map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + }, + } +} + +func getquic(decoded map[string]string) map[string]any { + + return map[string]any{ + "security": decoded["quicSecurity"], + "key": decoded["key"], + "header": map[string]string{ + "type": decoded["headertype"], + }, + } +} + +func getgrpc(decoded map[string]string) map[string]any { + + return map[string]any{ + "authority": decoded["authority"], + "serviceName": decoded["servicename"], + "mode": decoded["mode"], + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + } +} + +func getStreamSettingsXray(decoded map[string]string) (map[string]any, error) { + + net, path := decoded["net"], decoded["path"] + if net == "" { + net = decoded["type"] + } + if path == "" { + path = decoded["servicename"] + } + // fmoption.Printf("\n\nheaderType:%s, net:%s, type:%s\n\n", decoded["headerType"], net, decoded["type"]) + // if (decoded["type"] == "http" || decoded["headertype"] == "http") && net == "tcp" { + // net = "http" + // } + res := map[string]any{} + tls := getTLSOptionsXray(decoded) + if tls != nil { + res["security"] = "tls" + res["tlsSettings"] = tls + } + reality := getRealityOptionsXray(decoded) + if reality != nil { + res["security"] = "reality" + res["realitySettings"] = reality + } + res["network"] = net + switch net { + case "tcp": + res[net+"Settings"] = map[string]any{} + + case "httpupgrade": + res[net+"Settings"] = gethttpupgrade(decoded) + case "ws": + res[net+"Settings"] = getwebsocket(decoded) + case "grpc": + res[net+"Settings"] = getgrpc(decoded) + case "quic": + res[net+"Settings"] = getquic(decoded) + case "splithttp": + res[net+"Settings"] = getsplithttp(decoded) + case "h2": + res[net+"Settings"] = geth2(decoded) + default: + return nil, E.New("unknown transport type: " + net) + } + + return res, nil +} diff --git a/ray2sing/xraydirect.go b/ray2sing/xraydirect.go new file mode 100644 index 0000000..5f5e88c --- /dev/null +++ b/ray2sing/xraydirect.go @@ -0,0 +1,43 @@ +package ray2sing + +import ( + "strings" + + T "github.com/sagernet/sing-box/option" +) + +func DirectXray(vlessURL string) (*T.Outbound, error) { + u, err := ParseUrl(vlessURL, 443) + if err != nil { + return nil, err + } + decoded := u.Params + // packetEncoding := decoded["packetencoding"] + // if packetEncoding==""{ + // packetEncoding="xudp" + // } + frag, err := getOneOf(decoded, "frg", "fragment") + fragdata := map[string]any{} + if err != nil && frag != "" { + frags := strings.Split(frag, ",") + fragdata = map[string]any{ + "packets": frags[0], + "length": frags[1], + "interval": frags[2], + } + } + return &T.Outbound{ + Tag: u.Name, + Type: "xray", + XrayOptions: T.XrayOutboundOptions{ + // DialerOptions: getDialerOptions(decoded), + XrayOutboundJson: map[string]any{ + "protocol": "freedom", + "settings": map[string]any{ + "fragment": fragdata, + }, + "tag": u.Name, + }, + }, + }, nil +} diff --git a/ray2sing/xraytrojan.go b/ray2sing/xraytrojan.go new file mode 100644 index 0000000..304bd95 --- /dev/null +++ b/ray2sing/xraytrojan.go @@ -0,0 +1,46 @@ +package ray2sing + +import ( + T "github.com/sagernet/sing-box/option" +) + +func TrojanXray(vlessURL string) (*T.Outbound, error) { + u, err := ParseUrl(vlessURL, 443) + if err != nil { + return nil, err + } + decoded := u.Params + // fmt.Printf("Port %v deco=%v", port, decoded) + streamSettings, err := getStreamSettingsXray(decoded) + if err != nil { + return nil, err + } + + // packetEncoding := decoded["packetencoding"] + // if packetEncoding==""{ + // packetEncoding="xudp" + // } + + return &T.Outbound{ + Tag: u.Name, + Type: "xray", + XrayOptions: T.XrayOutboundOptions{ + // DialerOptions: getDialerOptions(decoded), + XrayOutboundJson: map[string]any{ + "protocol": "trojan", + "settings": map[string]any{ + "vnext": []any{ + map[string]any{ + "address": decoded["host"], + "port": decoded["port"], + "password": u.Username, + }, + }, + }, + "tag": u.Name, + "streamSettings": streamSettings, + "mux": getMuxOptionsXray(decoded), + }, + }, + }, nil +} diff --git a/ray2sing/xrayvless.go b/ray2sing/xrayvless.go new file mode 100644 index 0000000..f2b78af --- /dev/null +++ b/ray2sing/xrayvless.go @@ -0,0 +1,52 @@ +package ray2sing + +import ( + T "github.com/sagernet/sing-box/option" +) + +func VlessXray(vlessURL string) (*T.Outbound, error) { + u, err := ParseUrl(vlessURL, 443) + if err != nil { + return nil, err + } + decoded := u.Params + // fmt.Printf("Port %v deco=%v", port, decoded) + streamSettings, err := getStreamSettingsXray(decoded) + if err != nil { + return nil, err + } + + // packetEncoding := decoded["packetencoding"] + // if packetEncoding==""{ + // packetEncoding="xudp" + // } + + return &T.Outbound{ + Tag: u.Name, + Type: "xray", + XrayOptions: T.XrayOutboundOptions{ + // DialerOptions: getDialerOptions(decoded), + XrayOutboundJson: map[string]any{ + + "protocol": "vless", + "settings": map[string]any{ + "vnext": []any{ + map[string]any{ + "address": decoded["host"], + "port": decoded["port"], + "users": []any{ + map[string]string{ + "id": u.Username, // Change to your UUID. + "encryption": "none", + }, + }, + }, + }, + }, + "tag": u.Name, + "streamSettings": streamSettings, + "mux": getMuxOptionsXray(decoded), + }, + }, + }, nil +} diff --git a/ray2sing/xrayvmess.go b/ray2sing/xrayvmess.go new file mode 100644 index 0000000..9d78b1f --- /dev/null +++ b/ray2sing/xrayvmess.go @@ -0,0 +1,52 @@ +package ray2sing + +import ( + T "github.com/sagernet/sing-box/option" +) + +func VmessXray(vlessURL string) (*T.Outbound, error) { + u, err := ParseUrl(vlessURL, 443) + if err != nil { + return nil, err + } + decoded := u.Params + // fmt.Printf("Port %v deco=%v", port, decoded) + streamSettings, err := getStreamSettingsXray(decoded) + if err != nil { + return nil, err + } + + // packetEncoding := decoded["packetencoding"] + // if packetEncoding==""{ + // packetEncoding="xudp" + // } + + return &T.Outbound{ + Tag: u.Name, + Type: "xray", + XrayOptions: T.XrayOutboundOptions{ + // DialerOptions: getDialerOptions(decoded), + XrayOutboundJson: map[string]any{ + + "protocol": "vmess", + "settings": map[string]any{ + "vnext": []any{ + map[string]any{ + "address": decoded["host"], + "port": decoded["port"], + "users": []any{ + map[string]any{ + "id": u.Username, // Change to your UUID. + "security": decoded["encryption"], + }, + }, + }, + }, + }, + "tag": u.Name, + "streamSettings": streamSettings, + "mux": getMuxOptionsXray(decoded), + }, + }, + }, nil +}