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