github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/socks5/client.go (about) 1 package socks5 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net" 9 10 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 11 "github.com/Asutorufa/yuhaiin/pkg/net/proxy/simple" 12 "github.com/Asutorufa/yuhaiin/pkg/net/proxy/socks5/tools" 13 "github.com/Asutorufa/yuhaiin/pkg/net/proxy/yuubinsya" 14 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 15 "github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol" 16 "github.com/Asutorufa/yuhaiin/pkg/protos/statistic" 17 "github.com/Asutorufa/yuhaiin/pkg/utils/pool" 18 "github.com/Asutorufa/yuhaiin/pkg/utils/relay" 19 "github.com/Asutorufa/yuhaiin/pkg/utils/yerror" 20 ) 21 22 func Dial(host, port, user, password string) netapi.Proxy { 23 addr, err := netapi.ParseAddress(statistic.Type_tcp, net.JoinHostPort(host, port)) 24 if err != nil { 25 return netapi.NewErrProxy(err) 26 } 27 p, _ := NewClient(&protocol.Protocol_Socks5{ 28 Socks5: &protocol.Socks5{ 29 Hostname: host, 30 User: user, 31 Password: password, 32 }})(yerror.Must(simple.NewClient(&protocol.Protocol_Simple{ 33 Simple: &protocol.Simple{ 34 Host: addr.Hostname(), 35 Port: int32(addr.Port().Port()), 36 }, 37 })(nil))) 38 return p 39 } 40 41 // https://tools.ietf.org/html/rfc1928 42 // Client socks5 Client 43 type Client struct { 44 username string 45 password string 46 47 hostname string 48 netapi.EmptyDispatch 49 dialer netapi.Proxy 50 } 51 52 func init() { 53 point.RegisterProtocol(NewClient) 54 } 55 56 // New returns a new Socks5 client 57 func NewClient(config *protocol.Protocol_Socks5) point.WrapProxy { 58 return func(dialer netapi.Proxy) (netapi.Proxy, error) { 59 return &Client{ 60 dialer: dialer, 61 username: config.Socks5.User, 62 password: config.Socks5.Password, 63 hostname: config.Socks5.Hostname, 64 }, nil 65 } 66 } 67 68 func (s *Client) Conn(ctx context.Context, host netapi.Address) (net.Conn, error) { 69 conn, err := s.dialer.Conn(ctx, host) 70 if err != nil { 71 return nil, fmt.Errorf("dial failed: %w", err) 72 } 73 74 err = s.handshake1(conn) 75 if err != nil { 76 conn.Close() 77 return nil, fmt.Errorf("first hand failed: %w", err) 78 } 79 80 _, err = s.handshake2(ctx, conn, tools.Connect, host) 81 if err != nil { 82 conn.Close() 83 return nil, fmt.Errorf("second hand failed: %w", err) 84 } 85 86 return conn, nil 87 } 88 89 func (s *Client) handshake1(conn net.Conn) error { 90 _, err := conn.Write([]byte{0x05, 0x02, tools.NoAuthenticationRequired, tools.UserAndPassword}) 91 if err != nil { 92 return fmt.Errorf("write sock5 header failed: %w", err) 93 } 94 95 header := make([]byte, 2) 96 _, err = io.ReadFull(conn, header) 97 if err != nil { 98 return fmt.Errorf("read header failed: %w", err) 99 } 100 101 if header[0] != 0x05 { 102 return errors.New("unknown socks5 version") 103 } 104 105 switch header[1] { 106 case tools.NoAuthenticationRequired: 107 return nil 108 case tools.UserAndPassword: // username and password 109 req := pool.GetBytesWriter(pool.DefaultSize) 110 defer req.Free() 111 112 req.WriteByte(0x01) 113 req.WriteByte(byte(len(s.username))) 114 req.WriteString(s.username) 115 req.WriteByte(byte(len(s.password))) 116 req.WriteString(s.password) 117 118 _, err = conn.Write(req.Bytes()) 119 if err != nil { 120 return fmt.Errorf("write auth data failed: %w", err) 121 } 122 123 _, err = io.ReadFull(conn, header) 124 if err != nil { 125 return fmt.Errorf("read auth data failed: %w", err) 126 } 127 if header[1] == 0x01 { 128 return errors.New("username or password not correct,socks5 handshake failed") 129 } 130 } 131 132 return fmt.Errorf("unsupported Authentication methods: %d", header[1]) 133 } 134 135 func (s *Client) handshake2(ctx context.Context, conn net.Conn, cmd tools.CMD, address netapi.Address) (target netapi.Address, err error) { 136 req := pool.GetBytesWriter(pool.DefaultSize) 137 defer req.Free() 138 139 req.WriteByte(0x05) 140 req.WriteByte(byte(cmd)) 141 req.WriteByte(0x00) 142 tools.EncodeAddr(address, req) 143 144 if _, err = conn.Write(req.Bytes()); err != nil { 145 return nil, err 146 } 147 148 header := make([]byte, 3) 149 if _, err := io.ReadFull(conn, header); err != nil { 150 return nil, err 151 } 152 153 if header[0] != 0x05 || header[1] != tools.Succeeded { 154 return nil, fmt.Errorf("socks5 second handshake failed, data: %v", header[:2]) 155 } 156 157 add, err := tools.ResolveAddr(conn) 158 if err != nil { 159 return nil, fmt.Errorf("resolve addr failed: %w", err) 160 } 161 162 addr := add.Address(statistic.Type_tcp) 163 164 if addr.Type() == netapi.IP && yerror.Must(addr.IP(ctx)).IsUnspecified() { 165 addr = netapi.ParseAddressPort(statistic.Type_tcp, s.hostname, addr.Port()) 166 } 167 168 return addr, nil 169 } 170 171 func (s *Client) PacketConn(ctx context.Context, host netapi.Address) (net.PacketConn, error) { 172 conn, err := s.dialer.Conn(ctx, host) 173 if err != nil { 174 return nil, fmt.Errorf("dial tcp failed: %w", err) 175 } 176 177 err = s.handshake1(conn) 178 if err != nil { 179 conn.Close() 180 return nil, fmt.Errorf("first hand failed: %w", err) 181 } 182 183 addr, err := s.handshake2(ctx, conn, tools.Udp, host) 184 if err != nil { 185 conn.Close() 186 return nil, fmt.Errorf("second hand failed: %w", err) 187 } 188 189 pc, err := s.dialer.PacketConn(context.WithValue(ctx, simple.PacketDirectKey{}, true), addr) 190 if err != nil { 191 conn.Close() 192 return nil, fmt.Errorf("listen udp failed: %w", err) 193 } 194 195 pc = yuubinsya.NewAuthPacketConn(pc).WithTcpConn(conn).WithTarget(addr).WithPrefix(true) 196 197 go func() { 198 _, _ = relay.Copy(io.Discard, conn) 199 pc.Close() 200 }() 201 202 return pc, nil 203 } 204 205 // The client connects to the server, and sends a version 206 // identifier/method selection message: 207 208 // +----+----------+----------+ 209 // |VER | NMETHODS | METHODS | 210 // +----+----------+----------+ 211 // | 1 | 1 | 1 to 255 | 212 // +----+----------+----------+ 213 214 // The VER field is set to X'05' for this version of the protocol. The 215 // NMETHODS field contains the number of method identifier octets that 216 // appear in the METHODS field. 217 218 // The server selects from one of the methods given in METHODS, and 219 // sends a METHOD selection message: 220 221 // +----+--------+ 222 // |VER | METHOD | 223 // +----+--------+ 224 // | 1 | 1 | 225 // +----+--------+ 226 227 // If the selected METHOD is X'FF', none of the methods listed by the 228 // client are acceptable, and the client MUST close the connection. 229 230 // The values currently defined for METHOD are: 231 232 // o X'00' NO AUTHENTICATION REQUIRED 233 // o X'01' GSSAPI 234 // o X'02' USERNAME/PASSWORD 235 // o X'03' to X'7F' IANA ASSIGNED 236 // o X'80' to X'FE' RESERVED FOR PRIVATE METHODS 237 // o X'FF' NO ACCEPTABLE METHODS 238 // The client and server then enter a method-specific sub-negotiation. 239 240 // second handshake 241 242 // Once the method-dependent subnegotiation has completed, the client 243 // sends the request details. If the negotiated method includes 244 // encapsulation for purposes of integrity checking and/or 245 // confidentiality, these requests MUST be encapsulated in the method- 246 // dependent encapsulation. 247 248 // The SOCKS request is formed as follows: 249 250 // +----+-----+-------+------+----------+----------+ 251 // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 252 // +----+-----+-------+------+----------+----------+ 253 // | 1 | 1 | X'00' | 1 | Variable | 2 | 254 // +----+-----+-------+------+----------+----------+ 255 256 // Where: 257 258 // o VER protocol version: X'05' 259 // o CMD 260 // o CONNECT X'01' 261 // o BIND X'02' 262 // o UDP ASSOCIATE X'03' 263 // o RSV RESERVED 264 // o ATYP address type of following address 265 // o IP V4 address: X'01' 266 // o DOMAINNAME: X'03' 267 // o IP V6 address: X'04' 268 // o DST.ADDR desired destination address 269 // o DST.PORT desired destination port in network octet 270 // order 271 272 // The SOCKS server will typically evaluate the request based on source 273 // and destination addresses, and return one or more reply messages, as 274 // appropriate for the request type. 275 276 // 5. Addressing 277 278 // In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies 279 // the type of address contained within the field: 280 281 // o X'01' 282 283 // the address is a version-4 IP address, with a length of 4 octets 284 285 // o X'03' 286 287 // the address field contains a fully-qualified domain name. The first 288 // octet of the address field contains the number of octets of name that 289 // follow, there is no terminating NUL octet. 290 291 // o X'04' 292 293 // the address is a version-6 IP address, with a length of 16 octets. 294 295 // 6. Replies 296 // The SOCKS request information is sent by the client as soon as it has 297 // established a connection to the SOCKS server, and completed the 298 // authentication negotiations. The server evaluates the request, and 299 // returns a reply formed as follows: 300 301 // +----+-----+-------+------+----------+----------+ 302 // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 303 // +----+-----+-------+------+----------+----------+ 304 // | 1 | 1 | X'00' | 1 | Variable | 2 | 305 // +----+-----+-------+------+----------+----------+ 306 307 // Where: 308 309 // o VER protocol version: X'05' 310 // o REP Reply field: 311 // o X'00' succeeded 312 // o X'01' general SOCKS server failure 313 // o X'02' connection not allowed by ruleset 314 // o X'03' Network unreachable 315 // o X'04' Host unreachable 316 // o X'05' Connection refused 317 // o X'06' TTL expired 318 // o X'07' Command not supported 319 // o X'08' Address type not supported 320 // o X'09' to X'FF' unassigned 321 // o RSV RESERVED 322 // o ATYP address type of following address 323 // o IP V4 address: X'01' 324 // o DOMAINNAME: X'03' 325 // o IP V6 address: X'04' 326 // o BND.ADDR server bound address 327 // o BND.PORT server bound port in network octet order 328 329 // Fields marked RESERVED (RSV) must be set to X'00'. 330 331 // If the chosen method includes encapsulation for purposes of 332 // authentication, integrity and/or confidentiality, the replies are 333 // encapsulated in the method-dependent encapsulation. 334 335 // CONNECT 336 337 // In the reply to a CONNECT, BND.PORT contains the port number that the 338 // server assigned to connect to the target host, while BND.ADDR 339 // contains the associated IP address. The supplied BND.ADDR is often 340 // different from the IP address that the client uses to reach the SOCKS 341 // server, since such servers are often multi-homed. It is expected 342 // that the SOCKS server will use DST.ADDR and DST.PORT, and the 343 // client-side source address and port in evaluating the CONNECT 344 // request. 345 346 // BIND 347 348 // The BIND request is used in protocols which require the client to 349 // accept connections from the server. FTP is a well-known example, 350 // which uses the primary client-to-server connection for commands and 351 // status reports, but may use a server-to-client connection for 352 // transferring data on demand (e.g. LS, GET, PUT). 353 354 // It is expected that the client side of an application protocol will 355 // use the BIND request only to establish secondary connections after a 356 // primary connection is established using CONNECT. In is expected that 357 // a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND 358 // request. 359 360 // Two replies are sent from the SOCKS server to the client during a 361 // BIND operation. The first is sent after the server creates and binds 362 // a new socket. The BND.PORT field contains the port number that the 363 // SOCKS server assigned to listen for an incoming connection. The 364 // BND.ADDR field contains the associated IP address. The client will 365 // typically use these pieces of information to notify (via the primary 366 // or control connection) the application server of the rendezvous 367 // address. The second reply occurs only after the anticipated incoming 368 // connection succeeds or fails. 369 370 // In the second reply, the BND.PORT and BND.ADDR fields contain the 371 // address and port number of the connecting host. 372 373 // UDP ASSOCIATE 374 375 // The UDP ASSOCIATE request is used to establish an association within 376 // the UDP relay process to handle UDP datagrams. The DST.ADDR and 377 // DST.PORT fields contain the address and port that the client expects 378 // to use to send UDP datagrams on for the association. The server MAY 379 // use this information to limit access to the association. If the 380 // client is not in possession of the information at the time of the UDP 381 // ASSOCIATE, the client MUST use a port number and address of all 382 // zeros. 383 384 // A UDP association terminates when the TCP connection that the UDP 385 // ASSOCIATE request arrived on terminates. 386 387 // In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR 388 // fields indicate the port number/address where the client MUST send 389 // UDP request messages to be relayed. 390 391 // Reply Processing 392 393 // When a reply (REP value other than X'00') indicates a failure, the 394 // SOCKS server MUST terminate the TCP connection shortly after sending 395 // the reply. This must be no more than 10 seconds after detecting the 396 // condition that caused a failure. 397 398 // If the reply code (REP value of X'00') indicates a success, and the 399 // request was either a BIND or a CONNECT, the client may now start 400 // passing data. If the selected authentication method supports 401 // encapsulation for the purposes of integrity, authentication and/or 402 // confidentiality, the data are encapsulated using the method-dependent 403 // encapsulation. Similarly, when data arrives at the SOCKS server for 404 // the client, the server MUST encapsulate the data as appropriate for 405 // the authentication method in use.