nsSOCKSIOLayer.cpp (47741B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set expandtab ts=4 sw=2 sts=2 cin: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "nspr.h" 8 #include "private/pprio.h" 9 #include "nsString.h" 10 #include "nsCRT.h" 11 12 #include "nsIDNSService.h" 13 #include "nsIDNSRecord.h" 14 #include "nsISocketProvider.h" 15 #include "nsNamedPipeIOLayer.h" 16 #include "nsSOCKSIOLayer.h" 17 #include "nsNetCID.h" 18 #include "nsIDNSListener.h" 19 #include "nsICancelable.h" 20 #include "nsThreadUtils.h" 21 #include "nsIFile.h" 22 #include "nsIFileProtocolHandler.h" 23 #include "mozilla/Components.h" 24 #include "mozilla/Logging.h" 25 #include "mozilla/net/DNS.h" 26 27 #include "IOnionAliasService.h" 28 29 using mozilla::LogLevel; 30 using namespace mozilla::net; 31 32 static PRDescIdentity nsSOCKSIOLayerIdentity; 33 static PRIOMethods nsSOCKSIOLayerMethods; 34 static bool firstTime = true; 35 static bool ipv6Supported = true; 36 37 static mozilla::LazyLogModule gSOCKSLog("SOCKS"); 38 #define LOGDEBUG(args) MOZ_LOG(gSOCKSLog, mozilla::LogLevel::Debug, args) 39 #define LOGERROR(args) MOZ_LOG(gSOCKSLog, mozilla::LogLevel::Error, args) 40 41 class nsSOCKSSocketInfo : public nsIDNSListener { 42 enum State { 43 SOCKS_INITIAL, 44 SOCKS_DNS_IN_PROGRESS, 45 SOCKS_DNS_COMPLETE, 46 SOCKS_CONNECTING_TO_PROXY, 47 SOCKS4_WRITE_CONNECT_REQUEST, 48 SOCKS4_READ_CONNECT_RESPONSE, 49 SOCKS5_WRITE_AUTH_REQUEST, 50 SOCKS5_READ_AUTH_RESPONSE, 51 SOCKS5_WRITE_USERNAME_REQUEST, 52 SOCKS5_READ_USERNAME_RESPONSE, 53 SOCKS5_WRITE_CONNECT_REQUEST, 54 SOCKS5_READ_CONNECT_RESPONSE_TOP, 55 SOCKS5_READ_CONNECT_RESPONSE_BOTTOM, 56 SOCKS_CONNECTED, 57 SOCKS_FAILED 58 }; 59 60 // A buffer of 520 bytes should be enough for any request and response 61 // in case of SOCKS4 as well as SOCKS5 62 static const uint32_t BUFFER_SIZE = 520; 63 static const uint32_t MAX_HOSTNAME_LEN = 255; 64 static const uint32_t MAX_USERNAME_LEN = 255; 65 static const uint32_t MAX_PASSWORD_LEN = 255; 66 67 public: 68 nsSOCKSSocketInfo(); 69 70 NS_DECL_THREADSAFE_ISUPPORTS 71 NS_DECL_NSIDNSLISTENER 72 73 void Init(int32_t version, int32_t family, nsIProxyInfo* proxy, 74 const char* destinationHost, uint32_t flags, uint32_t tlsFlags); 75 76 void SetConnectTimeout(PRIntervalTime to); 77 PRStatus DoHandshake(PRFileDesc* fd, int16_t oflags = -1); 78 int16_t GetPollFlags() const; 79 bool IsConnected() const { return mState == SOCKS_CONNECTED; } 80 void ForgetFD() { mFD = nullptr; } 81 void SetNamedPipeFD(PRFileDesc* fd) { mFD = fd; } 82 83 void GetExternalProxyAddr(NetAddr& aExternalProxyAddr); 84 void GetDestinationAddr(NetAddr& aDestinationAddr); 85 void SetDestinationAddr(const NetAddr& aDestinationAddr); 86 87 private: 88 virtual ~nsSOCKSSocketInfo() { 89 ForgetFD(); 90 HandshakeFinished(); 91 } 92 93 void HandshakeFinished(PRErrorCode err = 0); 94 PRStatus StartDNS(PRFileDesc* fd); 95 PRStatus ConnectToProxy(PRFileDesc* fd); 96 void FixupAddressFamily(PRFileDesc* fd, NetAddr* proxy); 97 PRStatus ContinueConnectingToProxy(PRFileDesc* fd, int16_t oflags); 98 PRStatus WriteV4ConnectRequest(); 99 PRStatus ReadV4ConnectResponse(); 100 PRStatus WriteV5AuthRequest(); 101 PRStatus ReadV5AuthResponse(); 102 PRStatus WriteV5UsernameRequest(); 103 PRStatus ReadV5UsernameResponse(); 104 PRStatus WriteV5ConnectRequest(); 105 PRStatus ReadV5AddrTypeAndLength(uint8_t* type, uint32_t* len); 106 PRStatus ReadV5ConnectResponseTop(); 107 PRStatus ReadV5ConnectResponseBottom(); 108 109 uint8_t ReadUint8(); 110 uint16_t ReadUint16(); 111 uint32_t ReadUint32(); 112 void ReadNetAddr(NetAddr* addr, uint16_t fam); 113 void ReadNetPort(NetAddr* addr); 114 115 void WantRead(uint32_t sz); 116 PRStatus ReadFromSocket(PRFileDesc* fd); 117 PRStatus WriteToSocket(PRFileDesc* fd); 118 119 bool IsLocalProxy() { 120 nsAutoCString proxyHost; 121 mProxy->GetHost(proxyHost); 122 return IsHostLocalTarget(proxyHost); 123 } 124 125 nsresult SetLocalProxyPath(const nsACString& aLocalProxyPath, 126 NetAddr* aProxyAddr) { 127 #ifdef XP_UNIX 128 nsresult rv; 129 MOZ_ASSERT(aProxyAddr); 130 131 nsCOMPtr<nsIProtocolHandler> protocolHandler( 132 mozilla::components::FileProtocolHandler::Service(&rv)); 133 if (NS_WARN_IF(NS_FAILED(rv))) { 134 return rv; 135 } 136 137 nsCOMPtr<nsIFileProtocolHandler> fileHandler( 138 do_QueryInterface(protocolHandler, &rv)); 139 if (NS_WARN_IF(NS_FAILED(rv))) { 140 return rv; 141 } 142 143 nsCOMPtr<nsIFile> socketFile; 144 rv = fileHandler->GetFileFromURLSpec(aLocalProxyPath, 145 getter_AddRefs(socketFile)); 146 if (NS_WARN_IF(NS_FAILED(rv))) { 147 return rv; 148 } 149 150 nsAutoCString path; 151 if (NS_WARN_IF(NS_FAILED(rv = socketFile->GetNativePath(path)))) { 152 return rv; 153 } 154 155 if (sizeof(aProxyAddr->local.path) <= path.Length()) { 156 NS_WARNING("domain socket path too long."); 157 return NS_ERROR_FAILURE; 158 } 159 160 aProxyAddr->raw.family = AF_UNIX; 161 strcpy(aProxyAddr->local.path, path.get()); 162 163 return NS_OK; 164 #elif defined(XP_WIN) 165 MOZ_ASSERT(aProxyAddr); 166 167 if (sizeof(aProxyAddr->local.path) <= aLocalProxyPath.Length()) { 168 NS_WARNING("pipe path too long."); 169 return NS_ERROR_FAILURE; 170 } 171 172 aProxyAddr->raw.family = AF_LOCAL; 173 strcpy(aProxyAddr->local.path, PromiseFlatCString(aLocalProxyPath).get()); 174 return NS_OK; 175 #else 176 (void)aLocalProxyPath; 177 (void)aProxyAddr; 178 return NS_ERROR_NOT_IMPLEMENTED; 179 #endif 180 } 181 182 bool SetupNamedPipeLayer(PRFileDesc* fd) { 183 #if defined(XP_WIN) 184 if (IsLocalProxy()) { 185 // nsSOCKSIOLayer handshaking only works under blocking mode 186 // unfortunately. Remember named pipe's FD to switch between modes. 187 SetNamedPipeFD(fd->lower); 188 return true; 189 } 190 #endif 191 return false; 192 } 193 194 private: 195 State mState{SOCKS_INITIAL}; 196 uint8_t* mData{nullptr}; 197 uint8_t* mDataIoPtr{nullptr}; 198 uint32_t mDataLength{0}; 199 uint32_t mReadOffset{0}; 200 uint32_t mAmountToRead{0}; 201 nsCOMPtr<nsIDNSRecord> mDnsRec; 202 nsCOMPtr<nsICancelable> mLookup; 203 nsresult mLookupStatus{NS_ERROR_NOT_INITIALIZED}; 204 PRFileDesc* mFD{nullptr}; 205 206 nsCString mDestinationHost; 207 nsCOMPtr<nsIProxyInfo> mProxy; 208 int32_t mVersion{-1}; // SOCKS version 4 or 5 209 int32_t mDestinationFamily{AF_INET}; 210 uint32_t mFlags{0}; 211 uint32_t mTlsFlags{0}; 212 NetAddr mInternalProxyAddr; 213 NetAddr mExternalProxyAddr; 214 NetAddr mDestinationAddr; 215 PRIntervalTime mTimeout{PR_INTERVAL_NO_TIMEOUT}; 216 nsCString mProxyUsername; // Cache, from mProxy 217 }; 218 219 nsSOCKSSocketInfo::nsSOCKSSocketInfo() { 220 mData = new uint8_t[BUFFER_SIZE]; 221 222 mInternalProxyAddr.raw.family = AF_INET; 223 mInternalProxyAddr.inet.ip = htonl(INADDR_ANY); 224 mInternalProxyAddr.inet.port = htons(0); 225 226 mExternalProxyAddr.raw.family = AF_INET; 227 mExternalProxyAddr.inet.ip = htonl(INADDR_ANY); 228 mExternalProxyAddr.inet.port = htons(0); 229 230 mDestinationAddr.raw.family = AF_INET; 231 mDestinationAddr.inet.ip = htonl(INADDR_ANY); 232 mDestinationAddr.inet.port = htons(0); 233 } 234 235 /* Helper template class to statically check that writes to a fixed-size 236 * buffer are not going to overflow. 237 * 238 * Example usage: 239 * uint8_t real_buf[TOTAL_SIZE]; 240 * Buffer<TOTAL_SIZE> buf(&real_buf); 241 * auto buf2 = buf.WriteUint16(1); 242 * auto buf3 = buf2.WriteUint8(2); 243 * 244 * It is possible to chain them, to limit the number of (error-prone) 245 * intermediate variables: 246 * auto buf = Buffer<TOTAL_SIZE>(&real_buf) 247 * .WriteUint16(1) 248 * .WriteUint8(2); 249 * 250 * Debug builds assert when intermediate variables are reused: 251 * Buffer<TOTAL_SIZE> buf(&real_buf); 252 * auto buf2 = buf.WriteUint16(1); 253 * auto buf3 = buf.WriteUint8(2); // Asserts 254 * 255 * Strings can be written, given an explicit maximum length. 256 * buf.WriteString<MAX_STRING_LENGTH>(str); 257 * 258 * The Written() method returns how many bytes have been written so far: 259 * Buffer<TOTAL_SIZE> buf(&real_buf); 260 * auto buf2 = buf.WriteUint16(1); 261 * auto buf3 = buf2.WriteUint8(2); 262 * buf3.Written(); // returns 3. 263 */ 264 template <size_t Size> 265 class Buffer { 266 public: 267 Buffer() = default; 268 269 explicit Buffer(uint8_t* aBuf, size_t aLength = 0) 270 : mBuf(aBuf), mLength(aLength) {} 271 272 template <size_t Size2> 273 MOZ_IMPLICIT Buffer(const Buffer<Size2>& aBuf) 274 : mBuf(aBuf.mBuf), mLength(aBuf.mLength) { 275 static_assert(Size2 > Size, "Cannot cast buffer"); 276 } 277 278 Buffer<Size - sizeof(uint8_t)> WriteUint8(uint8_t aValue) { 279 return Write(aValue); 280 } 281 282 Buffer<Size - sizeof(uint16_t)> WriteUint16(uint16_t aValue) { 283 return Write(aValue); 284 } 285 286 Buffer<Size - sizeof(uint32_t)> WriteUint32(uint32_t aValue) { 287 return Write(aValue); 288 } 289 290 Buffer<Size - sizeof(uint16_t)> WriteNetPort(const NetAddr* aAddr) { 291 return WriteUint16(aAddr->inet.port); 292 } 293 294 Buffer<Size - sizeof(IPv6Addr)> WriteNetAddr(const NetAddr* aAddr) { 295 if (aAddr->raw.family == AF_INET) { 296 return Write(aAddr->inet.ip); 297 } 298 if (aAddr->raw.family == AF_INET6) { 299 return Write(aAddr->inet6.ip.u8); 300 } 301 MOZ_ASSERT_UNREACHABLE("Unknown address family"); 302 return *this; 303 } 304 305 template <size_t MaxLength> 306 Buffer<Size - MaxLength> WriteString(const nsACString& aStr) { 307 if (aStr.Length() > MaxLength) { 308 return Buffer<Size - MaxLength>(nullptr); 309 } 310 return WritePtr<char, MaxLength>(aStr.Data(), aStr.Length()); 311 } 312 313 size_t Written() { 314 MOZ_ASSERT(mBuf); 315 return mLength; 316 } 317 318 explicit operator bool() { return !!mBuf; } 319 320 private: 321 template <size_t Size2> 322 friend class Buffer; 323 324 template <typename T> 325 Buffer<Size - sizeof(T)> Write(T& aValue) { 326 return WritePtr<T, sizeof(T)>(&aValue, sizeof(T)); 327 } 328 329 template <typename T, size_t Length> 330 Buffer<Size - Length> WritePtr(const T* aValue, size_t aCopyLength) { 331 static_assert(Size >= Length, "Cannot write that much"); 332 MOZ_ASSERT(aCopyLength <= Length); 333 MOZ_ASSERT(mBuf); 334 memcpy(mBuf, aValue, aCopyLength); 335 Buffer<Size - Length> result(mBuf + aCopyLength, mLength + aCopyLength); 336 mBuf = nullptr; 337 mLength = 0; 338 return result; 339 } 340 341 uint8_t* mBuf{nullptr}; 342 size_t mLength{0}; 343 }; 344 345 void nsSOCKSSocketInfo::Init(int32_t version, int32_t family, 346 nsIProxyInfo* proxy, const char* host, 347 uint32_t flags, uint32_t tlsFlags) { 348 mVersion = version; 349 mDestinationFamily = family; 350 mProxy = proxy; 351 mDestinationHost = host; 352 mFlags = flags; 353 mTlsFlags = tlsFlags; 354 mProxy->GetUsername(mProxyUsername); // cache 355 } 356 357 NS_IMPL_ISUPPORTS(nsSOCKSSocketInfo, nsIDNSListener) 358 359 void nsSOCKSSocketInfo::GetExternalProxyAddr(NetAddr& aExternalProxyAddr) { 360 aExternalProxyAddr = mExternalProxyAddr; 361 } 362 363 void nsSOCKSSocketInfo::GetDestinationAddr(NetAddr& aDestinationAddr) { 364 aDestinationAddr = mDestinationAddr; 365 } 366 367 void nsSOCKSSocketInfo::SetDestinationAddr(const NetAddr& aDestinationAddr) { 368 mDestinationAddr = aDestinationAddr; 369 } 370 371 // There needs to be a means of distinguishing between connection errors 372 // that the SOCKS server reports when it rejects a connection request, and 373 // connection errors that happen while attempting to connect to the SOCKS 374 // server. Otherwise, Firefox will report incorrectly that the proxy server 375 // is refusing connections when a SOCKS request is rejected by the proxy. 376 // When a SOCKS handshake failure occurs, the PR error is set to 377 // PR_UNKNOWN_ERROR, and the real error code is returned via the OS error. 378 void nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err) { 379 if (err == 0) { 380 mState = SOCKS_CONNECTED; 381 #if defined(XP_WIN) 382 // Switch back to nonblocking mode after finishing handshaking. 383 if (IsLocalProxy() && mFD) { 384 PRSocketOptionData opt_nonblock; 385 opt_nonblock.option = PR_SockOpt_Nonblocking; 386 opt_nonblock.value.non_blocking = PR_TRUE; 387 PR_SetSocketOption(mFD, &opt_nonblock); 388 mFD = nullptr; 389 } 390 #endif 391 } else { 392 mState = SOCKS_FAILED; 393 PR_SetError(PR_UNKNOWN_ERROR, err); 394 } 395 396 // We don't need the buffer any longer, so free it. 397 delete[] mData; 398 mData = nullptr; 399 mDataIoPtr = nullptr; 400 mDataLength = 0; 401 mReadOffset = 0; 402 mAmountToRead = 0; 403 if (mLookup) { 404 mLookup->Cancel(NS_ERROR_FAILURE); 405 mLookup = nullptr; 406 } 407 } 408 409 PRStatus nsSOCKSSocketInfo::StartDNS(PRFileDesc* fd) { 410 MOZ_ASSERT(!mDnsRec && mState == SOCKS_INITIAL, 411 "Must be in initial state to make DNS Lookup"); 412 413 nsCOMPtr<nsIDNSService> dns; 414 dns = mozilla::components::DNS::Service(); 415 if (!dns) return PR_FAILURE; 416 417 nsCString proxyHost; 418 mProxy->GetHost(proxyHost); 419 420 mozilla::OriginAttributes attrs; 421 422 mFD = fd; 423 nsresult rv = dns->AsyncResolveNative( 424 proxyHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, 425 nsIDNSService::RESOLVE_IGNORE_SOCKS_DNS, nullptr, this, 426 mozilla::GetCurrentSerialEventTarget(), attrs, getter_AddRefs(mLookup)); 427 428 if (NS_FAILED(rv)) { 429 LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed", proxyHost.get())); 430 return PR_FAILURE; 431 } 432 mState = SOCKS_DNS_IN_PROGRESS; 433 PR_SetError(PR_IN_PROGRESS_ERROR, 0); 434 return PR_FAILURE; 435 } 436 437 NS_IMETHODIMP 438 nsSOCKSSocketInfo::OnLookupComplete(nsICancelable* aRequest, 439 nsIDNSRecord* aRecord, nsresult aStatus) { 440 MOZ_ASSERT(aRequest == mLookup, "wrong DNS query"); 441 mLookup = nullptr; 442 mLookupStatus = aStatus; 443 mDnsRec = aRecord; 444 mState = SOCKS_DNS_COMPLETE; 445 if (mFD) { 446 ConnectToProxy(mFD); 447 ForgetFD(); 448 } 449 return NS_OK; 450 } 451 452 PRStatus nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc* fd) { 453 PRStatus status; 454 nsresult rv; 455 456 MOZ_ASSERT(mState == SOCKS_DNS_COMPLETE, "Must have DNS to make connection!"); 457 458 if (NS_FAILED(mLookupStatus)) { 459 PR_SetError(PR_BAD_ADDRESS_ERROR, 0); 460 return PR_FAILURE; 461 } 462 463 // Try socks5 if the destination addrress is IPv6 464 if (mVersion == 4 && mDestinationAddr.raw.family == AF_INET6) { 465 mVersion = 5; 466 } 467 468 nsAutoCString proxyHost; 469 mProxy->GetHost(proxyHost); 470 471 int32_t proxyPort; 472 mProxy->GetPort(&proxyPort); 473 474 int32_t addresses = 0; 475 do { 476 if (IsLocalProxy()) { 477 rv = SetLocalProxyPath(proxyHost, &mInternalProxyAddr); 478 if (NS_FAILED(rv)) { 479 LOGERROR( 480 ("socks: unable to connect to SOCKS proxy, %s", proxyHost.get())); 481 return PR_FAILURE; 482 } 483 } else { 484 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(mDnsRec); 485 MOZ_ASSERT(record); 486 if (addresses++) { 487 record->ReportUnusable(proxyPort); 488 } 489 490 rv = record->GetNextAddr(proxyPort, &mInternalProxyAddr); 491 // No more addresses to try? If so, we'll need to bail 492 if (NS_FAILED(rv)) { 493 LOGERROR( 494 ("socks: unable to connect to SOCKS proxy, %s", proxyHost.get())); 495 return PR_FAILURE; 496 } 497 498 if (MOZ_LOG_TEST(gSOCKSLog, LogLevel::Debug)) { 499 char buf[kIPv6CStrBufSize]; 500 mInternalProxyAddr.ToStringBuffer(buf, sizeof(buf)); 501 LOGDEBUG(("socks: trying proxy server, %s:%hu", buf, 502 ntohs(mInternalProxyAddr.inet.port))); 503 } 504 } 505 506 NetAddr proxy = mInternalProxyAddr; 507 FixupAddressFamily(fd, &proxy); 508 PRNetAddr prProxy; 509 NetAddrToPRNetAddr(&proxy, &prProxy); 510 status = fd->lower->methods->connect(fd->lower, &prProxy, mTimeout); 511 if (status != PR_SUCCESS) { 512 PRErrorCode c = PR_GetError(); 513 514 // If EINPROGRESS, return now and check back later after polling 515 if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) { 516 mState = SOCKS_CONNECTING_TO_PROXY; 517 return status; 518 } 519 if (IsLocalProxy()) { 520 LOGERROR(("socks: connect to domain socket failed (%d)", c)); 521 PR_SetError(PR_CONNECT_REFUSED_ERROR, 0); 522 mState = SOCKS_FAILED; 523 return status; 524 } 525 } 526 } while (status != PR_SUCCESS); 527 528 #if defined(XP_WIN) 529 // Switch to blocking mode during handshaking 530 if (IsLocalProxy() && mFD) { 531 PRSocketOptionData opt_nonblock; 532 opt_nonblock.option = PR_SockOpt_Nonblocking; 533 opt_nonblock.value.non_blocking = PR_FALSE; 534 PR_SetSocketOption(mFD, &opt_nonblock); 535 } 536 #endif 537 538 // Connected now, start SOCKS 539 if (mVersion == 4) return WriteV4ConnectRequest(); 540 return WriteV5AuthRequest(); 541 } 542 543 void nsSOCKSSocketInfo::FixupAddressFamily(PRFileDesc* fd, NetAddr* proxy) { 544 int32_t proxyFamily = mInternalProxyAddr.raw.family; 545 // Do nothing if the address family is already matched 546 if (proxyFamily == mDestinationFamily) { 547 return; 548 } 549 // If the system does not support IPv6 and the proxy address is IPv6, 550 // We can do nothing here. 551 if (proxyFamily == AF_INET6 && !ipv6Supported) { 552 return; 553 } 554 // If the system does not support IPv6 and the destination address is 555 // IPv6, convert IPv4 address to IPv4-mapped IPv6 address to satisfy 556 // the emulation layer 557 if (mDestinationFamily == AF_INET6 && !ipv6Supported) { 558 proxy->inet6.family = AF_INET6; 559 proxy->inet6.port = mInternalProxyAddr.inet.port; 560 uint8_t* proxyp = proxy->inet6.ip.u8; 561 memset(proxyp, 0, 10); 562 memset(proxyp + 10, 0xff, 2); 563 memcpy(proxyp + 12, (char*)&mInternalProxyAddr.inet.ip, 4); 564 // mDestinationFamily should not be updated 565 return; 566 } 567 // There's no PR_NSPR_IO_LAYER required when using named pipe, 568 // we simply ignore the TCP family here. 569 if (SetupNamedPipeLayer(fd)) { 570 return; 571 } 572 573 // Get an OS native handle from a specified FileDesc 574 PROsfd osfd = PR_FileDesc2NativeHandle(fd); 575 if (osfd == -1) { 576 return; 577 } 578 579 // Create a new FileDesc with a specified family 580 PRFileDesc* tmpfd = PR_OpenTCPSocket(proxyFamily); 581 if (!tmpfd) { 582 return; 583 } 584 PROsfd newsd = PR_FileDesc2NativeHandle(tmpfd); 585 if (newsd == -1) { 586 PR_Close(tmpfd); 587 return; 588 } 589 // Must succeed because PR_FileDesc2NativeHandle succeeded 590 fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); 591 MOZ_ASSERT(fd); 592 // Swap OS native handles 593 PR_ChangeFileDescNativeHandle(fd, newsd); 594 PR_ChangeFileDescNativeHandle(tmpfd, osfd); 595 // Close temporary FileDesc which is now associated with 596 // old OS native handle 597 PR_Close(tmpfd); 598 mDestinationFamily = proxyFamily; 599 } 600 601 PRStatus nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc* fd, 602 int16_t oflags) { 603 PRStatus status; 604 605 MOZ_ASSERT(mState == SOCKS_CONNECTING_TO_PROXY, 606 "Continuing connection in wrong state!"); 607 608 LOGDEBUG(("socks: continuing connection to proxy")); 609 610 status = fd->lower->methods->connectcontinue(fd->lower, oflags); 611 if (status != PR_SUCCESS) { 612 PRErrorCode c = PR_GetError(); 613 if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) { 614 // A connection failure occured, try another address 615 mState = SOCKS_DNS_COMPLETE; 616 return ConnectToProxy(fd); 617 } 618 619 // We're still connecting 620 return PR_FAILURE; 621 } 622 623 // Connected now, start SOCKS 624 if (mVersion == 4) return WriteV4ConnectRequest(); 625 return WriteV5AuthRequest(); 626 } 627 628 PRStatus nsSOCKSSocketInfo::WriteV4ConnectRequest() { 629 if (mProxyUsername.Length() > MAX_USERNAME_LEN) { 630 LOGERROR(("socks username is too long")); 631 HandshakeFinished(PR_UNKNOWN_ERROR); 632 return PR_FAILURE; 633 } 634 635 NetAddr* addr = &mDestinationAddr; 636 int32_t proxy_resolve; 637 638 MOZ_ASSERT(mState == SOCKS_CONNECTING_TO_PROXY, "Invalid state!"); 639 640 proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST; 641 642 mDataLength = 0; 643 mState = SOCKS4_WRITE_CONNECT_REQUEST; 644 645 LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)", 646 proxy_resolve ? "yes" : "no")); 647 648 // Send a SOCKS 4 connect request. 649 auto buf = Buffer<BUFFER_SIZE>(mData) 650 .WriteUint8(0x04) // version -- 4 651 .WriteUint8(0x01) // command -- connect 652 .WriteNetPort(addr); 653 654 // We don't have anything more to write after the if, so we can 655 // use a buffer with no further writes allowed. 656 Buffer<0> buf3; 657 if (proxy_resolve) { 658 // Add the full name, null-terminated, to the request 659 // according to SOCKS 4a. A fake IP address, with the first 660 // four bytes set to 0 and the last byte set to something other 661 // than 0, is used to notify the proxy that this is a SOCKS 4a 662 // request. This request type works for Tor and perhaps others. 663 // Passwords not supported by V4. 664 auto buf2 = 665 buf.WriteUint32(htonl(0x00000001)) // Fake IP 666 .WriteString<MAX_USERNAME_LEN>(mProxyUsername) 667 .WriteUint8(0x00) // Null-terminate username 668 .WriteString<MAX_HOSTNAME_LEN>(mDestinationHost); // Hostname 669 if (!buf2) { 670 LOGERROR(("socks4: destination host name is too long!")); 671 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 672 return PR_FAILURE; 673 } 674 buf3 = buf2.WriteUint8(0x00); 675 } else if (addr->raw.family == AF_INET) { 676 // Passwords not supported by V4. 677 buf3 = buf.WriteNetAddr(addr) // Add the IPv4 address 678 .WriteString<MAX_USERNAME_LEN>(mProxyUsername) 679 .WriteUint8(0x00); // Null-terminate username 680 } else { 681 LOGERROR(("socks: SOCKS 4 can only handle IPv4 addresses!")); 682 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 683 return PR_FAILURE; 684 } 685 686 mDataLength = buf3.Written(); 687 return PR_SUCCESS; 688 } 689 690 PRStatus nsSOCKSSocketInfo::ReadV4ConnectResponse() { 691 MOZ_ASSERT(mState == SOCKS4_READ_CONNECT_RESPONSE, 692 "Handling SOCKS 4 connection reply in wrong state!"); 693 MOZ_ASSERT(mDataLength == 8, "SOCKS 4 connection reply must be 8 bytes!"); 694 695 LOGDEBUG(("socks4: checking connection reply")); 696 697 if (ReadUint8() != 0x00) { 698 LOGERROR(("socks4: wrong connection reply")); 699 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 700 return PR_FAILURE; 701 } 702 703 // See if our connection request was granted 704 if (ReadUint8() == 90) { 705 LOGDEBUG(("socks4: connection successful!")); 706 HandshakeFinished(); 707 return PR_SUCCESS; 708 } 709 710 LOGERROR(("socks4: unable to connect")); 711 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 712 return PR_FAILURE; 713 } 714 715 PRStatus nsSOCKSSocketInfo::WriteV5AuthRequest() { 716 MOZ_ASSERT(mVersion == 5, "SOCKS version must be 5!"); 717 718 mDataLength = 0; 719 mState = SOCKS5_WRITE_AUTH_REQUEST; 720 721 // Send an initial SOCKS 5 greeting 722 LOGDEBUG(("socks5: sending auth methods")); 723 mDataLength = Buffer<BUFFER_SIZE>(mData) 724 .WriteUint8(0x05) // version -- 5 725 .WriteUint8(0x01) // # of auth methods -- 1 726 // Use authenticate iff we have a proxy username. 727 .WriteUint8(mProxyUsername.IsEmpty() ? 0x00 : 0x02) 728 .Written(); 729 730 return PR_SUCCESS; 731 } 732 733 PRStatus nsSOCKSSocketInfo::ReadV5AuthResponse() { 734 MOZ_ASSERT(mState == SOCKS5_READ_AUTH_RESPONSE, 735 "Handling SOCKS 5 auth method reply in wrong state!"); 736 MOZ_ASSERT(mDataLength == 2, "SOCKS 5 auth method reply must be 2 bytes!"); 737 738 LOGDEBUG(("socks5: checking auth method reply")); 739 740 // Check version number 741 if (ReadUint8() != 0x05) { 742 LOGERROR(("socks5: unexpected version in the reply")); 743 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 744 return PR_FAILURE; 745 } 746 747 // Make sure our authentication choice was accepted, 748 // and continue accordingly 749 uint8_t authMethod = ReadUint8(); 750 if (mProxyUsername.IsEmpty() && authMethod == 0x00) { // no auth 751 LOGDEBUG(("socks5: server allows connection without authentication")); 752 return WriteV5ConnectRequest(); 753 } 754 if (!mProxyUsername.IsEmpty() && authMethod == 0x02) { // username/pw 755 LOGDEBUG(("socks5: auth method accepted by server")); 756 return WriteV5UsernameRequest(); 757 } // 0xFF signals error 758 LOGERROR(("socks5: server did not accept our authentication method")); 759 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 760 return PR_FAILURE; 761 } 762 763 PRStatus nsSOCKSSocketInfo::WriteV5UsernameRequest() { 764 MOZ_ASSERT(mVersion == 5, "SOCKS version must be 5!"); 765 766 if (mProxyUsername.Length() > MAX_USERNAME_LEN) { 767 LOGERROR(("socks username is too long")); 768 HandshakeFinished(PR_UNKNOWN_ERROR); 769 return PR_FAILURE; 770 } 771 772 nsCString password; 773 mProxy->GetPassword(password); 774 if (password.Length() > MAX_PASSWORD_LEN) { 775 LOGERROR(("socks password is too long")); 776 HandshakeFinished(PR_UNKNOWN_ERROR); 777 return PR_FAILURE; 778 } 779 780 mDataLength = 0; 781 mState = SOCKS5_WRITE_USERNAME_REQUEST; 782 783 // RFC 1929 Username/password auth for SOCKS 5 784 LOGDEBUG(("socks5: sending username and password")); 785 mDataLength = Buffer<BUFFER_SIZE>(mData) 786 .WriteUint8(0x01) // version 1 (not 5) 787 .WriteUint8(mProxyUsername.Length()) // username length 788 .WriteString<MAX_USERNAME_LEN>(mProxyUsername) // username 789 .WriteUint8(password.Length()) // password length 790 .WriteString<MAX_PASSWORD_LEN>( 791 password) // password. WARNING: Sent unencrypted! 792 .Written(); 793 794 return PR_SUCCESS; 795 } 796 797 PRStatus nsSOCKSSocketInfo::ReadV5UsernameResponse() { 798 MOZ_ASSERT(mState == SOCKS5_READ_USERNAME_RESPONSE, 799 "Handling SOCKS 5 username/password reply in wrong state!"); 800 801 MOZ_ASSERT(mDataLength == 2, "SOCKS 5 username reply must be 2 bytes"); 802 803 // Check version number, must be 1 (not 5) 804 if (ReadUint8() != 0x01) { 805 LOGERROR(("socks5: unexpected version in the reply")); 806 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 807 return PR_FAILURE; 808 } 809 810 // Check whether username/password were accepted 811 if (ReadUint8() != 0x00) { // 0 = success 812 LOGERROR(("socks5: username/password not accepted")); 813 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 814 return PR_FAILURE; 815 } 816 817 LOGDEBUG(("socks5: username/password accepted by server")); 818 819 return WriteV5ConnectRequest(); 820 } 821 822 PRStatus nsSOCKSSocketInfo::WriteV5ConnectRequest() { 823 // Send SOCKS 5 connect request 824 NetAddr* addr = &mDestinationAddr; 825 int32_t proxy_resolve; 826 proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST; 827 828 LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)", 829 proxy_resolve ? "yes" : "no")); 830 831 mDataLength = 0; 832 mState = SOCKS5_WRITE_CONNECT_REQUEST; 833 834 auto buf = Buffer<BUFFER_SIZE>(mData) 835 .WriteUint8(0x05) // version -- 5 836 .WriteUint8(0x01) // command -- connect 837 .WriteUint8(0x00); // reserved 838 839 // We're writing a net port after the if, so we need a buffer allowing 840 // to write that much. 841 Buffer<sizeof(uint16_t)> buf2; 842 // Add the address to the SOCKS 5 request. SOCKS 5 supports several 843 // address types, so we pick the one that works best for us. 844 if (proxy_resolve) { 845 if (StringEndsWith(mDestinationHost, ".tor.onion"_ns)) { 846 nsAutoCString realHost; 847 nsCOMPtr<IOnionAliasService> oas = do_GetService(ONIONALIAS_CID); 848 if (NS_FAILED(oas->GetOnionAlias(mDestinationHost, realHost))) { 849 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 850 return PR_FAILURE; 851 } 852 buf2 = buf.WriteUint8(0x03) 853 .WriteUint8(realHost.Length()) 854 .WriteString<MAX_HOSTNAME_LEN>(realHost); 855 } else { 856 // Add the host name. Only a single byte is used to store the length, 857 // so we must prevent long names from being used. 858 buf2 = buf.WriteUint8(0x03) // addr type -- domainname 859 .WriteUint8(mDestinationHost.Length()) // name length 860 .WriteString<MAX_HOSTNAME_LEN>(mDestinationHost); // Hostname 861 } 862 if (!buf2) { 863 LOGERROR(("socks5: destination host name is too long!")); 864 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 865 return PR_FAILURE; 866 } 867 } else if (addr->raw.family == AF_INET) { 868 buf2 = buf.WriteUint8(0x01) // addr type -- IPv4 869 .WriteNetAddr(addr); 870 } else if (addr->raw.family == AF_INET6) { 871 buf2 = buf.WriteUint8(0x04) // addr type -- IPv6 872 .WriteNetAddr(addr); 873 } else { 874 LOGERROR(("socks5: destination address of unknown type!")); 875 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 876 return PR_FAILURE; 877 } 878 879 auto buf3 = buf2.WriteNetPort(addr); // port 880 mDataLength = buf3.Written(); 881 882 return PR_SUCCESS; 883 } 884 885 PRStatus nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(uint8_t* type, 886 uint32_t* len) { 887 MOZ_ASSERT(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP || 888 mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM, 889 "Invalid state!"); 890 MOZ_ASSERT(mDataLength >= 5, 891 "SOCKS 5 connection reply must be at least 5 bytes!"); 892 893 // Seek to the address location 894 mReadOffset = 3; 895 896 *type = ReadUint8(); 897 898 switch (*type) { 899 case 0x01: // ipv4 900 *len = 4 - 1; 901 break; 902 case 0x04: // ipv6 903 *len = 16 - 1; 904 break; 905 case 0x03: // fqdn 906 *len = ReadUint8(); 907 break; 908 default: // wrong address type 909 LOGERROR(("socks5: wrong address type in connection reply!")); 910 return PR_FAILURE; 911 } 912 913 return PR_SUCCESS; 914 } 915 916 PRStatus nsSOCKSSocketInfo::ReadV5ConnectResponseTop() { 917 uint8_t res; 918 uint32_t len; 919 920 MOZ_ASSERT(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP, "Invalid state!"); 921 MOZ_ASSERT(mDataLength == 5, 922 "SOCKS 5 connection reply must be exactly 5 bytes!"); 923 924 LOGDEBUG(("socks5: checking connection reply")); 925 926 // Check version number 927 if (ReadUint8() != 0x05) { 928 LOGERROR(("socks5: unexpected version in the reply")); 929 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 930 return PR_FAILURE; 931 } 932 933 // Check response 934 res = ReadUint8(); 935 if (res != 0x00) { 936 PRErrorCode c = PR_CONNECT_REFUSED_ERROR; 937 938 switch (res) { 939 case 0x01: 940 LOGERROR( 941 ("socks5: connect failed: " 942 "01, General SOCKS server failure.")); 943 break; 944 case 0x02: 945 LOGERROR( 946 ("socks5: connect failed: " 947 "02, Connection not allowed by ruleset.")); 948 break; 949 case 0x03: 950 LOGERROR(("socks5: connect failed: 03, Network unreachable.")); 951 c = PR_NETWORK_UNREACHABLE_ERROR; 952 break; 953 case 0x04: 954 LOGERROR(("socks5: connect failed: 04, Host unreachable.")); 955 c = PR_BAD_ADDRESS_ERROR; 956 break; 957 case 0x05: 958 LOGERROR(("socks5: connect failed: 05, Connection refused.")); 959 break; 960 case 0x06: 961 LOGERROR(("socks5: connect failed: 06, TTL expired.")); 962 c = PR_CONNECT_TIMEOUT_ERROR; 963 break; 964 case 0x07: 965 LOGERROR( 966 ("socks5: connect failed: " 967 "07, Command not supported.")); 968 break; 969 case 0x08: 970 LOGERROR( 971 ("socks5: connect failed: " 972 "08, Address type not supported.")); 973 c = PR_BAD_ADDRESS_ERROR; 974 break; 975 case 0xF0: // Tor SOCKS5_HS_NOT_FOUND 976 LOGERROR( 977 ("socks5: connect failed: F0," 978 " Tor onion service descriptor can not be found.")); 979 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_NOT_FOUND); 980 break; 981 case 0xF1: // Tor SOCKS5_HS_IS_INVALID 982 LOGERROR( 983 ("socks5: connect failed: F1," 984 " Tor onion service descriptor is invalid.")); 985 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_IS_INVALID); 986 break; 987 case 0xF2: // Tor SOCKS5_HS_INTRO_FAILED 988 LOGERROR( 989 ("socks5: connect failed: F2," 990 " Tor onion service introduction failed.")); 991 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED); 992 break; 993 case 0xF3: // Tor SOCKS5_HS_REND_FAILED 994 LOGERROR( 995 ("socks5: connect failed: F3," 996 " Tor onion service rendezvous failed.")); 997 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_REND_FAILED); 998 break; 999 case 0xF4: // Tor SOCKS5_HS_MISSING_CLIENT_AUTH 1000 LOGERROR( 1001 ("socks5: connect failed: F4," 1002 " Tor onion service missing client authorization.")); 1003 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH); 1004 break; 1005 case 0xF5: // Tor SOCKS5_HS_BAD_CLIENT_AUTH 1006 LOGERROR( 1007 ("socks5: connect failed: F5," 1008 " Tor onion service wrong client authorization.")); 1009 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH); 1010 break; 1011 case 0xF6: // Tor SOCKS5_HS_BAD_ADDRESS 1012 LOGERROR( 1013 ("socks5: connect failed: F6," 1014 " Tor onion service bad address.")); 1015 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS); 1016 break; 1017 case 0xF7: // Tor SOCKS5_HS_INTRO_TIMEDOUT 1018 LOGERROR( 1019 ("socks5: connect failed: F7," 1020 " Tor onion service introduction timed out.")); 1021 c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT); 1022 break; 1023 1024 default: 1025 LOGERROR(("socks5: connect failed.")); 1026 break; 1027 } 1028 1029 HandshakeFinished(c); 1030 return PR_FAILURE; 1031 } 1032 1033 if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) { 1034 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 1035 return PR_FAILURE; 1036 } 1037 1038 mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM; 1039 WantRead(len + 2); 1040 1041 return PR_SUCCESS; 1042 } 1043 1044 PRStatus nsSOCKSSocketInfo::ReadV5ConnectResponseBottom() { 1045 uint8_t type; 1046 uint32_t len; 1047 1048 MOZ_ASSERT(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM, "Invalid state!"); 1049 1050 if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) { 1051 HandshakeFinished(PR_BAD_ADDRESS_ERROR); 1052 return PR_FAILURE; 1053 } 1054 1055 MOZ_ASSERT(mDataLength == 7 + len, 1056 "SOCKS 5 unexpected length of connection reply!"); 1057 1058 LOGDEBUG(("socks5: loading source addr and port")); 1059 // Read what the proxy says is our source address 1060 switch (type) { 1061 case 0x01: // ipv4 1062 ReadNetAddr(&mExternalProxyAddr, AF_INET); 1063 break; 1064 case 0x04: // ipv6 1065 ReadNetAddr(&mExternalProxyAddr, AF_INET6); 1066 break; 1067 case 0x03: // fqdn (skip) 1068 mReadOffset += len; 1069 mExternalProxyAddr.raw.family = AF_INET; 1070 break; 1071 } 1072 1073 ReadNetPort(&mExternalProxyAddr); 1074 1075 LOGDEBUG(("socks5: connected!")); 1076 HandshakeFinished(); 1077 1078 return PR_SUCCESS; 1079 } 1080 1081 void nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to) { mTimeout = to; } 1082 1083 PRStatus nsSOCKSSocketInfo::DoHandshake(PRFileDesc* fd, int16_t oflags) { 1084 LOGDEBUG(("socks: DoHandshake(), state = %d", mState)); 1085 1086 switch (mState) { 1087 case SOCKS_INITIAL: 1088 if (IsLocalProxy()) { 1089 mState = SOCKS_DNS_COMPLETE; 1090 mLookupStatus = NS_OK; 1091 return ConnectToProxy(fd); 1092 } 1093 1094 return StartDNS(fd); 1095 case SOCKS_DNS_IN_PROGRESS: 1096 PR_SetError(PR_IN_PROGRESS_ERROR, 0); 1097 return PR_FAILURE; 1098 case SOCKS_DNS_COMPLETE: 1099 return ConnectToProxy(fd); 1100 case SOCKS_CONNECTING_TO_PROXY: 1101 return ContinueConnectingToProxy(fd, oflags); 1102 case SOCKS4_WRITE_CONNECT_REQUEST: 1103 if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1104 WantRead(8); 1105 mState = SOCKS4_READ_CONNECT_RESPONSE; 1106 return PR_SUCCESS; 1107 case SOCKS4_READ_CONNECT_RESPONSE: 1108 if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1109 return ReadV4ConnectResponse(); 1110 1111 case SOCKS5_WRITE_AUTH_REQUEST: 1112 if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1113 WantRead(2); 1114 mState = SOCKS5_READ_AUTH_RESPONSE; 1115 return PR_SUCCESS; 1116 case SOCKS5_READ_AUTH_RESPONSE: 1117 if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1118 return ReadV5AuthResponse(); 1119 case SOCKS5_WRITE_USERNAME_REQUEST: 1120 if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1121 WantRead(2); 1122 mState = SOCKS5_READ_USERNAME_RESPONSE; 1123 return PR_SUCCESS; 1124 case SOCKS5_READ_USERNAME_RESPONSE: 1125 if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1126 return ReadV5UsernameResponse(); 1127 case SOCKS5_WRITE_CONNECT_REQUEST: 1128 if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1129 1130 // The SOCKS 5 response to the connection request is variable 1131 // length. First, we'll read enough to tell how long the response 1132 // is, and will read the rest later. 1133 WantRead(5); 1134 mState = SOCKS5_READ_CONNECT_RESPONSE_TOP; 1135 return PR_SUCCESS; 1136 case SOCKS5_READ_CONNECT_RESPONSE_TOP: 1137 if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1138 return ReadV5ConnectResponseTop(); 1139 case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM: 1140 if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; 1141 return ReadV5ConnectResponseBottom(); 1142 1143 case SOCKS_CONNECTED: 1144 LOGERROR(("socks: already connected")); 1145 HandshakeFinished(PR_IS_CONNECTED_ERROR); 1146 return PR_FAILURE; 1147 case SOCKS_FAILED: 1148 LOGERROR(("socks: already failed")); 1149 return PR_FAILURE; 1150 } 1151 1152 LOGERROR(("socks: executing handshake in invalid state, %d", mState)); 1153 HandshakeFinished(PR_INVALID_STATE_ERROR); 1154 1155 return PR_FAILURE; 1156 } 1157 1158 int16_t nsSOCKSSocketInfo::GetPollFlags() const { 1159 switch (mState) { 1160 case SOCKS_DNS_IN_PROGRESS: 1161 case SOCKS_DNS_COMPLETE: 1162 case SOCKS_CONNECTING_TO_PROXY: 1163 return PR_POLL_EXCEPT | PR_POLL_WRITE; 1164 case SOCKS4_WRITE_CONNECT_REQUEST: 1165 case SOCKS5_WRITE_AUTH_REQUEST: 1166 case SOCKS5_WRITE_USERNAME_REQUEST: 1167 case SOCKS5_WRITE_CONNECT_REQUEST: 1168 return PR_POLL_WRITE; 1169 case SOCKS4_READ_CONNECT_RESPONSE: 1170 case SOCKS5_READ_AUTH_RESPONSE: 1171 case SOCKS5_READ_USERNAME_RESPONSE: 1172 case SOCKS5_READ_CONNECT_RESPONSE_TOP: 1173 case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM: 1174 return PR_POLL_READ; 1175 default: 1176 break; 1177 } 1178 1179 return 0; 1180 } 1181 1182 inline uint8_t nsSOCKSSocketInfo::ReadUint8() { 1183 uint8_t rv; 1184 MOZ_ASSERT(mReadOffset + sizeof(rv) <= mDataLength, 1185 "Not enough space to pop a uint8_t!"); 1186 rv = mData[mReadOffset]; 1187 mReadOffset += sizeof(rv); 1188 return rv; 1189 } 1190 1191 inline uint16_t nsSOCKSSocketInfo::ReadUint16() { 1192 uint16_t rv; 1193 MOZ_ASSERT(mReadOffset + sizeof(rv) <= mDataLength, 1194 "Not enough space to pop a uint16_t!"); 1195 memcpy(&rv, mData + mReadOffset, sizeof(rv)); 1196 mReadOffset += sizeof(rv); 1197 return rv; 1198 } 1199 1200 inline uint32_t nsSOCKSSocketInfo::ReadUint32() { 1201 uint32_t rv; 1202 MOZ_ASSERT(mReadOffset + sizeof(rv) <= mDataLength, 1203 "Not enough space to pop a uint32_t!"); 1204 memcpy(&rv, mData + mReadOffset, sizeof(rv)); 1205 mReadOffset += sizeof(rv); 1206 return rv; 1207 } 1208 1209 void nsSOCKSSocketInfo::ReadNetAddr(NetAddr* addr, uint16_t fam) { 1210 uint32_t amt = 0; 1211 const uint8_t* ip = mData + mReadOffset; 1212 1213 addr->raw.family = fam; 1214 if (fam == AF_INET) { 1215 amt = sizeof(addr->inet.ip); 1216 MOZ_ASSERT(mReadOffset + amt <= mDataLength, 1217 "Not enough space to pop an ipv4 addr!"); 1218 memcpy(&addr->inet.ip, ip, amt); 1219 } else if (fam == AF_INET6) { 1220 amt = sizeof(addr->inet6.ip.u8); 1221 MOZ_ASSERT(mReadOffset + amt <= mDataLength, 1222 "Not enough space to pop an ipv6 addr!"); 1223 memcpy(addr->inet6.ip.u8, ip, amt); 1224 } 1225 1226 mReadOffset += amt; 1227 } 1228 1229 void nsSOCKSSocketInfo::ReadNetPort(NetAddr* addr) { 1230 addr->inet.port = ReadUint16(); 1231 } 1232 1233 void nsSOCKSSocketInfo::WantRead(uint32_t sz) { 1234 MOZ_ASSERT(mDataIoPtr == nullptr, 1235 "WantRead() called while I/O already in progress!"); 1236 MOZ_ASSERT(mDataLength + sz <= BUFFER_SIZE, "Can't read that much data!"); 1237 mAmountToRead = sz; 1238 } 1239 1240 PRStatus nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc* fd) { 1241 int32_t rc; 1242 const uint8_t* end; 1243 1244 if (!mAmountToRead) { 1245 LOGDEBUG(("socks: ReadFromSocket(), nothing to do")); 1246 return PR_SUCCESS; 1247 } 1248 1249 if (!mDataIoPtr) { 1250 mDataIoPtr = mData + mDataLength; 1251 mDataLength += mAmountToRead; 1252 } 1253 1254 end = mData + mDataLength; 1255 1256 while (mDataIoPtr < end) { 1257 rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr); 1258 if (rc <= 0) { 1259 if (rc == 0) { 1260 LOGERROR(("socks: proxy server closed connection")); 1261 HandshakeFinished(PR_CONNECT_REFUSED_ERROR); 1262 return PR_FAILURE; 1263 } 1264 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { 1265 LOGDEBUG(("socks: ReadFromSocket(), want read")); 1266 } 1267 break; 1268 } 1269 1270 mDataIoPtr += rc; 1271 } 1272 1273 LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total", 1274 unsigned(mDataIoPtr - mData))); 1275 if (mDataIoPtr == end) { 1276 mDataIoPtr = nullptr; 1277 mAmountToRead = 0; 1278 mReadOffset = 0; 1279 return PR_SUCCESS; 1280 } 1281 1282 return PR_FAILURE; 1283 } 1284 1285 PRStatus nsSOCKSSocketInfo::WriteToSocket(PRFileDesc* fd) { 1286 int32_t rc; 1287 const uint8_t* end; 1288 1289 if (!mDataLength) { 1290 LOGDEBUG(("socks: WriteToSocket(), nothing to do")); 1291 return PR_SUCCESS; 1292 } 1293 1294 if (!mDataIoPtr) mDataIoPtr = mData; 1295 1296 end = mData + mDataLength; 1297 1298 while (mDataIoPtr < end) { 1299 rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr); 1300 if (rc < 0) { 1301 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { 1302 LOGDEBUG(("socks: WriteToSocket(), want write")); 1303 } 1304 break; 1305 } 1306 1307 mDataIoPtr += rc; 1308 } 1309 1310 if (mDataIoPtr == end) { 1311 mDataIoPtr = nullptr; 1312 mDataLength = 0; 1313 mReadOffset = 0; 1314 return PR_SUCCESS; 1315 } 1316 1317 return PR_FAILURE; 1318 } 1319 1320 static PRStatus nsSOCKSIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr, 1321 PRIntervalTime to) { 1322 PRStatus status; 1323 NetAddr dst; 1324 1325 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1326 if (info == nullptr) return PR_FAILURE; 1327 1328 if (addr->raw.family == PR_AF_INET6 && 1329 PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) { 1330 const uint8_t* srcp; 1331 1332 LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4")); 1333 1334 // copied from _PR_ConvertToIpv4NetAddr() 1335 dst.raw.family = AF_INET; 1336 dst.inet.ip = htonl(INADDR_ANY); 1337 dst.inet.port = htons(0); 1338 srcp = addr->ipv6.ip.pr_s6_addr; 1339 memcpy(&dst.inet.ip, srcp + 12, 4); 1340 dst.inet.family = AF_INET; 1341 dst.inet.port = addr->ipv6.port; 1342 } else { 1343 dst = NetAddr(addr); 1344 } 1345 1346 info->SetDestinationAddr(dst); 1347 info->SetConnectTimeout(to); 1348 1349 do { 1350 status = info->DoHandshake(fd, -1); 1351 } while (status == PR_SUCCESS && !info->IsConnected()); 1352 1353 return status; 1354 } 1355 1356 static PRStatus nsSOCKSIOLayerConnectContinue(PRFileDesc* fd, int16_t oflags) { 1357 PRStatus status; 1358 1359 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1360 if (info == nullptr) return PR_FAILURE; 1361 1362 do { 1363 status = info->DoHandshake(fd, oflags); 1364 } while (status == PR_SUCCESS && !info->IsConnected()); 1365 1366 return status; 1367 } 1368 1369 static int16_t nsSOCKSIOLayerPoll(PRFileDesc* fd, int16_t in_flags, 1370 int16_t* out_flags) { 1371 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1372 if (info == nullptr) return PR_FAILURE; 1373 1374 if (!info->IsConnected()) { 1375 *out_flags = 0; 1376 return info->GetPollFlags(); 1377 } 1378 1379 return fd->lower->methods->poll(fd->lower, in_flags, out_flags); 1380 } 1381 1382 static PRStatus nsSOCKSIOLayerClose(PRFileDesc* fd) { 1383 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1384 PRDescIdentity id = PR_GetLayersIdentity(fd); 1385 1386 if (info && id == nsSOCKSIOLayerIdentity) { 1387 info->ForgetFD(); 1388 NS_RELEASE(info); 1389 fd->identity = PR_INVALID_IO_LAYER; 1390 } 1391 1392 return fd->lower->methods->close(fd->lower); 1393 } 1394 1395 static PRFileDesc* nsSOCKSIOLayerAccept(PRFileDesc* fd, PRNetAddr* addr, 1396 PRIntervalTime timeout) { 1397 // TODO: implement SOCKS support for accept 1398 return fd->lower->methods->accept(fd->lower, addr, timeout); 1399 } 1400 1401 static int32_t nsSOCKSIOLayerAcceptRead(PRFileDesc* sd, PRFileDesc** nd, 1402 PRNetAddr** raddr, void* buf, 1403 int32_t amount, 1404 PRIntervalTime timeout) { 1405 // TODO: implement SOCKS support for accept, then read from it 1406 return sd->lower->methods->acceptread(sd->lower, nd, raddr, buf, amount, 1407 timeout); 1408 } 1409 1410 static PRStatus nsSOCKSIOLayerBind(PRFileDesc* fd, const PRNetAddr* addr) { 1411 // TODO: implement SOCKS support for bind (very similar to connect) 1412 return fd->lower->methods->bind(fd->lower, addr); 1413 } 1414 1415 static PRStatus nsSOCKSIOLayerGetName(PRFileDesc* fd, PRNetAddr* addr) { 1416 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1417 1418 if (info != nullptr && addr != nullptr) { 1419 NetAddr temp; 1420 info->GetExternalProxyAddr(temp); 1421 NetAddrToPRNetAddr(&temp, addr); 1422 return PR_SUCCESS; 1423 } 1424 1425 return PR_FAILURE; 1426 } 1427 1428 static PRStatus nsSOCKSIOLayerGetPeerName(PRFileDesc* fd, PRNetAddr* addr) { 1429 nsSOCKSSocketInfo* info = (nsSOCKSSocketInfo*)fd->secret; 1430 1431 if (info != nullptr && addr != nullptr) { 1432 NetAddr temp; 1433 info->GetDestinationAddr(temp); 1434 NetAddrToPRNetAddr(&temp, addr); 1435 return PR_SUCCESS; 1436 } 1437 1438 return PR_FAILURE; 1439 } 1440 1441 static PRStatus nsSOCKSIOLayerListen(PRFileDesc* fd, int backlog) { 1442 // TODO: implement SOCKS support for listen 1443 return fd->lower->methods->listen(fd->lower, backlog); 1444 } 1445 1446 // add SOCKS IO layer to an existing socket 1447 nsresult nsSOCKSIOLayerAddToSocket(int32_t family, const char* host, 1448 int32_t port, nsIProxyInfo* proxy, 1449 int32_t socksVersion, uint32_t flags, 1450 uint32_t tlsFlags, PRFileDesc* fd) { 1451 NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), 1452 NS_ERROR_NOT_INITIALIZED); 1453 1454 if (firstTime) { 1455 // XXX hack until NSPR provides an official way to detect system IPv6 1456 // support (bug 388519) 1457 PRFileDesc* tmpfd = PR_OpenTCPSocket(PR_AF_INET6); 1458 if (!tmpfd) { 1459 ipv6Supported = false; 1460 } else { 1461 // If the system does not support IPv6, NSPR will push 1462 // IPv6-to-IPv4 emulation layer onto the native layer 1463 ipv6Supported = PR_GetIdentitiesLayer(tmpfd, PR_NSPR_IO_LAYER) == tmpfd; 1464 PR_Close(tmpfd); 1465 } 1466 1467 nsSOCKSIOLayerIdentity = PR_GetUniqueIdentity("SOCKS layer"); 1468 nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods(); 1469 1470 nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect; 1471 nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue; 1472 nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll; 1473 nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind; 1474 nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead; 1475 nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName; 1476 nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName; 1477 nsSOCKSIOLayerMethods.accept = nsSOCKSIOLayerAccept; 1478 nsSOCKSIOLayerMethods.listen = nsSOCKSIOLayerListen; 1479 nsSOCKSIOLayerMethods.close = nsSOCKSIOLayerClose; 1480 1481 firstTime = false; 1482 } 1483 1484 LOGDEBUG(("Entering nsSOCKSIOLayerAddToSocket().")); 1485 1486 PRFileDesc* layer; 1487 PRStatus rv; 1488 1489 layer = PR_CreateIOLayerStub(nsSOCKSIOLayerIdentity, &nsSOCKSIOLayerMethods); 1490 if (!layer) { 1491 LOGERROR(("PR_CreateIOLayerStub() failed.")); 1492 return NS_ERROR_FAILURE; 1493 } 1494 1495 nsSOCKSSocketInfo* infoObject = new nsSOCKSSocketInfo(); 1496 if (!infoObject) { 1497 // clean up IOLayerStub 1498 LOGERROR(("Failed to create nsSOCKSSocketInfo().")); 1499 PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc(). 1500 return NS_ERROR_FAILURE; 1501 } 1502 1503 NS_ADDREF(infoObject); 1504 infoObject->Init(socksVersion, family, proxy, host, flags, tlsFlags); 1505 layer->secret = (PRFilePrivate*)infoObject; 1506 1507 PRDescIdentity fdIdentity = PR_GetLayersIdentity(fd); 1508 #if defined(XP_WIN) 1509 if (fdIdentity == mozilla::net::nsNamedPipeLayerIdentity) { 1510 // remember named pipe fd on the info object so that we can switch 1511 // blocking and non-blocking mode on the pipe later. 1512 infoObject->SetNamedPipeFD(fd); 1513 } 1514 #endif 1515 rv = PR_PushIOLayer(fd, fdIdentity, layer); 1516 1517 if (rv == PR_FAILURE) { 1518 LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv)); 1519 NS_RELEASE(infoObject); 1520 PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc(). 1521 return NS_ERROR_FAILURE; 1522 } 1523 1524 return NS_OK; 1525 } 1526 1527 bool IsHostLocalTarget(const nsACString& aHost) { 1528 #if defined(XP_UNIX) 1529 return StringBeginsWith(aHost, "file:"_ns); 1530 #elif defined(XP_WIN) 1531 return IsNamedPipePath(aHost); 1532 #else 1533 return false; 1534 #endif // XP_UNIX 1535 }