github.com/yaling888/clash@v1.53.0/adapter/outbound/socks5.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "net/netip" 11 "strconv" 12 13 "github.com/yaling888/clash/component/dialer" 14 C "github.com/yaling888/clash/constant" 15 "github.com/yaling888/clash/transport/socks5" 16 ) 17 18 var _ C.ProxyAdapter = (*Socks5)(nil) 19 20 type Socks5 struct { 21 *Base 22 user string 23 pass string 24 tls bool 25 skipCertVerify bool 26 tlsConfig *tls.Config 27 } 28 29 type Socks5Option struct { 30 BasicOption 31 Name string `proxy:"name"` 32 Server string `proxy:"server"` 33 Port int `proxy:"port"` 34 UserName string `proxy:"username,omitempty"` 35 Password string `proxy:"password,omitempty"` 36 TLS bool `proxy:"tls,omitempty"` 37 UDP bool `proxy:"udp,omitempty"` 38 SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` 39 RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` 40 } 41 42 // StreamConn implements C.ProxyAdapter 43 func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 44 var err error 45 c, _, err = ss.streamConn(c, metadata) 46 47 return c, err 48 } 49 50 func (ss *Socks5) StreamSocks5PacketConn(c net.Conn, pc net.PacketConn, metadata *C.Metadata) (net.PacketConn, error) { 51 if c == nil { 52 return pc, fmt.Errorf("%s connect error: parameter net.Conn is nil", ss.addr) 53 } 54 55 if pc == nil { 56 return pc, fmt.Errorf("%s connect error: parameter net.PacketConn is nil", ss.addr) 57 } 58 59 cc, bindAddr, err := ss.streamConn(c, metadata) 60 if err != nil { 61 return pc, err 62 } 63 64 c = cc 65 66 go func() { 67 _, _ = io.Copy(io.Discard, c) 68 _ = c.Close() 69 // A UDP association terminates when the TCP connection that the UDP 70 // ASSOCIATE request arrived at terminates. RFC1928 71 _ = pc.Close() 72 }() 73 74 // Support unspecified UDP bind address. 75 bindUDPAddr := bindAddr.UDPAddr() 76 if bindUDPAddr == nil { 77 return pc, errors.New("invalid UDP bind address") 78 } else if bindUDPAddr.IP.IsUnspecified() { 79 serverAddr, err := resolveUDPAddr("udp", ss.Addr()) 80 if err != nil { 81 return pc, err 82 } 83 84 bindUDPAddr.IP = serverAddr.IP 85 } 86 87 return &socksPacketConn{PacketConn: pc, rAddr: bindUDPAddr, tcpConn: c}, nil 88 } 89 90 func (ss *Socks5) streamConn(c net.Conn, metadata *C.Metadata) (_ net.Conn, bindAddr socks5.Addr, err error) { 91 if ss.tls { 92 cc := tls.Client(c, ss.tlsConfig) 93 ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) 94 defer cancel() 95 err = cc.HandshakeContext(ctx) 96 c = cc 97 if err != nil { 98 return c, nil, fmt.Errorf("%s connect error: %w", ss.addr, err) 99 } 100 } 101 102 var user *socks5.User 103 if ss.user != "" { 104 user = &socks5.User{ 105 Username: ss.user, 106 Password: ss.pass, 107 } 108 } 109 110 if metadata.NetWork == C.UDP { 111 udpAssocateAddr := socks5.AddrFromStdAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), 0)) 112 bindAddr, err = socks5.ClientHandshake(c, udpAssocateAddr, socks5.CmdUDPAssociate, user) 113 } else { 114 bindAddr, err = socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdConnect, user) 115 } 116 117 return c, bindAddr, err 118 } 119 120 // DialContext implements C.ProxyAdapter 121 func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 122 c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) 123 if err != nil { 124 return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) 125 } 126 tcpKeepAlive(c) 127 128 defer func(cc net.Conn, e error) { 129 safeConnClose(cc, e) 130 }(c, err) 131 132 c, err = ss.StreamConn(c, metadata) 133 if err != nil { 134 return nil, err 135 } 136 137 return NewConn(c, ss), nil 138 } 139 140 // ListenPacketContext implements C.ProxyAdapter 141 func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { 142 c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) 143 if err != nil { 144 return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) 145 } 146 147 defer func(cc net.Conn, e error) { 148 safeConnClose(cc, e) 149 }(c, err) 150 151 pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...) 152 if err != nil { 153 return 154 } 155 156 tcpKeepAlive(c) 157 158 pc, err = ss.StreamSocks5PacketConn(c, pc, metadata) 159 if err != nil { 160 return 161 } 162 163 return NewPacketConn(pc, ss), nil 164 } 165 166 func NewSocks5(option Socks5Option) *Socks5 { 167 var tlsConfig *tls.Config 168 if option.TLS { 169 tlsConfig = &tls.Config{ 170 InsecureSkipVerify: option.SkipCertVerify, 171 ServerName: option.Server, 172 } 173 } 174 175 return &Socks5{ 176 Base: &Base{ 177 name: option.Name, 178 addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), 179 tp: C.Socks5, 180 udp: option.UDP, 181 iface: option.Interface, 182 rmark: option.RoutingMark, 183 dns: option.RemoteDnsResolve, 184 }, 185 user: option.UserName, 186 pass: option.Password, 187 tls: option.TLS, 188 skipCertVerify: option.SkipCertVerify, 189 tlsConfig: tlsConfig, 190 } 191 } 192 193 type socksPacketConn struct { 194 net.PacketConn 195 rAddr net.Addr 196 tcpConn net.Conn 197 } 198 199 func (uc *socksPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { 200 packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) 201 if err != nil { 202 return 203 } 204 return uc.PacketConn.WriteTo(packet, uc.rAddr) 205 } 206 207 func (uc *socksPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 208 n, _, e := uc.PacketConn.ReadFrom(b) 209 if e != nil { 210 return 0, nil, e 211 } 212 addr, payload, err := socks5.DecodeUDPPacket(b) 213 if err != nil { 214 return 0, nil, err 215 } 216 217 udpAddr := addr.UDPAddr() 218 if udpAddr == nil { 219 return 0, nil, errors.New("parse udp addr error") 220 } 221 222 // due to DecodeUDPPacket is mutable, record addr length 223 copy(b, payload) 224 return n - len(addr) - 3, udpAddr, nil 225 } 226 227 func (uc *socksPacketConn) Close() error { 228 _ = uc.tcpConn.Close() 229 return uc.PacketConn.Close() 230 }