add shadowsocks and subscribe support

This commit is contained in:
zu1k
2020-08-12 17:09:11 +08:00
parent a96d21f4c7
commit e6c935f13f
9 changed files with 202 additions and 37 deletions

View File

@@ -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)

View File

@@ -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))
}

View File

@@ -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,
}
}

View File

@@ -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)...)
})
// 找到之前消息页面的链接,加入访问队列

View File

@@ -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 {

View File

@@ -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())
}

View File

@@ -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
View 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
}

View File

@@ -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))
}