github.com/laof/lite-speed-test@v0.0.0-20230930011949-1f39b7037845/config/shadowsocks.go (about) 1 package config 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "net/url" 8 "regexp" 9 "strconv" 10 "strings" 11 12 "github.com/laof/lite-speed-test/outbound" 13 "github.com/laof/lite-speed-test/utils" 14 ) 15 16 var ( 17 NotSSLink error = errors.New("not a shadowsocksR link") 18 ) 19 20 func decodeB64SS(link string) (string, error) { 21 if strings.Contains(link, "@") { 22 return link, nil 23 } 24 regex := regexp.MustCompile(`^ss://([A-Za-z0-9+-=/_]+)`) 25 res := regex.FindAllStringSubmatch(link, 1) 26 b64 := "" 27 if len(res) > 0 && len(res[0]) > 1 { 28 b64 = res[0][1] 29 } 30 if b64 == "" { 31 return link, nil 32 } 33 uri, err := utils.DecodeB64(b64) 34 if err != nil { 35 return "", err 36 } 37 return fmt.Sprintf("ss://%s", uri), nil 38 } 39 40 func SSLinkToSSOption(link1 string) (*outbound.ShadowSocksOption, error) { 41 link, err := decodeB64SS(link1) 42 if err != nil { 43 return nil, err 44 } 45 u, err := url.Parse(link) 46 if err != nil { 47 return nil, err 48 } 49 if u.Scheme != "ss" { 50 return nil, errors.New("not a shadowsocks link") 51 } 52 pass := u.User.Username() 53 hostport := u.Host 54 host, port1, err := net.SplitHostPort(hostport) 55 if err != nil { 56 return nil, err 57 } 58 port, err := strconv.Atoi(port1) 59 if err != nil { 60 return nil, err 61 } 62 userinfo, err := utils.DecodeB64(pass) 63 if err != nil || !strings.Contains(userinfo, ":") { 64 pw, _ := u.User.Password() 65 if pw == "" { 66 if err == nil { 67 err = NotSSLink 68 } 69 return nil, err 70 } 71 userinfo = fmt.Sprintf("%s:%s", u.User.Username(), pw) 72 } 73 splits := strings.SplitN(userinfo, ":", 2) 74 method := splits[0] 75 pass = splits[1] 76 remarks := u.Fragment 77 if remarks == "" { 78 // fmt.Println(link1) 79 if splits := strings.Split(link1, "#"); len(splits) > 1 { 80 if rmk, err := url.QueryUnescape(splits[1]); err == nil { 81 remarks = rmk 82 } 83 } 84 } 85 86 shadwosocksOption := &outbound.ShadowSocksOption{ 87 Name: "ss", 88 Server: host, 89 Port: port, 90 Password: pass, 91 Cipher: method, 92 Remarks: remarks, 93 } 94 return shadwosocksOption, nil 95 } 96 97 func init() { 98 outbound.RegisterDialerCreator("ss", func(link string) (outbound.Dialer, error) { 99 ssOption, err := SSLinkToSSOption(link) 100 if err != nil { 101 return nil, err 102 } 103 return outbound.NewShadowSocks(ssOption) 104 }) 105 }