add shadowsocks and subscribe support
This commit is contained in:
@@ -36,6 +36,11 @@ func CrawlTGChannel() {
|
||||
proxies = append(proxies, getter.NewWebFuzz("https://www.freefq.com/d/file/free-ssr/20200811/1f3e9d0d0064f662457062712dcf1b66.txt").Get()...)
|
||||
proxies = append(proxies, getter.NewWebFuzz("https://merlinblog.xyz/wiki/freess.html").Get()...)
|
||||
|
||||
// 订阅链接
|
||||
proxies = append(proxies, getter.NewSubscribe("https://raw.githubusercontent.com/ssrsub/ssr/master/v2ray").Get()...)
|
||||
proxies = append(proxies, getter.NewSubscribe("https://raw.githubusercontent.com/ssrsub/ssr/master/ssrsub").Get()...)
|
||||
proxies = append(proxies, getter.NewSubscribe("https://raw.githubusercontent.com/ssrsub/ssr/master/ss-sub").Get()...)
|
||||
|
||||
proxies = append(proxies, cache.GetProxies()...)
|
||||
proxies = proxy.Deduplication(proxies)
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ func String2Proxy(link string) proxy.Proxy {
|
||||
data, err = proxy.ParseSSRLink(link)
|
||||
} else if strings.HasPrefix(link, "vmess://") {
|
||||
data, err = proxy.ParseVmessLink(link)
|
||||
} else if strings.HasPrefix(link, "ss://") {
|
||||
data, err = proxy.ParseSSLink(link)
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -25,19 +27,20 @@ func String2Proxy(link string) proxy.Proxy {
|
||||
}
|
||||
|
||||
func StringArray2ProxyArray(origin []string) []proxy.Proxy {
|
||||
var err error
|
||||
results := make([]proxy.Proxy, 0)
|
||||
for _, link := range origin {
|
||||
var data proxy.Proxy
|
||||
if strings.HasPrefix(link, "ssr://") {
|
||||
data, err = proxy.ParseSSRLink(link)
|
||||
} else if strings.HasPrefix(link, "vmess://") {
|
||||
data, err = proxy.ParseVmessLink(link)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
results = append(results, data)
|
||||
results = append(results, String2Proxy(link))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func GrepLinksFromString(text string) []string {
|
||||
results := proxy.GrepSSRLinkFromString(text)
|
||||
results = append(results, proxy.GrepVmessLinkFromString(text)...)
|
||||
results = append(results, proxy.GrepSSLinkFromString(text)...)
|
||||
return results
|
||||
}
|
||||
|
||||
func FuzzParseProxyFromString(text string) []proxy.Proxy {
|
||||
return StringArray2ProxyArray(GrepLinksFromString(text))
|
||||
}
|
||||
|
||||
@@ -1,13 +1,41 @@
|
||||
package getter
|
||||
|
||||
import "github.com/zu1k/proxypool/proxy"
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/proxy"
|
||||
"github.com/zu1k/proxypool/tool"
|
||||
)
|
||||
|
||||
type Subscribe struct {
|
||||
NumNeeded int
|
||||
Results []string
|
||||
Url string
|
||||
Url string
|
||||
}
|
||||
|
||||
func (s Subscribe) Get() []proxy.Proxy {
|
||||
return nil
|
||||
resp, err := http.Get(s.Url)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodesString, err := tool.Base64DecodeString(string(body))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
nodesString = strings.ReplaceAll(nodesString, "\t", "")
|
||||
|
||||
nodes := strings.Split(nodesString, "\n")
|
||||
return StringArray2ProxyArray(nodes)
|
||||
}
|
||||
|
||||
func NewSubscribe(url string) *Subscribe {
|
||||
return &Subscribe{
|
||||
Url: url,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@ func NewTGChannelGetter(url string, numNeeded int) *TGChannelGetter {
|
||||
func (g TGChannelGetter) Get() []proxy.Proxy {
|
||||
// 找到所有的文字消息
|
||||
g.c.OnHTML("div.tgme_widget_message_text", func(e *colly.HTMLElement) {
|
||||
g.Results = append(g.Results, proxy.GrepSSRLinkFromString(e.Text)...)
|
||||
g.Results = append(g.Results, proxy.GrepVmessLinkFromString(e.Text)...)
|
||||
g.Results = append(g.Results, GrepLinksFromString(e.Text)...)
|
||||
})
|
||||
|
||||
// 找到之前消息页面的链接,加入访问队列
|
||||
|
||||
@@ -21,12 +21,7 @@ func (w WebFuzz) Get() []proxy.Proxy {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
text := string(body)
|
||||
|
||||
results := proxy.GrepSSRLinkFromString(text)
|
||||
results = append(results, proxy.GrepVmessLinkFromString(text)...)
|
||||
|
||||
return StringArray2ProxyArray(results)
|
||||
return FuzzParseProxyFromString(string(body))
|
||||
}
|
||||
|
||||
func NewWebFuzz(url string) *WebFuzz {
|
||||
|
||||
@@ -16,3 +16,8 @@ func TestWebFreessrXyz_Get(t *testing.T) {
|
||||
func TestWebFuzz_Get(t *testing.T) {
|
||||
fmt.Println(NewWebFuzz("https://merlinblog.xyz/wiki/freess.html").Get())
|
||||
}
|
||||
|
||||
func TestSubscribe_Get(t *testing.T) {
|
||||
fmt.Println(NewSubscribe("https://raw.githubusercontent.com/ssrsub/ssr/master/v2ray").Get())
|
||||
fmt.Println(NewSubscribe("https://raw.githubusercontent.com/ssrsub/ssr/master/ssrsub").Get())
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ func checkClashSupport(p proxy.Proxy) bool {
|
||||
if checkInList(vmessCipherList, vmess.Cipher) {
|
||||
return true
|
||||
}
|
||||
case *proxy.Shadowsocks:
|
||||
ss := p.(*proxy.Shadowsocks)
|
||||
if checkInList(ssCipherList, ss.Cipher) {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -102,3 +107,20 @@ var vmessCipherList = []string{
|
||||
"chacha20-poly1305",
|
||||
"none",
|
||||
}
|
||||
|
||||
var ssCipherList = []string{
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"rc4-md5",
|
||||
"chacha20-ietf",
|
||||
"xchacha20",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
}
|
||||
|
||||
121
proxy/shadowsocks.go
Normal file
121
proxy/shadowsocks.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/tool"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorNotSSLink = errors.New("not a correct ss link")
|
||||
)
|
||||
|
||||
type Shadowsocks struct {
|
||||
Base
|
||||
Password string `yaml:"password" json:"password"`
|
||||
Cipher string `yaml:"cipher" json:"cipher"`
|
||||
Plugin string `yaml:"plugin,omitempty" json:"plugin,omitempty"`
|
||||
PluginOpts map[string]interface{} `yaml:"plugin-opts,omitempty" json:"plugin-opts,omitempty"`
|
||||
}
|
||||
|
||||
func (ss Shadowsocks) Identifier() string {
|
||||
return net.JoinHostPort(ss.Server, strconv.Itoa(ss.Port)) + ss.Password
|
||||
}
|
||||
|
||||
func (ss Shadowsocks) String() string {
|
||||
data, err := json.Marshal(ss)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func (ss Shadowsocks) ToClash() string {
|
||||
data, err := json.Marshal(ss)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return "- " + string(data)
|
||||
}
|
||||
|
||||
func (ss *Shadowsocks) SetName(name string) {
|
||||
ss.Name = name
|
||||
}
|
||||
|
||||
func ParseSSLink(link string) (*Shadowsocks, error) {
|
||||
if !strings.HasPrefix(link, "ss://") {
|
||||
return nil, ErrorNotSSRLink
|
||||
}
|
||||
|
||||
uri, err := url.Parse(link)
|
||||
if err != nil {
|
||||
return nil, ErrorNotSSLink
|
||||
}
|
||||
|
||||
server := uri.Hostname()
|
||||
port, _ := strconv.Atoi(uri.Port())
|
||||
|
||||
cipherInfoString, err := tool.Base64DecodeString(uri.User.Username())
|
||||
if err != nil {
|
||||
return nil, ErrorPasswordParseFail
|
||||
}
|
||||
cipherInfo := strings.SplitN(cipherInfoString, ":", 2)
|
||||
if len(cipherInfo) < 2 {
|
||||
return nil, ErrorPasswordParseFail
|
||||
}
|
||||
cipher := strings.ToLower(cipherInfo[0])
|
||||
password := cipherInfo[1]
|
||||
|
||||
moreInfos := uri.Query()
|
||||
pluginString := moreInfos.Get("plugin")
|
||||
plugin := ""
|
||||
pluginOpts := make(map[string]interface{})
|
||||
if strings.Contains(pluginString, ";") {
|
||||
pluginInfos, err := url.ParseQuery(pluginString)
|
||||
if err == nil {
|
||||
if strings.Contains(pluginString, "obfs") {
|
||||
plugin = "obfs"
|
||||
pluginOpts["mode"] = pluginInfos.Get("obfs")
|
||||
pluginOpts["host"] = pluginInfos.Get("obfs-host")
|
||||
} else if strings.Contains(pluginString, "v2ray") {
|
||||
plugin = "v2ray-plugin"
|
||||
pluginOpts["mode"] = pluginInfos.Get("mode")
|
||||
pluginOpts["host"] = pluginInfos.Get("host")
|
||||
pluginOpts["tls"] = strings.Contains(pluginString, "tls")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &Shadowsocks{
|
||||
Base: Base{
|
||||
Name: strconv.Itoa(rand.Int()),
|
||||
Server: server,
|
||||
Port: port,
|
||||
Type: "ss",
|
||||
},
|
||||
Password: password,
|
||||
Cipher: cipher,
|
||||
Plugin: plugin,
|
||||
PluginOpts: pluginOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
ssPlainRe = regexp.MustCompile("ss://([A-Za-z0-9+/_&?=@:%.-])+")
|
||||
)
|
||||
|
||||
func GrepSSLinkFromString(text string) []string {
|
||||
results := make([]string, 0)
|
||||
texts := strings.Split(text, "ss://")
|
||||
for _, text := range texts {
|
||||
results = append(results, ssPlainRe.FindAllString("ss://"+text, -1)...)
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseVmessLink(t *testing.T) {
|
||||
//link := "vmess://YXV0bzo5MGQ0YTM3NC1kYWU4LTExZWEtODY3Zi01NjAwMDJlY2MzNDlAZml2ZWRlbWFuZHMubWw6NDQz?remarks=%E6%97%A5%E6%9C%AC5%EF%BC%9A%E7%94%B5%E6%8A%A5%E9%A2%91%E9%81%93%EF%BC%9A"
|
||||
|
||||
link := "vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIkBTU1JTVUItVjI5LeS7mOi0ueaOqOiNkDp0LmNuL0VHSkl5cmwiLA0KICAiYWRkIjogImJ1cmdlcmtpbmdnb29kLm1sIiwNCiAgInBvcnQiOiAiNDQzIiwNCiAgImlkIjogIjRiNWJhMzkwLWRhZjQtMTFlYS04ODEwLTU2MDAwMmVjYzk2NyIsDQogICJhaWQiOiAiNDYiLA0KICAibmV0IjogIndzIiwNCiAgInR5cGUiOiAibm9uZSIsDQogICJob3N0IjogImJ1cmdlcmtpbmdnb29kLm1sIiwNCiAgInBhdGgiOiAiL0M2bGt2UzNLLyIsDQogICJ0bHMiOiAidGxzIg0KfQ=="
|
||||
fmt.Println(ParseVmessLink(link))
|
||||
}
|
||||
Reference in New Issue
Block a user