11package Common
22
33import (
4+ "context"
5+ "crypto/tls"
46 "errors"
57 "fmt"
6- "golang.org/x/net/proxy"
78 "net"
89 "net/url"
910 "strings"
1011 "time"
12+
13+ "golang.org/x/net/proxy"
1114)
1215
1316// WrapperTcpWithTimeout 创建一个带超时的TCP连接
@@ -16,6 +19,12 @@ func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.
1619 return WrapperTCP (network , address , d )
1720}
1821
22+ // WrapperTcpWithContext 创建一个带上下文的TCP连接
23+ func WrapperTcpWithContext (ctx context.Context , network , address string ) (net.Conn , error ) {
24+ d := & net.Dialer {}
25+ return WrapperTCPWithContext (ctx , network , address , d )
26+ }
27+
1928// WrapperTCP 根据配置创建TCP连接
2029func WrapperTCP (network , address string , forward * net.Dialer ) (net.Conn , error ) {
2130 // 直连模式
@@ -41,6 +50,54 @@ func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error)
4150 return conn , nil
4251}
4352
53+ // WrapperTCPWithContext 根据配置创建支持上下文的TCP连接
54+ func WrapperTCPWithContext (ctx context.Context , network , address string , forward * net.Dialer ) (net.Conn , error ) {
55+ // 直连模式
56+ if Socks5Proxy == "" {
57+ conn , err := forward .DialContext (ctx , network , address )
58+ if err != nil {
59+ return nil , fmt .Errorf (GetText ("tcp_conn_failed" ), err )
60+ }
61+ return conn , nil
62+ }
63+
64+ // Socks5代理模式
65+ dialer , err := Socks5Dialer (forward )
66+ if err != nil {
67+ return nil , fmt .Errorf (GetText ("socks5_create_failed" ), err )
68+ }
69+
70+ // 创建一个结果通道来处理连接和取消
71+ connChan := make (chan struct {
72+ conn net.Conn
73+ err error
74+ }, 1 )
75+
76+ go func () {
77+ conn , err := dialer .Dial (network , address )
78+ select {
79+ case <- ctx .Done ():
80+ if conn != nil {
81+ conn .Close ()
82+ }
83+ case connChan <- struct {
84+ conn net.Conn
85+ err error
86+ }{conn , err }:
87+ }
88+ }()
89+
90+ select {
91+ case <- ctx .Done ():
92+ return nil , ctx .Err ()
93+ case result := <- connChan :
94+ if result .err != nil {
95+ return nil , fmt .Errorf (GetText ("socks5_conn_failed" ), result .err )
96+ }
97+ return result .conn , nil
98+ }
99+ }
100+
44101// Socks5Dialer 创建Socks5代理拨号器
45102func Socks5Dialer (forward * net.Dialer ) (proxy.Dialer , error ) {
46103 // 解析代理URL
@@ -76,3 +133,59 @@ func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
76133
77134 return dialer , nil
78135}
136+
137+ // WrapperTlsWithContext 创建一个通过代理的TLS连接
138+ func WrapperTlsWithContext (ctx context.Context , network , address string , tlsConfig * tls.Config ) (net.Conn , error ) {
139+ // 直连模式
140+ if Socks5Proxy == "" {
141+ dialer := & net.Dialer {}
142+
143+ tcpConn , err := dialer .DialContext (ctx , network , address )
144+ if err != nil {
145+ return nil , fmt .Errorf ("直连TCP连接失败: %v" , err )
146+ }
147+
148+ // 在TCP连接上进行TLS握手
149+ tlsConn := tls .Client (tcpConn , tlsConfig )
150+
151+ // 使用ctx的deadline设置TLS握手超时
152+ if deadline , ok := ctx .Deadline (); ok {
153+ tlsConn .SetDeadline (deadline )
154+ }
155+
156+ if err := tlsConn .Handshake (); err != nil {
157+ tcpConn .Close ()
158+ return nil , fmt .Errorf ("TLS握手失败: %v" , err )
159+ }
160+
161+ // 清除deadline,让上层代码自己管理超时
162+ tlsConn .SetDeadline (time.Time {})
163+
164+ return tlsConn , nil
165+ }
166+
167+ // Socks5代理模式
168+ // 首先通过代理建立到目标的TCP连接
169+ tcpConn , err := WrapperTcpWithContext (ctx , network , address )
170+ if err != nil {
171+ return nil , fmt .Errorf ("通过代理建立TCP连接失败: %v" , err )
172+ }
173+
174+ // 在TCP连接上进行TLS握手
175+ tlsConn := tls .Client (tcpConn , tlsConfig )
176+
177+ // 使用ctx的deadline设置TLS握手超时
178+ if deadline , ok := ctx .Deadline (); ok {
179+ tlsConn .SetDeadline (deadline )
180+ }
181+
182+ if err := tlsConn .Handshake (); err != nil {
183+ tcpConn .Close ()
184+ return nil , fmt .Errorf ("TLS握手失败: %v" , err )
185+ }
186+
187+ // 清除deadline,让上层代码自己管理超时
188+ tlsConn .SetDeadline (time.Time {})
189+
190+ return tlsConn , nil
191+ }
0 commit comments