github.com/v2fly/v2ray-core/v4@v4.45.2/proxy/socks/protocol.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package socks 5 6 import ( 7 "encoding/binary" 8 "io" 9 10 "github.com/v2fly/v2ray-core/v4/common" 11 "github.com/v2fly/v2ray-core/v4/common/buf" 12 "github.com/v2fly/v2ray-core/v4/common/net" 13 "github.com/v2fly/v2ray-core/v4/common/protocol" 14 ) 15 16 const ( 17 socks5Version = 0x05 18 socks4Version = 0x04 19 20 cmdTCPConnect = 0x01 21 cmdTCPBind = 0x02 22 cmdUDPAssociate = 0x03 23 cmdTorResolve = 0xF0 24 cmdTorResolvePTR = 0xF1 25 26 socks4RequestGranted = 90 27 socks4RequestRejected = 91 28 29 authNotRequired = 0x00 30 // authGssAPI = 0x01 31 authPassword = 0x02 32 authNoMatchingMethod = 0xFF 33 34 statusSuccess = 0x00 35 statusCmdNotSupport = 0x07 36 ) 37 38 var addrParser = protocol.NewAddressParser( 39 protocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4), 40 protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6), 41 protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain), 42 ) 43 44 type ServerSession struct { 45 config *ServerConfig 46 address net.Address 47 port net.Port 48 clientAddress net.Address 49 } 50 51 func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { 52 if s.config.AuthType == AuthType_PASSWORD { 53 writeSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0)) 54 return nil, newError("socks 4 is not allowed when auth is required.") 55 } 56 57 var port net.Port 58 var address net.Address 59 60 { 61 buffer := buf.StackNew() 62 if _, err := buffer.ReadFullFrom(reader, 6); err != nil { 63 buffer.Release() 64 return nil, newError("insufficient header").Base(err) 65 } 66 port = net.PortFromBytes(buffer.BytesRange(0, 2)) 67 address = net.IPAddress(buffer.BytesRange(2, 6)) 68 buffer.Release() 69 } 70 71 if _, err := ReadUntilNull(reader); /* user id */ err != nil { 72 return nil, err 73 } 74 if address.IP()[0] == 0x00 { 75 domain, err := ReadUntilNull(reader) 76 if err != nil { 77 return nil, newError("failed to read domain for socks 4a").Base(err) 78 } 79 address = net.DomainAddress(domain) 80 } 81 82 switch cmd { 83 case cmdTCPConnect: 84 request := &protocol.RequestHeader{ 85 Command: protocol.RequestCommandTCP, 86 Address: address, 87 Port: port, 88 Version: socks4Version, 89 } 90 if err := writeSocks4Response(writer, socks4RequestGranted, net.AnyIP, net.Port(0)); err != nil { 91 return nil, err 92 } 93 return request, nil 94 default: 95 writeSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0)) 96 return nil, newError("unsupported command: ", cmd) 97 } 98 } 99 100 func (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer) (username string, err error) { 101 buffer := buf.StackNew() 102 defer buffer.Release() 103 104 if _, err = buffer.ReadFullFrom(reader, int32(nMethod)); err != nil { 105 return "", newError("failed to read auth methods").Base(err) 106 } 107 108 var expectedAuth byte = authNotRequired 109 if s.config.AuthType == AuthType_PASSWORD { 110 expectedAuth = authPassword 111 } 112 113 if !hasAuthMethod(expectedAuth, buffer.BytesRange(0, int32(nMethod))) { 114 writeSocks5AuthenticationResponse(writer, socks5Version, authNoMatchingMethod) 115 return "", newError("no matching auth method") 116 } 117 118 if err := writeSocks5AuthenticationResponse(writer, socks5Version, expectedAuth); err != nil { 119 return "", newError("failed to write auth response").Base(err) 120 } 121 122 if expectedAuth == authPassword { 123 username, password, err := ReadUsernamePassword(reader) 124 if err != nil { 125 return "", newError("failed to read username and password for authentication").Base(err) 126 } 127 128 if !s.config.HasAccount(username, password) { 129 writeSocks5AuthenticationResponse(writer, 0x01, 0xFF) 130 return "", newError("invalid username or password") 131 } 132 133 if err := writeSocks5AuthenticationResponse(writer, 0x01, 0x00); err != nil { 134 return "", newError("failed to write auth response").Base(err) 135 } 136 return username, nil 137 } 138 139 return "", nil 140 } 141 142 func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { 143 var ( 144 username string 145 err error 146 ) 147 if username, err = s.auth5(nMethod, reader, writer); err != nil { 148 return nil, err 149 } 150 151 var cmd byte 152 { 153 buffer := buf.StackNew() 154 if _, err := buffer.ReadFullFrom(reader, 3); err != nil { 155 buffer.Release() 156 return nil, newError("failed to read request").Base(err) 157 } 158 cmd = buffer.Byte(1) 159 buffer.Release() 160 } 161 162 request := new(protocol.RequestHeader) 163 if username != "" { 164 request.User = &protocol.MemoryUser{Email: username} 165 } 166 switch cmd { 167 case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR: 168 // We don't have a solution for Tor case now. Simply treat it as connect command. 169 request.Command = protocol.RequestCommandTCP 170 case cmdUDPAssociate: 171 if !s.config.UdpEnabled { 172 writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) 173 return nil, newError("UDP is not enabled.") 174 } 175 request.Command = protocol.RequestCommandUDP 176 case cmdTCPBind: 177 writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) 178 return nil, newError("TCP bind is not supported.") 179 default: 180 writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) 181 return nil, newError("unknown command ", cmd) 182 } 183 184 request.Version = socks5Version 185 186 addr, port, err := addrParser.ReadAddressPort(nil, reader) 187 if err != nil { 188 return nil, newError("failed to read address").Base(err) 189 } 190 request.Address = addr 191 request.Port = port 192 193 responseAddress := s.address 194 responsePort := s.port 195 //nolint:gocritic // Use if else chain for clarity 196 if request.Command == protocol.RequestCommandUDP { 197 if s.config.Address != nil { 198 // Use configured IP as remote address in the response to UdpAssociate 199 responseAddress = s.config.Address.AsAddress() 200 } else if s.clientAddress == net.LocalHostIP || s.clientAddress == net.LocalHostIPv6 { 201 // For localhost clients use loopback IP 202 responseAddress = s.clientAddress 203 } else { 204 // For non-localhost clients use inbound listening address 205 responseAddress = s.address 206 } 207 } 208 if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil { 209 return nil, err 210 } 211 212 return request, nil 213 } 214 215 // Handshake performs a Socks4/4a/5 handshake. 216 func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { 217 buffer := buf.StackNew() 218 if _, err := buffer.ReadFullFrom(reader, 2); err != nil { 219 buffer.Release() 220 return nil, newError("insufficient header").Base(err) 221 } 222 223 version := buffer.Byte(0) 224 cmd := buffer.Byte(1) 225 buffer.Release() 226 227 switch version { 228 case socks4Version: 229 return s.handshake4(cmd, reader, writer) 230 case socks5Version: 231 return s.handshake5(cmd, reader, writer) 232 default: 233 return nil, newError("unknown Socks version: ", version) 234 } 235 } 236 237 // ReadUsernamePassword reads Socks 5 username/password message from the given reader. 238 // +----+------+----------+------+----------+ 239 // |VER | ULEN | UNAME | PLEN | PASSWD | 240 // +----+------+----------+------+----------+ 241 // | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 242 // +----+------+----------+------+----------+ 243 func ReadUsernamePassword(reader io.Reader) (string, string, error) { 244 buffer := buf.StackNew() 245 defer buffer.Release() 246 247 if _, err := buffer.ReadFullFrom(reader, 2); err != nil { 248 return "", "", err 249 } 250 nUsername := int32(buffer.Byte(1)) 251 252 buffer.Clear() 253 if _, err := buffer.ReadFullFrom(reader, nUsername); err != nil { 254 return "", "", err 255 } 256 username := buffer.String() 257 258 buffer.Clear() 259 if _, err := buffer.ReadFullFrom(reader, 1); err != nil { 260 return "", "", err 261 } 262 nPassword := int32(buffer.Byte(0)) 263 264 buffer.Clear() 265 if _, err := buffer.ReadFullFrom(reader, nPassword); err != nil { 266 return "", "", err 267 } 268 password := buffer.String() 269 return username, password, nil 270 } 271 272 // ReadUntilNull reads content from given reader, until a null (0x00) byte. 273 func ReadUntilNull(reader io.Reader) (string, error) { 274 b := buf.StackNew() 275 defer b.Release() 276 277 for { 278 _, err := b.ReadFullFrom(reader, 1) 279 if err != nil { 280 return "", err 281 } 282 if b.Byte(b.Len()-1) == 0x00 { 283 b.Resize(0, b.Len()-1) 284 return b.String(), nil 285 } 286 if b.IsFull() { 287 return "", newError("buffer overrun") 288 } 289 } 290 } 291 292 func hasAuthMethod(expectedAuth byte, authCandidates []byte) bool { 293 for _, a := range authCandidates { 294 if a == expectedAuth { 295 return true 296 } 297 } 298 return false 299 } 300 301 func writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte) error { 302 return buf.WriteAllBytes(writer, []byte{version, auth}) 303 } 304 305 func writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error { 306 buffer := buf.New() 307 defer buffer.Release() 308 309 common.Must2(buffer.Write([]byte{socks5Version, errCode, 0x00 /* reserved */})) 310 if err := addrParser.WriteAddressPort(buffer, address, port); err != nil { 311 return err 312 } 313 314 return buf.WriteAllBytes(writer, buffer.Bytes()) 315 } 316 317 func writeSocks4Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error { 318 buffer := buf.StackNew() 319 defer buffer.Release() 320 321 common.Must(buffer.WriteByte(0x00)) 322 common.Must(buffer.WriteByte(errCode)) 323 portBytes := buffer.Extend(2) 324 binary.BigEndian.PutUint16(portBytes, port.Value()) 325 common.Must2(buffer.Write(address.IP())) 326 return buf.WriteAllBytes(writer, buffer.Bytes()) 327 } 328 329 func DecodeUDPPacket(packet *buf.Buffer) (*protocol.RequestHeader, error) { 330 if packet.Len() < 5 { 331 return nil, newError("insufficient length of packet.") 332 } 333 request := &protocol.RequestHeader{ 334 Version: socks5Version, 335 Command: protocol.RequestCommandUDP, 336 } 337 338 // packet[0] and packet[1] are reserved 339 if packet.Byte(2) != 0 /* fragments */ { 340 return nil, newError("discarding fragmented payload.") 341 } 342 343 packet.Advance(3) 344 345 addr, port, err := addrParser.ReadAddressPort(nil, packet) 346 if err != nil { 347 return nil, newError("failed to read UDP header").Base(err) 348 } 349 request.Address = addr 350 request.Port = port 351 return request, nil 352 } 353 354 func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer, error) { 355 b := buf.New() 356 common.Must2(b.Write([]byte{0, 0, 0 /* Fragment */})) 357 if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil { 358 b.Release() 359 return nil, err 360 } 361 common.Must2(b.Write(data)) 362 return b, nil 363 } 364 365 type UDPReader struct { 366 reader io.Reader 367 } 368 369 func NewUDPReader(reader io.Reader) *UDPReader { 370 return &UDPReader{reader: reader} 371 } 372 373 func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) { 374 b := buf.New() 375 if _, err := b.ReadFrom(r.reader); err != nil { 376 return nil, err 377 } 378 if _, err := DecodeUDPPacket(b); err != nil { 379 return nil, err 380 } 381 return buf.MultiBuffer{b}, nil 382 } 383 384 type UDPWriter struct { 385 request *protocol.RequestHeader 386 writer io.Writer 387 } 388 389 func NewUDPWriter(request *protocol.RequestHeader, writer io.Writer) *UDPWriter { 390 return &UDPWriter{ 391 request: request, 392 writer: writer, 393 } 394 } 395 396 // Write implements io.Writer. 397 func (w *UDPWriter) Write(b []byte) (int, error) { 398 eb, err := EncodeUDPPacket(w.request, b) 399 if err != nil { 400 return 0, err 401 } 402 defer eb.Release() 403 if _, err := w.writer.Write(eb.Bytes()); err != nil { 404 return 0, err 405 } 406 return len(b), nil 407 } 408 409 func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { 410 authByte := byte(authNotRequired) 411 if request.User != nil { 412 authByte = byte(authPassword) 413 } 414 415 b := buf.New() 416 defer b.Release() 417 418 common.Must2(b.Write([]byte{socks5Version, 0x01, authByte})) 419 if authByte == authPassword { 420 account := request.User.Account.(*Account) 421 422 common.Must(b.WriteByte(0x01)) 423 common.Must(b.WriteByte(byte(len(account.Username)))) 424 common.Must2(b.WriteString(account.Username)) 425 common.Must(b.WriteByte(byte(len(account.Password)))) 426 common.Must2(b.WriteString(account.Password)) 427 } 428 429 if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil { 430 return nil, err 431 } 432 433 b.Clear() 434 if _, err := b.ReadFullFrom(reader, 2); err != nil { 435 return nil, err 436 } 437 438 if b.Byte(0) != socks5Version { 439 return nil, newError("unexpected server version: ", b.Byte(0)).AtWarning() 440 } 441 if b.Byte(1) != authByte { 442 return nil, newError("auth method not supported.").AtWarning() 443 } 444 445 if authByte == authPassword { 446 b.Clear() 447 if _, err := b.ReadFullFrom(reader, 2); err != nil { 448 return nil, err 449 } 450 if b.Byte(1) != 0x00 { 451 return nil, newError("server rejects account: ", b.Byte(1)) 452 } 453 } 454 455 b.Clear() 456 457 command := byte(cmdTCPConnect) 458 if request.Command == protocol.RequestCommandUDP { 459 command = byte(cmdUDPAssociate) 460 } 461 common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */})) 462 if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil { 463 return nil, err 464 } 465 466 if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil { 467 return nil, err 468 } 469 470 b.Clear() 471 if _, err := b.ReadFullFrom(reader, 3); err != nil { 472 return nil, err 473 } 474 475 resp := b.Byte(1) 476 if resp != 0x00 { 477 return nil, newError("server rejects request: ", resp) 478 } 479 480 b.Clear() 481 482 address, port, err := addrParser.ReadAddressPort(b, reader) 483 if err != nil { 484 return nil, err 485 } 486 487 if request.Command == protocol.RequestCommandUDP { 488 udpRequest := &protocol.RequestHeader{ 489 Version: socks5Version, 490 Command: protocol.RequestCommandUDP, 491 Address: address, 492 Port: port, 493 } 494 return udpRequest, nil 495 } 496 497 return nil, nil 498 }