proxy.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package core
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "strings"
  11. "sync"
  12. "time"
  13. "github.com/Dreamacro/clash/adapter"
  14. C "github.com/Dreamacro/clash/constant"
  15. "github.com/cdle/sillyplus/core/storage"
  16. "github.com/cdle/sillyplus/utils"
  17. "github.com/google/uuid"
  18. )
  19. // type ProxyKey struct {
  20. // }
  21. type ProxyConfig struct {
  22. ID string `json:"id"`
  23. Type string `json:"type"`
  24. Server string `json:"server"`
  25. Port int `json:"port"`
  26. Name string `json:"name"`
  27. // ProxyKey
  28. // RuleMatcher *RuleMatcher `json:"-"`
  29. Conn C.Proxy `json:"-"`
  30. Rules []string `json:"rules"`
  31. Plugins []string `json:"plugins"`
  32. // Cipher string `json:"cipher,omitempty"`
  33. // Username string `json:"username,omitempty"`
  34. // Password string `json:"password,omitempty"`
  35. // SkipCertVerify bool `json:"skip-cert-verify,omitempty"`
  36. // TLS bool `json:"tls,omitempty"`
  37. // CreatedAt int `json:"created_at,omitempty"`
  38. // Remark string `json:"remark,omitempty"`
  39. Enable bool `json:"enable,omitempty"`
  40. // UDP bool `json:"udp,omitempty"`
  41. // Plugin string `json:"plugin,omitempty"`
  42. // PluginOpts map[string]string `json:"plugin-opts,omitempty"`
  43. // Obfs string `json:"obfs,omitempty"`
  44. // ObfsOpts map[string]string `json:"obfs-opts,omitempty"`
  45. // Enable bool `json:"enable,omitempty"`
  46. // ExcludeIPs []string `json:"exclude-ip,omitempty"`
  47. // ProxyGroups []string `json:"proxy-groups,omitempty"`
  48. Google []int `json:"google"`
  49. }
  50. var Proxies sync.Map
  51. var proxies = MakeBucket("proxies")
  52. func GetProxyTransport(rawURL string, uuid string, params map[string]interface{}) (C.Conn, error) {
  53. u, err := url.Parse(rawURL)
  54. if err != nil {
  55. return nil, err
  56. }
  57. port := u.Port()
  58. if port == "" {
  59. switch u.Scheme {
  60. case "https":
  61. port = "443"
  62. case "http":
  63. port = "80"
  64. default:
  65. err = fmt.Errorf("%s scheme not Support", rawURL)
  66. return nil, err
  67. }
  68. }
  69. addr := C.Metadata{
  70. Host: u.Hostname(),
  71. DstIP: nil,
  72. DstPort: port,
  73. }
  74. var p *ProxyConfig
  75. if params != nil {
  76. params["port"] = utils.Int(params["port"])
  77. conn, err := adapter.ParseProxy(params)
  78. if err != nil {
  79. err = fmt.Errorf("代理配置错误:%v", err)
  80. return nil, err
  81. }
  82. i, err := conn.DialContext(context.Background(), &addr)
  83. if err != nil {
  84. err = fmt.Errorf("代理连接错误:%v", err)
  85. }
  86. return i, err
  87. }
  88. var plugins = []*ProxyConfig{}
  89. Proxies.Range(func(key, value any) bool {
  90. cfg := value.(*ProxyConfig)
  91. if !cfg.Enable {
  92. return true
  93. }
  94. if Contains(cfg.Rules, addr.Host) {
  95. p = cfg
  96. return false
  97. }
  98. if Contains(cfg.Plugins, uuid) {
  99. plugins = append(plugins, cfg)
  100. }
  101. return true
  102. })
  103. if p != nil {
  104. i, err := p.Conn.DialContext(context.Background(), &addr)
  105. if err != nil {
  106. err = fmt.Errorf("%s(%s)代理错误:%v", p.Type, p.Name, err)
  107. }
  108. return i, err
  109. }
  110. if len(plugins) != 0 {
  111. p = plugins[0]
  112. i, err := p.Conn.DialContext(context.Background(), &addr)
  113. if err != nil {
  114. err = fmt.Errorf("%s(%s)代理错误:%v", p.Type, p.Name, err)
  115. }
  116. return i, err
  117. }
  118. return nil, nil
  119. }
  120. func init() {
  121. proxies.Foreach(func(b1, b2 []byte) error {
  122. key := string(b1)
  123. new := string(b2)
  124. var ncfg = ProxyConfig{}
  125. var params = map[string]interface{}{}
  126. if strings.HasPrefix(new, "o:") {
  127. var data = []byte(strings.Replace(new, "o:", "", 1))
  128. err := json.Unmarshal(data, &ncfg)
  129. json.Unmarshal(data, &params)
  130. if err != nil {
  131. console.Log("无法解析的代理数据:", err)
  132. return nil
  133. }
  134. p, err := adapter.ParseProxy(params)
  135. if err != nil {
  136. console.Log("无法解析的代理:", err)
  137. return nil
  138. }
  139. ncfg.Conn = p
  140. // fmt.Println("===", string(utils.JsonMarshal(ncfg)))
  141. // fmt.Println(ncfg.RuleMatcher.Match("106.52.87.206"))
  142. // fmt.Println(ncfg.RuleMatcher.Match("api.telegram.org"))
  143. Proxies.Store(key, &ncfg)
  144. }
  145. return nil
  146. })
  147. go checkProxy()
  148. storage.Watch(proxies, "*", func(old, new, key string) *storage.Final {
  149. _, err := uuid.Parse(key)
  150. if err != nil {
  151. return &storage.Final{
  152. Error: errors.New("非法的UUID"),
  153. }
  154. }
  155. // var ocfg = ProxyConfig{}
  156. // if strings.HasPrefix(new, "o:") {
  157. // json.Unmarshal([]byte(strings.Replace(old, "o:", "", 1)), &ocfg)
  158. // }
  159. // var okey = ProxyKey{
  160. // Type: ocfg.Type,
  161. // Server: ocfg.Server,
  162. // Port: ocfg.Port,
  163. // }
  164. // var nkey = ProxyKey{}
  165. var ncfg = ProxyConfig{}
  166. var params = map[string]interface{}{}
  167. if new == "" { //删除逻辑
  168. Proxies.Delete(key)
  169. return nil
  170. }
  171. if strings.HasPrefix(new, "o:") {
  172. var data = []byte(strings.Replace(new, "o:", "", 1))
  173. err := json.Unmarshal(data, &ncfg)
  174. json.Unmarshal(data, &params)
  175. if err != nil {
  176. return &storage.Final{
  177. Error: err,
  178. }
  179. }
  180. // nkey = ProxyKey{
  181. // Type: ncfg.Type,
  182. // Server: ncfg.Server,
  183. // Port: ncfg.Port,
  184. // }
  185. }
  186. // if ncfg.CreatedAt == 0 {
  187. // ncfg.CreatedAt = int(time.Now().Unix())
  188. // new = "o:" + string(utils.JsonMarshal(ncfg))
  189. // }
  190. // ov, ok := Proxies.Load(nkey)
  191. // if ok && (!IsDifferent(ocfg, ncfg, []string{"Name", "UUID", "Rules", "Plugins"}) || checkProxy(ov.(C.Proxy))) { //代理依旧有效
  192. // return nil
  193. // }
  194. // ncfg.RuleMatcher, err = preprocessRules(ncfg.Rules)
  195. if err != nil {
  196. return &storage.Final{
  197. Error: errors.New("不支持的代理匹配规则:" + err.Error()),
  198. }
  199. }
  200. p, err := adapter.ParseProxy(params)
  201. if err != nil {
  202. return &storage.Final{
  203. Error: err,
  204. }
  205. }
  206. ncfg.Conn = p
  207. Proxies.Store(key, &ncfg)
  208. go checkProxy()
  209. return &storage.Final{
  210. Now: new,
  211. }
  212. })
  213. }
  214. func checkProxy() {
  215. proxies.Foreach(func(b1, b2 []byte) error {
  216. go func(b1, b2 []byte) {
  217. key := string(b1)
  218. new := string(b2)
  219. var ncfg = ProxyConfig{}
  220. var params = map[string]interface{}{}
  221. if strings.HasPrefix(new, "o:") {
  222. var data = []byte(strings.Replace(new, "o:", "", 1))
  223. err := json.Unmarshal(data, &ncfg)
  224. json.Unmarshal(data, &params)
  225. if err != nil {
  226. return
  227. }
  228. var check = map[string]int64{}
  229. for _, site := range []string{"https://google.com", "https://github.com"} {
  230. func(site string) {
  231. instance, err := GetProxyTransport(site, "", params)
  232. if err != nil {
  233. return
  234. }
  235. defer instance.Close()
  236. var client = &http.Client{
  237. Transport: &http.Transport{
  238. Dial: func(string, string) (net.Conn, error) {
  239. return instance, nil
  240. },
  241. MaxIdleConns: 100,
  242. IdleConnTimeout: 90 * time.Second,
  243. TLSHandshakeTimeout: 10 * time.Second,
  244. ExpectContinueTimeout: 1 * time.Second,
  245. },
  246. }
  247. req, err := http.NewRequest("GET", site, strings.NewReader(""))
  248. if err != nil {
  249. return
  250. }
  251. startTime := time.Now().UnixMilli()
  252. resp, err := client.Do(req)
  253. if err != nil {
  254. return
  255. }
  256. endTime := time.Now().UnixMilli()
  257. resp.Body.Close()
  258. spend := endTime - startTime
  259. check[site] = spend
  260. // console.Log(site, "resp.StatusCode", resp.StatusCode, "time", spend)
  261. }(site)
  262. }
  263. params["check"] = check
  264. proxies.Set2(key, "o:"+string(utils.JsonMarshal(params)))
  265. }
  266. }(b1, b2)
  267. return nil
  268. })
  269. }