diff --git a/README.md b/README.md index 02ba0ca..eeab6db 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ - Trojan - Hysteria (Clash.Meta) - Hysteria2 (Clash.Meta) + - Socks5 ## 使用 diff --git a/common/proxy.go b/common/proxy.go index b3c5e22..47f5aeb 100644 --- a/common/proxy.go +++ b/common/proxy.go @@ -127,6 +127,9 @@ func ParseProxy(proxies ...string) []model.Proxy { if strings.HasPrefix(proxy, constant.HysteriaPrefix) { proxyItem, err = parser.ParseHysteria(proxy) } + if strings.HasPrefix(proxy, constant.SocksPrefix) { + proxyItem, err = parser.ParseSocks(proxy) + } if err == nil { result = append(result, proxyItem) } else { diff --git a/constant/prefix.go b/constant/prefix.go index e629cf1..bc85e7b 100644 --- a/constant/prefix.go +++ b/constant/prefix.go @@ -9,4 +9,5 @@ const ( TrojanPrefix string = "trojan://" VLESSPrefix string = "vless://" VMessPrefix string = "vmess://" + SocksPrefix string = "socks" ) diff --git a/model/clash.go b/model/clash.go index 5159709..39906b0 100644 --- a/model/clash.go +++ b/model/clash.go @@ -14,6 +14,7 @@ func GetSupportProxyTypes(clashType ClashType) map[string]bool { "ssr": true, "vmess": true, "trojan": true, + "socks5": true, } } if clashType == ClashMeta { @@ -25,6 +26,7 @@ func GetSupportProxyTypes(clashType ClashType) map[string]bool { "vless": true, "hysteria": true, "hysteria2": true, + "socks5": true, } } return nil diff --git a/model/proxy.go b/model/proxy.go index deb62fa..59520d3 100644 --- a/model/proxy.go +++ b/model/proxy.go @@ -10,6 +10,7 @@ type Proxy struct { Port int `yaml:"port,omitempty"` Type string `yaml:"type,omitempty"` Cipher string `yaml:"cipher,omitempty"` + Username string `yaml:"username,omitempty"` Password string `yaml:"password,omitempty"` UDP bool `yaml:"udp,omitempty"` UUID string `yaml:"uuid,omitempty"` diff --git a/parser/socks.go b/parser/socks.go new file mode 100644 index 0000000..677ad66 --- /dev/null +++ b/parser/socks.go @@ -0,0 +1,79 @@ +package parser + +import ( + "fmt" + "github.com/nitezs/sub2clash/constant" + "github.com/nitezs/sub2clash/model" + "net/url" + "strings" +) + +func ParseSocks(proxy string) (model.Proxy, error) { + if !strings.HasPrefix(proxy, constant.SocksPrefix) { + return model.Proxy{}, &ParseError{Type: ErrInvalidPrefix, Raw: proxy} + } + link, err := url.Parse(proxy) + if err != nil { + return model.Proxy{}, &ParseError{ + Type: ErrInvalidStruct, + Message: "url parse error", + Raw: proxy, + } + } + server := link.Hostname() + if server == "" { + return model.Proxy{}, &ParseError{ + Type: ErrInvalidStruct, + Message: "missing server host", + Raw: proxy, + } + } + portStr := link.Port() + if portStr == "" { + return model.Proxy{}, &ParseError{ + Type: ErrInvalidStruct, + Message: "missing server port", + Raw: proxy, + } + } + port, err := ParsePort(portStr) + if err != nil { + return model.Proxy{}, &ParseError{ + Type: ErrInvalidPort, + Raw: portStr, + } + } + + remarks := link.Fragment + if remarks == "" { + remarks = fmt.Sprintf("%s:%s", server, portStr) + } + remarks = strings.TrimSpace(remarks) + + encodeStr := link.User.Username() + var username, password string + if encodeStr != "" { + decodeStr, err := DecodeBase64(encodeStr) + splitStr := strings.Split(decodeStr, ":") + if err != nil { + return model.Proxy{}, &ParseError{ + Type: ErrInvalidStruct, + Message: "url parse error", + Raw: proxy, + } + } + username = splitStr[0] + if len(splitStr) == 2 { + password = splitStr[1] + } + } + return model.Proxy{ + Type: "socks5", + Name: remarks, + Server: server, + Port: port, + Username: username, + Password: password, + }, nil + +}