shadowsocksr.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package proxy
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "math/rand"
  7. "net"
  8. "net/url"
  9. "regexp"
  10. "strconv"
  11. "strings"
  12. "github.com/zu1k/proxypool/pkg/tool"
  13. )
  14. var (
  15. ErrorNotSSRLink = errors.New("not a correct ssr link")
  16. ErrorPasswordParseFail = errors.New("password parse failed")
  17. ErrorPathNotComplete = errors.New("path not complete")
  18. ErrorMissingQuery = errors.New("link missing query")
  19. ErrorProtocolParamParseFail = errors.New("protocol param parse failed")
  20. ErrorObfsParamParseFail = errors.New("obfs param parse failed")
  21. )
  22. type ShadowsocksR struct {
  23. Base
  24. Password string `yaml:"password" json:"password"`
  25. Cipher string `yaml:"cipher" json:"cipher"`
  26. Protocol string `yaml:"protocol" json:"protocol"`
  27. ProtocolParam string `yaml:"protocol-param,omitempty" json:"protocol_param,omitempty"`
  28. Obfs string `yaml:"obfs" json:"obfs"`
  29. ObfsParam string `yaml:"obfs-param,omitempty" json:"obfs_param,omitempty"`
  30. Group string `yaml:"group,omitempty" json:"group,omitempty"`
  31. }
  32. func (ssr ShadowsocksR) Identifier() string {
  33. return net.JoinHostPort(ssr.Server, strconv.Itoa(ssr.Port)) + ssr.Password + ssr.ProtocolParam
  34. }
  35. func (ssr ShadowsocksR) String() string {
  36. data, err := json.Marshal(ssr)
  37. if err != nil {
  38. return ""
  39. }
  40. return string(data)
  41. }
  42. func (ssr ShadowsocksR) ToClash() string {
  43. data, err := json.Marshal(ssr)
  44. if err != nil {
  45. return ""
  46. }
  47. return "- " + string(data)
  48. }
  49. func (ssr ShadowsocksR) ToSurge() string {
  50. return ""
  51. }
  52. func (ssr ShadowsocksR) Clone() Proxy {
  53. return &ssr
  54. }
  55. func (ssr ShadowsocksR) Link() (link string) {
  56. payload := fmt.Sprintf("%s:%d:%s:%s:%s:%s",
  57. ssr.Server, ssr.Port, ssr.Protocol, ssr.Cipher, ssr.Obfs, tool.Base64EncodeString(ssr.Password))
  58. query := url.Values{}
  59. query.Add("obfsparam", tool.Base64EncodeString(ssr.ObfsParam))
  60. query.Add("protoparam", tool.Base64EncodeString(ssr.ProtocolParam))
  61. query.Add("remarks", tool.Base64EncodeString(ssr.Name))
  62. query.Add("group", tool.Base64EncodeString("proxy.tgbot.co"))
  63. payload = tool.Base64EncodeString(fmt.Sprintf("%s/?%s", payload, query.Encode()))
  64. return fmt.Sprintf("ssr://%s", payload)
  65. }
  66. func ParseSSRLink(link string) (*ShadowsocksR, error) {
  67. if !strings.HasPrefix(link, "ssr") {
  68. return nil, ErrorNotSSRLink
  69. }
  70. ssrmix := strings.SplitN(link, "://", 2)
  71. if len(ssrmix) < 2 {
  72. return nil, ErrorNotSSRLink
  73. }
  74. linkPayloadBase64 := ssrmix[1]
  75. payload, err := tool.Base64DecodeString(linkPayloadBase64)
  76. if err != nil {
  77. return nil, ErrorMissingQuery
  78. }
  79. infoPayload := strings.SplitN(payload, "/?", 2)
  80. if len(infoPayload) < 2 {
  81. return nil, ErrorNotSSRLink
  82. }
  83. ssrpath := strings.Split(infoPayload[0], ":")
  84. if len(ssrpath) < 6 {
  85. return nil, ErrorPathNotComplete
  86. }
  87. // base info
  88. server := strings.ToLower(ssrpath[0])
  89. port, _ := strconv.Atoi(ssrpath[1])
  90. protocol := strings.ToLower(ssrpath[2])
  91. cipher := strings.ToLower(ssrpath[3])
  92. obfs := strings.ToLower(ssrpath[4])
  93. password, err := tool.Base64DecodeString(ssrpath[5])
  94. if err != nil {
  95. return nil, ErrorPasswordParseFail
  96. }
  97. moreInfo, _ := url.ParseQuery(infoPayload[1])
  98. // remarks
  99. remarks := moreInfo.Get("remarks")
  100. remarks, err = tool.Base64DecodeString(remarks)
  101. if err != nil {
  102. remarks = ""
  103. err = nil
  104. }
  105. if strings.ContainsAny(remarks, "\t\r\n ") {
  106. remarks = strings.ReplaceAll(remarks, "\t", "")
  107. remarks = strings.ReplaceAll(remarks, "\r", "")
  108. remarks = strings.ReplaceAll(remarks, "\n", "")
  109. remarks = strings.ReplaceAll(remarks, " ", "")
  110. }
  111. // protocol param
  112. protocolParam, err := tool.Base64DecodeString(moreInfo.Get("protoparam"))
  113. if err != nil {
  114. return nil, ErrorProtocolParamParseFail
  115. }
  116. if tool.ContainChineseChar(protocolParam) {
  117. protocolParam = ""
  118. }
  119. if strings.HasSuffix(protocol, "_compatible") {
  120. protocol = strings.ReplaceAll(protocol, "_compatible", "")
  121. }
  122. // obfs param
  123. obfsParam, err := tool.Base64DecodeString(moreInfo.Get("obfsparam"))
  124. if err != nil {
  125. return nil, ErrorObfsParamParseFail
  126. }
  127. if tool.ContainChineseChar(obfsParam) {
  128. obfsParam = ""
  129. }
  130. if strings.HasSuffix(obfs, "_compatible") {
  131. obfs = strings.ReplaceAll(obfs, "_compatible", "")
  132. }
  133. //group, err := tool.Base64DecodeString(moreInfo.Get("group"))
  134. //if err != nil {
  135. // group = ""
  136. //}
  137. group := ""
  138. return &ShadowsocksR{
  139. Base: Base{
  140. Name: remarks + "_" + strconv.Itoa(rand.Int()),
  141. Server: server,
  142. Port: port,
  143. Type: "ssr",
  144. },
  145. Password: password,
  146. Cipher: cipher,
  147. Protocol: protocol,
  148. ProtocolParam: protocolParam,
  149. Obfs: obfs,
  150. ObfsParam: obfsParam,
  151. Group: group,
  152. }, nil
  153. }
  154. var (
  155. ssrPlainRe = regexp.MustCompile("ssr://([A-Za-z0-9+/_-])+")
  156. )
  157. func GrepSSRLinkFromString(text string) []string {
  158. results := make([]string, 0)
  159. texts := strings.Split(text, "ssr://")
  160. for _, text := range texts {
  161. results = append(results, ssrPlainRe.FindAllString("ssr://"+text, -1)...)
  162. }
  163. return results
  164. }