Skip to content

Commit d1181f5

Browse files
committed
refactor(protocol): 统一代理配置转换逻辑并完善协议支持
- 在各协议文件中添加 ConvertProxyToX 函数,将 Clash 格式配置转换为对应协议结构体 - 修改 sub.go 中的 GenerateLinkFromClashProxy 函数,使用协议层转换函数统一生成链接 - 移除 sub.go 中重复的代理配置解析逻辑,简化代码结构 - 为 HY 协议添加 protocol 参数和 ALPN 参数支持 - 为 HY2 协议添加客户端指纹参数和 ALPN 参数支持 - 为 Trojan 协议添加 Reality 参数支持和 ALPN 参数支持 - 优化 SSR 协议链接生成逻辑,仅添加非空参数 - 完善 VLESS 协议的多种传输层选项支持 - 为 Hysteria2 协议添加 SNI 和 Servername 优先级处理
1 parent beffbd4 commit d1181f5

File tree

11 files changed

+504
-424
lines changed

11 files changed

+504
-424
lines changed

node/protocol/anytls.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,17 @@ func EncodeAnyTLSURL(a AnyTLS) string {
9191
}
9292
return u.String()
9393
}
94+
95+
// ConvertProxyToAnyTLS 将 Proxy 结构体转换为 AnyTLS 结构体
96+
// 用于从 Clash 格式的代理配置生成 AnyTLS 链接
97+
func ConvertProxyToAnyTLS(proxy Proxy) AnyTLS {
98+
return AnyTLS{
99+
Name: proxy.Name,
100+
Server: proxy.Server,
101+
Port: int(proxy.Port),
102+
Password: proxy.Password,
103+
SkipCertVerify: proxy.Skip_cert_verify,
104+
SNI: proxy.Sni,
105+
ClientFingerprint: proxy.Client_fingerprint,
106+
}
107+
}

node/protocol/hy.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,21 @@ func EncodeHYURL(hy HY) string {
4747
Fragment: hy.Name,
4848
}
4949
q := u.Query()
50+
// protocol 参数,Hysteria 基于 UDP/QUIC
51+
q.Set("protocol", "udp")
5052
q.Set("insecure", strconv.Itoa(hy.Insecure))
5153
q.Set("peer", hy.Peer)
5254
q.Set("auth", hy.Auth)
5355
q.Set("upmbps", strconv.Itoa(hy.UpMbps))
5456
q.Set("downmbps", strconv.Itoa(hy.DownMbps))
55-
// q.Set("alpn", hy.ALPN)
57+
// alpn 参数支持
58+
if len(hy.ALPN) > 0 {
59+
q.Set("alpn", strings.Join(hy.ALPN, ","))
60+
}
5661
// 检查query是否有空值,有的话删除
5762
for k, v := range q {
58-
if v[0] == "" {
63+
if v[0] == "" || v[0] == "0" {
5964
delete(q, k)
60-
// fmt.Printf("k: %v, v: %v\n", k, v)
6165
}
6266
}
6367
u.RawQuery = q.Encode()
@@ -114,3 +118,25 @@ func DecodeHYURL(s string) (HY, error) {
114118
Name: name,
115119
}, nil
116120
}
121+
122+
// ConvertProxyToHy 将 Proxy 结构体转换为 HY 结构体
123+
// 用于从 Clash 格式的代理配置生成 Hysteria 链接
124+
func ConvertProxyToHy(proxy Proxy) HY {
125+
hy := HY{
126+
Host: proxy.Server,
127+
Port: int(proxy.Port),
128+
Auth: proxy.Auth_str,
129+
UpMbps: proxy.Up,
130+
DownMbps: proxy.Down,
131+
ALPN: proxy.Alpn,
132+
Peer: proxy.Peer,
133+
Name: proxy.Name,
134+
}
135+
136+
// 处理跳过证书验证
137+
if proxy.Skip_cert_verify {
138+
hy.Insecure = 1
139+
}
140+
141+
return hy
142+
}

node/protocol/hy2.go

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,21 @@ import (
99
)
1010

1111
type HY2 struct {
12-
Password string
13-
Host string
14-
Port interface{}
15-
MPort string
16-
Insecure int
17-
Peer string
18-
Auth string
19-
UpMbps int
20-
DownMbps int
21-
ALPN []string
22-
Name string
23-
Sni string
24-
Obfs string
25-
ObfsPassword string
12+
Password string
13+
Host string
14+
Port interface{}
15+
MPort string
16+
Insecure int
17+
Peer string
18+
Auth string
19+
UpMbps int
20+
DownMbps int
21+
ALPN []string
22+
Name string
23+
Sni string
24+
Obfs string
25+
ObfsPassword string
26+
ClientFingerprint string // 客户端指纹
2627
}
2728

2829
// 开发者测试 CallHy 调用
@@ -63,6 +64,12 @@ func EncodeHY2URL(hy2 HY2) string {
6364
q.Set("sni", hy2.Sni)
6465
q.Set("obfs", hy2.Obfs)
6566
q.Set("obfs-password", hy2.ObfsPassword)
67+
// 客户端指纹参数
68+
q.Set("fp", hy2.ClientFingerprint)
69+
// alpn 参数支持
70+
if len(hy2.ALPN) > 0 {
71+
q.Set("alpn", strings.Join(hy2.ALPN, ","))
72+
}
6673
// 检查query是否有空值,有的话删除
6774
for k, v := range q {
6875
if v[0] == "" || v[0] == "0" {
@@ -105,6 +112,7 @@ func DecodeHY2URL(s string) (HY2, error) {
105112
sni := u.Query().Get("sni")
106113
obfs := u.Query().Get("obfs")
107114
obfsPassword := u.Query().Get("obfs-password")
115+
clientFingerprint := u.Query().Get("fp")
108116
name := u.Fragment
109117
// 如果没有设置 Name,则使用 Host:Port 作为 Fragment
110118
if name == "" {
@@ -123,21 +131,56 @@ func DecodeHY2URL(s string) (HY2, error) {
123131
fmt.Println("sni:", sni)
124132
fmt.Println("obfs:", obfs)
125133
fmt.Println("obfsPassword:", obfsPassword)
134+
fmt.Println("fp:", clientFingerprint)
126135
fmt.Println("name:", name)
127136
}
128137
return HY2{
129-
Password: password,
130-
Host: server,
131-
Port: port,
132-
MPort: mport,
133-
Insecure: insecure,
134-
Auth: auth,
135-
UpMbps: upMbps,
136-
DownMbps: downMbps,
137-
ALPN: alpn,
138-
Name: name,
139-
Sni: sni,
140-
Obfs: obfs,
141-
ObfsPassword: obfsPassword,
138+
Password: password,
139+
Host: server,
140+
Port: port,
141+
MPort: mport,
142+
Insecure: insecure,
143+
Auth: auth,
144+
UpMbps: upMbps,
145+
DownMbps: downMbps,
146+
ALPN: alpn,
147+
Name: name,
148+
Sni: sni,
149+
Obfs: obfs,
150+
ObfsPassword: obfsPassword,
151+
ClientFingerprint: clientFingerprint,
142152
}, nil
143153
}
154+
155+
// ConvertProxyToHy2 将 Proxy 结构体转换为 HY2 结构体
156+
// 用于从 Clash 格式的代理配置生成 Hysteria2 链接
157+
func ConvertProxyToHy2(proxy Proxy) HY2 {
158+
hy2 := HY2{
159+
Password: proxy.Password,
160+
Host: proxy.Server,
161+
Port: int(proxy.Port),
162+
MPort: proxy.Ports,
163+
Auth: proxy.Auth_str,
164+
UpMbps: proxy.Up,
165+
DownMbps: proxy.Down,
166+
ALPN: proxy.Alpn,
167+
Name: proxy.Name,
168+
Sni: proxy.Sni,
169+
Obfs: proxy.Obfs,
170+
ObfsPassword: proxy.Obfs_password,
171+
ClientFingerprint: proxy.Client_fingerprint,
172+
Peer: proxy.Peer,
173+
}
174+
175+
// 处理跳过证书验证
176+
if proxy.Skip_cert_verify {
177+
hy2.Insecure = 1
178+
}
179+
180+
// 如果SNI为空,尝试使用Servername
181+
if hy2.Sni == "" && proxy.Servername != "" {
182+
hy2.Sni = proxy.Servername
183+
}
184+
185+
return hy2
186+
}

node/protocol/socks5.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,15 @@ func EncodeSocks5URL(s Socks5) string {
7373
}
7474
return u.String()
7575
}
76+
77+
// ConvertProxyToSocks5 将 Proxy 结构体转换为 Socks5 结构体
78+
// 用于从 Clash 格式的代理配置生成 Socks5 链接
79+
func ConvertProxyToSocks5(proxy Proxy) Socks5 {
80+
return Socks5{
81+
Name: proxy.Name,
82+
Server: proxy.Server,
83+
Port: int(proxy.Port),
84+
Username: proxy.Username,
85+
Password: proxy.Password,
86+
}
87+
}

node/protocol/ss.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,50 @@ func DecodeSSURL(s string) (Ss, error) {
326326
Plugin: plugin,
327327
}, nil
328328
}
329+
330+
// ConvertProxyToSs 将 Proxy 结构体转换为 Ss 结构体
331+
// 用于从 Clash 格式的代理配置生成 SS 链接
332+
func ConvertProxyToSs(proxy Proxy) Ss {
333+
ss := Ss{
334+
Param: Param{
335+
Cipher: proxy.Cipher,
336+
Password: proxy.Password,
337+
},
338+
Server: proxy.Server,
339+
Port: int(proxy.Port),
340+
Name: proxy.Name,
341+
Type: "ss",
342+
}
343+
344+
// 处理插件信息
345+
if proxy.Plugin != "" {
346+
ss.Plugin = SsPlugin{
347+
Name: proxy.Plugin,
348+
}
349+
if proxy.Plugin_opts != nil {
350+
if mode, ok := proxy.Plugin_opts["mode"].(string); ok {
351+
ss.Plugin.Mode = mode
352+
}
353+
if host, ok := proxy.Plugin_opts["host"].(string); ok {
354+
ss.Plugin.Host = host
355+
}
356+
if path, ok := proxy.Plugin_opts["path"].(string); ok {
357+
ss.Plugin.Path = path
358+
}
359+
if tls, ok := proxy.Plugin_opts["tls"].(bool); ok {
360+
ss.Plugin.Tls = tls
361+
}
362+
if mux, ok := proxy.Plugin_opts["mux"].(bool); ok {
363+
ss.Plugin.Mux = mux
364+
}
365+
if password, ok := proxy.Plugin_opts["password"].(string); ok {
366+
ss.Plugin.Password = password
367+
}
368+
if version, ok := proxy.Plugin_opts["version"].(int); ok {
369+
ss.Plugin.Version = version
370+
}
371+
}
372+
}
373+
374+
return ss
375+
}

node/protocol/ssr.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,31 @@ func EncodeSSRURL(s Ssr) string {
2929
/*编码格式
3030
ssr://base64(host:port:protocol:method:obfs:base64(password)/?obfsparam=base64(obfsparam)&protoparam=base64(protoparam)&remarks=base64(remarks)&group=base64(group))
3131
*/
32-
obfsparam := "obfsparam=" + utils.Base64Encode(s.Qurey.Obfsparam)
33-
remarks := "remarks=" + utils.Base64Encode(s.Qurey.Remarks)
34-
// 如果没有备注默认使用服务器+端口作为备注
35-
if s.Qurey.Remarks == "" {
36-
server_port := utils.Base64Encode(s.Server + ":" + utils.GetPortString(s.Port))
37-
remarks = fmt.Sprintf("remarks=%s", server_port)
32+
// 构建查询参数,仅添加非空参数
33+
var queryParts []string
34+
35+
// remarks 必须有,如果没有则使用服务器+端口
36+
remarks := s.Qurey.Remarks
37+
if remarks == "" {
38+
remarks = s.Server + ":" + utils.GetPortString(s.Port)
3839
}
39-
param := fmt.Sprintf("%s:%s:%s:%s:%s:%s/?%s&%s",
40+
queryParts = append(queryParts, "remarks="+utils.Base64Encode(remarks))
41+
42+
// obfsparam 仅在非空时添加
43+
if s.Qurey.Obfsparam != "" {
44+
queryParts = append(queryParts, "obfsparam="+utils.Base64Encode(s.Qurey.Obfsparam))
45+
}
46+
47+
param := fmt.Sprintf("%s:%s:%s:%s:%s:%s/?%s",
4048
s.Server,
4149
utils.GetPortString(s.Port),
4250
s.Protocol,
4351
s.Method,
4452
s.Obfs,
4553
utils.Base64Encode(s.Password),
46-
obfsparam,
47-
remarks,
54+
strings.Join(queryParts, "&"),
4855
)
4956
return "ssr://" + utils.Base64Encode(param)
50-
5157
}
5258

5359
// ssr解码
@@ -143,3 +149,21 @@ type Ssrquery struct {
143149
Obfsparam string
144150
Remarks string
145151
}
152+
153+
// ConvertProxyToSsr 将 Proxy 结构体转换为 Ssr 结构体
154+
// 用于从 Clash 格式的代理配置生成 SSR 链接
155+
func ConvertProxyToSsr(proxy Proxy) Ssr {
156+
return Ssr{
157+
Server: proxy.Server,
158+
Port: int(proxy.Port),
159+
Protocol: proxy.Protocol,
160+
Method: proxy.Cipher,
161+
Obfs: proxy.Obfs,
162+
Password: proxy.Password,
163+
Qurey: Ssrquery{
164+
Obfsparam: proxy.Obfs_password,
165+
Remarks: proxy.Name,
166+
},
167+
Type: "ssr",
168+
}
169+
}

0 commit comments

Comments
 (0)