github.com/laof/lite-speed-test@v0.0.0-20230930011949-1f39b7037845/config/shadowsocksr.go (about) 1 package config 2 3 import ( 4 "errors" 5 "net" 6 "net/url" 7 "regexp" 8 "strconv" 9 "strings" 10 11 "github.com/laof/lite-speed-test/outbound" 12 "github.com/laof/lite-speed-test/utils" 13 ) 14 15 var ( 16 NotSSRLink error = errors.New("not a shadowsocksR link") 17 ) 18 19 func SSRLinkToSSROption(link string) (*outbound.ShadowSocksROption, error) { 20 regex := regexp.MustCompile(`^ssr://([A-Za-z0-9+-=/_]+)`) 21 res := regex.FindAllStringSubmatch(link, 1) 22 b64 := "" 23 if len(res) > 0 && len(res[0]) > 1 { 24 b64 = res[0][1] 25 } 26 uri, err := utils.DecodeB64(b64) 27 if err != nil { 28 return nil, err 29 } 30 parts := strings.SplitN(uri, "/?", 2) 31 links := strings.Split(parts[0], ":") 32 if len(links) != 6 || len(parts) != 2 { 33 return nil, NotSSRLink 34 } 35 port, err := strconv.Atoi(links[1]) 36 if err != nil { 37 return nil, err 38 } 39 pass, err := utils.DecodeB64(links[5]) 40 if err != nil { 41 return nil, err 42 } 43 cipher := links[3] 44 if cipher == "none" { 45 cipher = "dummy" 46 } 47 ssrOption := &outbound.ShadowSocksROption{ 48 Name: "ssr", 49 Server: links[0], 50 Port: port, 51 Protocol: links[2], 52 Cipher: cipher, 53 Obfs: links[4], 54 Password: pass, 55 UDP: false, 56 Remarks: "", 57 } 58 query := strings.ReplaceAll(parts[1], "+", "%2B") 59 if rawQuery, err := url.ParseQuery(query); err == nil { 60 obfsparam, err := utils.DecodeB64(rawQuery.Get("obfsparam")) 61 if err != nil { 62 return nil, err 63 } 64 ssrOption.ObfsParam = obfsparam 65 if obfsparam == "" { 66 obfsparam, err := utils.DecodeB64(rawQuery.Get("obfs-param")) 67 if err != nil { 68 return nil, err 69 } 70 ssrOption.ObfsParam = obfsparam 71 } 72 protoparam, err := utils.DecodeB64(rawQuery.Get("protoparam")) 73 if err != nil { 74 return nil, err 75 } 76 ssrOption.ProtocolParam = protoparam 77 remarks, err := utils.DecodeB64(rawQuery.Get("remarks")) 78 if err == nil { 79 if remarks == "" { 80 remarks = net.JoinHostPort(ssrOption.Server, strconv.Itoa(ssrOption.Port)) 81 } 82 ssrOption.Remarks = remarks 83 ssrOption.Name = remarks 84 } 85 } 86 return ssrOption, nil 87 } 88 89 func init() { 90 outbound.RegisterDialerCreator("ssr", func(link string) (outbound.Dialer, error) { 91 ssOption, err := SSRLinkToSSROption(link) 92 if err != nil { 93 return nil, err 94 } 95 return outbound.NewShadowSocksR(ssOption) 96 }) 97 }