sublinker / node /ss.go
YimoEx
init
bb9df9e
package node
import (
"fmt"
"log"
"net/url"
"strconv"
"strings"
)
// ss匹配规则
type Ss struct {
Param Param
Server string
Port int
Name string
Type string
}
type Param struct {
Cipher string
Password string
}
func parsingSS(s string) (string, string, string) {
/* ss url编码分为三部分:加密方式、服务器地址和端口、备注
://和@之前为第一部分 @到#之间为第二部分 #之后为第三部分
第一部分 为加密方式和密码,格式为:加密方式:密码 示例:aes-128-gcm:123456
第二部分 为服务器地址和端口,格式为:服务器地址:端口 示例:xxx.xxx:12345
第三部分 为备注,格式为:#备注 示例:#备注
*/
u, err := url.Parse(s)
if err != nil {
log.Println("ss url parse fail.", err)
return "", "", ""
}
if u.Scheme != "ss" {
log.Println("ss url parse fail, not ss url.")
return "", "", ""
}
// 处理url全编码的情况
if u.User == nil {
// 截取ss://后的字符串
raw := s[5:]
s = "ss://" + Base64Decode(raw)
u, err = url.Parse(s)
}
var auth, addr, name string
auth = u.User.String()
if u.Host != "" {
addr = u.Host
}
if u.Fragment != "" {
name = u.Fragment
}
return auth, addr, name
}
// 开发者测试
func CallSSURL() {
ss := Ss{}
// ss.Name = "测试"
ss.Server = "baidu.com"
ss.Port = 443
ss.Param.Cipher = "2022-blake3-aes-256-gcm"
ss.Param.Password = "asdasd"
fmt.Println(EncodeSSURL(ss))
}
// ss 编码输出
func EncodeSSURL(s Ss) string {
//编码格式 ss://base64(base64(method:password)@hostname:port)
p := Base64Encode(s.Param.Cipher + ":" + s.Param.Password)
// 假设备注没有使用服务器加端口命名
if s.Name == "" {
s.Name = s.Server + ":" + strconv.Itoa(s.Port)
}
param := fmt.Sprintf("%s@%s:%s#%s",
p,
s.Server,
strconv.Itoa(s.Port),
s.Name,
)
return "ss://" + param
}
func DecodeSSURL(s string) (Ss, error) {
// 解析ss链接
param, addr, name := parsingSS(s)
// base64解码
param = Base64Decode(param)
// 判断是否为空
if param == "" || addr == "" {
return Ss{}, fmt.Errorf("invalid SS URL")
}
// 解析参数
parts := strings.Split(addr, ":")
port, _ := strconv.Atoi(parts[len(parts)-1])
server := strings.Replace(ValRetIPv6Addr(addr), ":"+parts[len(parts)-1], "", -1)
cipher := strings.Split(param, ":")[0]
password := strings.Replace(param, cipher+":", "", 1)
// 如果没有备注则使用服务器加端口命名
if name == "" {
name = addr
}
// 开发环境输出结果
if CheckEnvironment() {
fmt.Println("Param:", Base64Decode(param))
fmt.Println("Server", server)
fmt.Println("Port", port)
fmt.Println("Name:", name)
fmt.Println("Cipher:", cipher)
fmt.Println("Password:", password)
}
// 返回结果
return Ss{
Param: Param{
Cipher: cipher,
Password: password,
},
Server: server,
Port: port,
Name: name,
Type: "ss",
}, nil
}