netwerk/socket/nsSOCKSIOLayer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim:set expandtab ts=4 sw=4 sts=4 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/. */
     7 #include "nspr.h"
     8 #include "private/pprio.h"
     9 #include "nsString.h"
    10 #include "nsCRT.h"
    12 #include "nsIServiceManager.h"
    13 #include "nsIDNSService.h"
    14 #include "nsIDNSRecord.h"
    15 #include "nsISOCKSSocketInfo.h"
    16 #include "nsISocketProvider.h"
    17 #include "nsSOCKSIOLayer.h"
    18 #include "nsNetCID.h"
    19 #include "nsIDNSListener.h"
    20 #include "nsICancelable.h"
    21 #include "nsThreadUtils.h"
    22 #include "mozilla/net/DNS.h"
    24 using namespace mozilla::net;
    26 static PRDescIdentity nsSOCKSIOLayerIdentity;
    27 static PRIOMethods nsSOCKSIOLayerMethods;
    28 static bool firstTime = true;
    29 static bool ipv6Supported = true;
    31 #if defined(PR_LOGGING)
    32 static PRLogModuleInfo *gSOCKSLog;
    33 #define LOGDEBUG(args) PR_LOG(gSOCKSLog, PR_LOG_DEBUG, args)
    34 #define LOGERROR(args) PR_LOG(gSOCKSLog, PR_LOG_ERROR , args)
    36 #else
    37 #define LOGDEBUG(args)
    38 #define LOGERROR(args)
    39 #endif
    41 class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
    42                         , public nsIDNSListener
    43 {
    44     enum State {
    45         SOCKS_INITIAL,
    46         SOCKS_DNS_IN_PROGRESS,
    47         SOCKS_DNS_COMPLETE,
    48         SOCKS_CONNECTING_TO_PROXY,
    49         SOCKS4_WRITE_CONNECT_REQUEST,
    50         SOCKS4_READ_CONNECT_RESPONSE,
    51         SOCKS5_WRITE_AUTH_REQUEST,
    52         SOCKS5_READ_AUTH_RESPONSE,
    53         SOCKS5_WRITE_USERNAME_REQUEST,
    54         SOCKS5_READ_USERNAME_RESPONSE,
    55         SOCKS5_WRITE_CONNECT_REQUEST,
    56         SOCKS5_READ_CONNECT_RESPONSE_TOP,
    57         SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
    58         SOCKS_CONNECTED,
    59         SOCKS_FAILED
    60     };
    62     // A buffer of 520 bytes should be enough for any request and response
    63     // in case of SOCKS4 as well as SOCKS5
    64     static const uint32_t BUFFER_SIZE = 520;
    65     static const uint32_t MAX_HOSTNAME_LEN = 255;
    66     static const uint32_t MAX_USERNAME_LEN = 255;
    67     static const uint32_t MAX_PASSWORD_LEN = 255;
    69 public:
    70     nsSOCKSSocketInfo();
    71     virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); }
    73     NS_DECL_THREADSAFE_ISUPPORTS
    74     NS_DECL_NSISOCKSSOCKETINFO
    75     NS_DECL_NSIDNSLISTENER
    77     void Init(int32_t version,
    78               int32_t family,
    79               nsIProxyInfo *proxy,
    80               const char *destinationHost,
    81               uint32_t flags);
    83     void SetConnectTimeout(PRIntervalTime to);
    84     PRStatus DoHandshake(PRFileDesc *fd, int16_t oflags = -1);
    85     int16_t GetPollFlags() const;
    86     bool IsConnected() const { return (mState == SOCKS_CONNECTED ||
    87                                        mState == SOCKS5_READ_CONNECT_RESPONSE_TOP); }
    89     void ForgetFD() { mFD = nullptr; }
    91 private:
    92     void HandshakeFinished(PRErrorCode err = 0);
    93     PRStatus StartDNS(PRFileDesc *fd);
    94     PRStatus ConnectToProxy(PRFileDesc *fd);
    95     void FixupAddressFamily(PRFileDesc *fd, NetAddr *proxy);
    96     PRStatus ContinueConnectingToProxy(PRFileDesc *fd, int16_t oflags);
    97     PRStatus WriteV4ConnectRequest();
    98     PRStatus ReadV4ConnectResponse();
    99     PRStatus WriteV5AuthRequest();
   100     PRStatus ReadV5AuthResponse();
   101     PRStatus WriteV5UsernameRequest();
   102     PRStatus ReadV5UsernameResponse();
   103     PRStatus WriteV5ConnectRequest();
   104     PRStatus ReadV5AddrTypeAndLength(uint8_t *type, uint32_t *len);
   105     PRStatus ReadV5ConnectResponseTop();
   106     PRStatus ReadV5ConnectResponseBottom();
   108     void WriteUint8(uint8_t d);
   109     void WriteUint16(uint16_t d);
   110     void WriteUint32(uint32_t d);
   111     void WriteNetAddr(const NetAddr *addr);
   112     void WriteNetPort(const NetAddr *addr);
   113     void WriteString(const nsACString &str);
   115     uint8_t ReadUint8();
   116     uint16_t ReadUint16();
   117     uint32_t ReadUint32();
   118     void ReadNetAddr(NetAddr *addr, uint16_t fam);
   119     void ReadNetPort(NetAddr *addr);
   121     void WantRead(uint32_t sz);
   122     PRStatus ReadFromSocket(PRFileDesc *fd);
   123     PRStatus WriteToSocket(PRFileDesc *fd);
   125 private:
   126     State     mState;
   127     uint8_t * mData;
   128     uint8_t * mDataIoPtr;
   129     uint32_t  mDataLength;
   130     uint32_t  mReadOffset;
   131     uint32_t  mAmountToRead;
   132     nsCOMPtr<nsIDNSRecord>  mDnsRec;
   133     nsCOMPtr<nsICancelable> mLookup;
   134     nsresult                mLookupStatus;
   135     PRFileDesc             *mFD;
   137     nsCString mDestinationHost;
   138     nsCOMPtr<nsIProxyInfo> mProxy;
   139     int32_t   mVersion;   // SOCKS version 4 or 5
   140     int32_t   mDestinationFamily;
   141     uint32_t  mFlags;
   142     NetAddr   mInternalProxyAddr;
   143     NetAddr   mExternalProxyAddr;
   144     NetAddr   mDestinationAddr;
   145     PRIntervalTime mTimeout;
   146     nsCString mProxyUsername; // Cache, from mProxy
   147 };
   149 nsSOCKSSocketInfo::nsSOCKSSocketInfo()
   150     : mState(SOCKS_INITIAL)
   151     , mDataIoPtr(nullptr)
   152     , mDataLength(0)
   153     , mReadOffset(0)
   154     , mAmountToRead(0)
   155     , mVersion(-1)
   156     , mDestinationFamily(AF_INET)
   157     , mFlags(0)
   158     , mTimeout(PR_INTERVAL_NO_TIMEOUT)
   159 {
   160     mData = new uint8_t[BUFFER_SIZE];
   162     mInternalProxyAddr.raw.family = AF_INET;
   163     mInternalProxyAddr.inet.ip = htonl(INADDR_ANY);
   164     mInternalProxyAddr.inet.port = htons(0);
   166     mExternalProxyAddr.raw.family = AF_INET;
   167     mExternalProxyAddr.inet.ip = htonl(INADDR_ANY);
   168     mExternalProxyAddr.inet.port = htons(0);
   170     mDestinationAddr.raw.family = AF_INET;
   171     mDestinationAddr.inet.ip = htonl(INADDR_ANY);
   172     mDestinationAddr.inet.port = htons(0);
   173 }
   175 void
   176 nsSOCKSSocketInfo::Init(int32_t version, int32_t family, nsIProxyInfo *proxy, const char *host, uint32_t flags)
   177 {
   178     mVersion         = version;
   179     mDestinationFamily = family;
   180     mProxy           = proxy;
   181     mDestinationHost = host;
   182     mFlags           = flags;
   183     mProxy->GetUsername(mProxyUsername); // cache
   184 }
   186 NS_IMPL_ISUPPORTS(nsSOCKSSocketInfo, nsISOCKSSocketInfo, nsIDNSListener)
   188 NS_IMETHODIMP 
   189 nsSOCKSSocketInfo::GetExternalProxyAddr(NetAddr * *aExternalProxyAddr)
   190 {
   191     memcpy(*aExternalProxyAddr, &mExternalProxyAddr, sizeof(NetAddr));
   192     return NS_OK;
   193 }
   195 NS_IMETHODIMP 
   196 nsSOCKSSocketInfo::SetExternalProxyAddr(NetAddr *aExternalProxyAddr)
   197 {
   198     memcpy(&mExternalProxyAddr, aExternalProxyAddr, sizeof(NetAddr));
   199     return NS_OK;
   200 }
   202 NS_IMETHODIMP 
   203 nsSOCKSSocketInfo::GetDestinationAddr(NetAddr * *aDestinationAddr)
   204 {
   205     memcpy(*aDestinationAddr, &mDestinationAddr, sizeof(NetAddr));
   206     return NS_OK;
   207 }
   209 NS_IMETHODIMP 
   210 nsSOCKSSocketInfo::SetDestinationAddr(NetAddr *aDestinationAddr)
   211 {
   212     memcpy(&mDestinationAddr, aDestinationAddr, sizeof(NetAddr));
   213     return NS_OK;
   214 }
   216 NS_IMETHODIMP 
   217 nsSOCKSSocketInfo::GetInternalProxyAddr(NetAddr * *aInternalProxyAddr)
   218 {
   219     memcpy(*aInternalProxyAddr, &mInternalProxyAddr, sizeof(NetAddr));
   220     return NS_OK;
   221 }
   223 NS_IMETHODIMP 
   224 nsSOCKSSocketInfo::SetInternalProxyAddr(NetAddr *aInternalProxyAddr)
   225 {
   226     memcpy(&mInternalProxyAddr, aInternalProxyAddr, sizeof(NetAddr));
   227     return NS_OK;
   228 }
   230 // There needs to be a means of distinguishing between connection errors
   231 // that the SOCKS server reports when it rejects a connection request, and
   232 // connection errors that happen while attempting to connect to the SOCKS
   233 // server. Otherwise, Firefox will report incorrectly that the proxy server
   234 // is refusing connections when a SOCKS request is rejected by the proxy.
   235 // When a SOCKS handshake failure occurs, the PR error is set to
   236 // PR_UNKNOWN_ERROR, and the real error code is returned via the OS error.
   237 void
   238 nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err)
   239 {
   240     if (err == 0) {
   241         mState = SOCKS_CONNECTED;
   242     } else {
   243         mState = SOCKS_FAILED;
   244         PR_SetError(PR_UNKNOWN_ERROR, err);
   245     }
   247     // We don't need the buffer any longer, so free it.
   248     delete [] mData;
   249     mData = nullptr;
   250     mDataIoPtr = nullptr;
   251     mDataLength = 0;
   252     mReadOffset = 0;
   253     mAmountToRead = 0;
   254     if (mLookup) {
   255         mLookup->Cancel(NS_ERROR_FAILURE);
   256         mLookup = nullptr;
   257     }
   258 }
   260 PRStatus
   261 nsSOCKSSocketInfo::StartDNS(PRFileDesc *fd)
   262 {
   263     NS_ABORT_IF_FALSE(!mDnsRec && mState == SOCKS_INITIAL,
   264                       "Must be in initial state to make DNS Lookup");
   266     nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
   267     if (!dns)
   268         return PR_FAILURE;
   270     nsCString proxyHost;
   271     mProxy->GetHost(proxyHost);
   273     mFD  = fd;
   274     nsresult rv = dns->AsyncResolve(proxyHost, 0, this,
   275                                     NS_GetCurrentThread(),
   276                                     getter_AddRefs(mLookup));
   278     if (NS_FAILED(rv)) {
   279         LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
   280                   proxyHost.get()));
   281         return PR_FAILURE;
   282     }
   283     mState = SOCKS_DNS_IN_PROGRESS;
   284     PR_SetError(PR_IN_PROGRESS_ERROR, 0);
   285     return PR_FAILURE;
   286 }
   288 NS_IMETHODIMP
   289 nsSOCKSSocketInfo::OnLookupComplete(nsICancelable *aRequest,
   290                                     nsIDNSRecord *aRecord,
   291                                     nsresult aStatus)
   292 {
   293     NS_ABORT_IF_FALSE(aRequest == mLookup, "wrong DNS query");
   294     mLookup = nullptr;
   295     mLookupStatus = aStatus;
   296     mDnsRec = aRecord;
   297     mState = SOCKS_DNS_COMPLETE;
   298     if (mFD) {
   299       ConnectToProxy(mFD);
   300       ForgetFD();
   301     }
   302     return NS_OK;
   303 }
   305 PRStatus
   306 nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
   307 {
   308     PRStatus status;
   309     nsresult rv;
   311     NS_ABORT_IF_FALSE(mState == SOCKS_DNS_COMPLETE,
   312                       "Must have DNS to make connection!");
   314     if (NS_FAILED(mLookupStatus)) {
   315         PR_SetError(PR_BAD_ADDRESS_ERROR, 0);
   316         return PR_FAILURE;
   317     }
   319     // Try socks5 if the destination addrress is IPv6
   320     if (mVersion == 4 &&
   321         mDestinationAddr.raw.family == AF_INET6) {
   322         mVersion = 5;
   323     }
   325     int32_t proxyPort;
   326     mProxy->GetPort(&proxyPort);
   328     int32_t addresses = 0;
   329     do {
   330         if (addresses++)
   331             mDnsRec->ReportUnusable(proxyPort);
   333         rv = mDnsRec->GetNextAddr(proxyPort, &mInternalProxyAddr);
   334         // No more addresses to try? If so, we'll need to bail
   335         if (NS_FAILED(rv)) {
   336             nsCString proxyHost;
   337             mProxy->GetHost(proxyHost);
   338             LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
   339                      proxyHost.get()));
   340             return PR_FAILURE;
   341         }
   343 #if defined(PR_LOGGING)
   344         char buf[kIPv6CStrBufSize];
   345         NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
   346         LOGDEBUG(("socks: trying proxy server, %s:%hu",
   347                  buf, ntohs(mInternalProxyAddr.inet.port)));
   348 #endif
   349         NetAddr proxy = mInternalProxyAddr;
   350         FixupAddressFamily(fd, &proxy);
   351         PRNetAddr prProxy;
   352         NetAddrToPRNetAddr(&proxy, &prProxy);
   353         status = fd->lower->methods->connect(fd->lower, &prProxy, mTimeout);
   354         if (status != PR_SUCCESS) {
   355             PRErrorCode c = PR_GetError();
   356             // If EINPROGRESS, return now and check back later after polling
   357             if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
   358                 mState = SOCKS_CONNECTING_TO_PROXY;
   359                 return status;
   360             }
   361         }
   362     } while (status != PR_SUCCESS);
   364     // Connected now, start SOCKS
   365     if (mVersion == 4)
   366         return WriteV4ConnectRequest();
   367     return WriteV5AuthRequest();
   368 }
   370 void
   371 nsSOCKSSocketInfo::FixupAddressFamily(PRFileDesc *fd, NetAddr *proxy)
   372 {
   373     int32_t proxyFamily = mInternalProxyAddr.raw.family;
   374     // Do nothing if the address family is already matched
   375     if (proxyFamily == mDestinationFamily) {
   376         return;
   377     }
   378     // If the system does not support IPv6 and the proxy address is IPv6,
   379     // We can do nothing here.
   380     if (proxyFamily == AF_INET6 && !ipv6Supported) {
   381         return;
   382     }
   383     // If the system does not support IPv6 and the destination address is
   384     // IPv6, convert IPv4 address to IPv4-mapped IPv6 address to satisfy
   385     // the emulation layer
   386     if (mDestinationFamily == AF_INET6 && !ipv6Supported) {
   387         proxy->inet6.family = AF_INET6;
   388         proxy->inet6.port = mInternalProxyAddr.inet.port;
   389         uint8_t *proxyp = proxy->inet6.ip.u8;
   390         memset(proxyp, 0, 10);
   391         memset(proxyp + 10, 0xff, 2);
   392         memcpy(proxyp + 12,(char *) &mInternalProxyAddr.inet.ip, 4);
   393         // mDestinationFamily should not be updated
   394         return;
   395     }
   396     // Get an OS native handle from a specified FileDesc
   397     PROsfd osfd = PR_FileDesc2NativeHandle(fd);
   398     if (osfd == -1) {
   399         return;
   400     }
   401     // Create a new FileDesc with a specified family
   402     PRFileDesc *tmpfd = PR_OpenTCPSocket(proxyFamily);
   403     if (!tmpfd) {
   404         return;
   405     }
   406     PROsfd newsd = PR_FileDesc2NativeHandle(tmpfd);
   407     if (newsd == -1) {
   408         PR_Close(tmpfd);
   409         return;
   410     }
   411     // Must succeed because PR_FileDesc2NativeHandle succeeded
   412     fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
   413     MOZ_ASSERT(fd);
   414     // Swap OS native handles
   415     PR_ChangeFileDescNativeHandle(fd, newsd);
   416     PR_ChangeFileDescNativeHandle(tmpfd, osfd);
   417     // Close temporary FileDesc which is now associated with
   418     // old OS native handle
   419     PR_Close(tmpfd);
   420     mDestinationFamily = proxyFamily;
   421 }
   423 PRStatus
   424 nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, int16_t oflags)
   425 {
   426     PRStatus status;
   428     NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
   429                       "Continuing connection in wrong state!");
   431     LOGDEBUG(("socks: continuing connection to proxy"));
   433     status = fd->lower->methods->connectcontinue(fd->lower, oflags);
   434     if (status != PR_SUCCESS) {
   435         PRErrorCode c = PR_GetError();
   436         if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
   437             // A connection failure occured, try another address
   438             mState = SOCKS_DNS_COMPLETE;
   439             return ConnectToProxy(fd);
   440         }
   442         // We're still connecting
   443         return PR_FAILURE;
   444     }
   446     // Connected now, start SOCKS
   447     if (mVersion == 4)
   448         return WriteV4ConnectRequest();
   449     return WriteV5AuthRequest();
   450 }
   452 PRStatus
   453 nsSOCKSSocketInfo::WriteV4ConnectRequest()
   454 {
   455     if (mProxyUsername.Length() > MAX_USERNAME_LEN) {
   456         LOGERROR(("socks username is too long"));
   457         HandshakeFinished(PR_UNKNOWN_ERROR);
   458         return PR_FAILURE;
   459     }
   461     NetAddr *addr = &mDestinationAddr;
   462     int32_t proxy_resolve;
   464     NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
   465                       "Invalid state!");
   467     proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
   469     mDataLength = 0;
   470     mState = SOCKS4_WRITE_CONNECT_REQUEST;
   472     LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
   473              proxy_resolve? "yes" : "no"));
   475     // Send a SOCKS 4 connect request.
   476     WriteUint8(0x04); // version -- 4
   477     WriteUint8(0x01); // command -- connect
   478     WriteNetPort(addr);
   479     if (proxy_resolve) {
   480         // Add the full name, null-terminated, to the request
   481         // according to SOCKS 4a. A fake IP address, with the first
   482         // four bytes set to 0 and the last byte set to something other
   483         // than 0, is used to notify the proxy that this is a SOCKS 4a
   484         // request. This request type works for Tor and perhaps others.
   485         WriteUint32(htonl(0x00000001)); // Fake IP
   486         WriteString(mProxyUsername); // Send username. May be empty.
   487         WriteUint8(0x00); // Null-terminate username
   488         // Password not supported by V4.
   489         if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
   490             LOGERROR(("socks4: destination host name is too long!"));
   491             HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   492             return PR_FAILURE;
   493         }
   494         WriteString(mDestinationHost); // Hostname
   495         WriteUint8(0x00);
   496     } else if (addr->raw.family == AF_INET) {
   497         WriteNetAddr(addr); // Add the IPv4 address
   498         WriteString(mProxyUsername); // Send username. May be empty.
   499         WriteUint8(0x00); // Null-terminate username
   500         // Password not supported by V4.
   501     } else if (addr->raw.family == AF_INET6) {
   502         LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
   503         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   504         return PR_FAILURE;
   505     }
   507     return PR_SUCCESS;
   508 }
   510 PRStatus
   511 nsSOCKSSocketInfo::ReadV4ConnectResponse()
   512 {
   513     NS_ABORT_IF_FALSE(mState == SOCKS4_READ_CONNECT_RESPONSE,
   514                       "Handling SOCKS 4 connection reply in wrong state!");
   516     LOGDEBUG(("socks4: checking connection reply"));
   518     if (mDataLength != 8) {
   519         LOGERROR(("SOCKS 4 connection reply must be 8 bytes!"));
   520         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   521         return PR_FAILURE;
   522     }
   524     if (ReadUint8() != 0x00) {
   525         LOGERROR(("socks4: wrong connection reply"));
   526         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   527         return PR_FAILURE;
   528     }
   530     // See if our connection request was granted
   531     if (ReadUint8() == 90) {
   532         LOGDEBUG(("socks4: connection successful!"));
   533         HandshakeFinished();
   534         return PR_SUCCESS;
   535     }
   537     LOGERROR(("socks4: unable to connect"));
   538     HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   539     return PR_FAILURE;
   540 }
   542 PRStatus
   543 nsSOCKSSocketInfo::WriteV5AuthRequest()
   544 {
   545     NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
   547     mDataLength = 0;
   548     mState = SOCKS5_WRITE_AUTH_REQUEST;
   550     // Send an initial SOCKS 5 greeting
   551     LOGDEBUG(("socks5: sending auth methods"));
   552     WriteUint8(0x05); // version -- 5
   553     WriteUint8(0x01); // # of auth methods -- 1
   554     if (mProxyUsername.IsEmpty()) {
   555       WriteUint8(0x00); // no authentication
   556     } else {
   557       WriteUint8(0x02); // username/password
   558     }
   560     return PR_SUCCESS;
   561 }
   563 PRStatus
   564 nsSOCKSSocketInfo::ReadV5AuthResponse()
   565 {
   566     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_AUTH_RESPONSE,
   567                       "Handling SOCKS 5 auth method reply in wrong state!");
   569     if (mDataLength != 2) {
   570         LOGERROR(("SOCKS 5 auth method reply must be 2 bytes"));
   571         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   572         return PR_FAILURE;
   573     }
   575     // Check version number
   576     if (ReadUint8() != 0x05) {
   577         LOGERROR(("socks5: unexpected version in the reply"));
   578         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   579         return PR_FAILURE;
   580     }
   582     // Make sure our authentication choice was accepted,
   583     // and continue accordingly
   584     uint8_t authMethod = ReadUint8();
   585     if (mProxyUsername.IsEmpty() && authMethod == 0x00) { // no auth
   586         LOGDEBUG(("socks5: server allows connection without authentication"));
   587         return WriteV5ConnectRequest();
   588     } else if (!mProxyUsername.IsEmpty() && authMethod == 0x02) { // username/pw
   589         LOGDEBUG(("socks5: auth method accepted by server"));
   590         return WriteV5UsernameRequest();
   591     } else { // 0xFF signals error
   592         LOGERROR(("socks5: server did not accept our authentication method"));
   593         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   594         return PR_FAILURE;
   595     }
   596 }
   598 PRStatus
   599 nsSOCKSSocketInfo::WriteV5UsernameRequest()
   600 {
   601     NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
   603     if (mProxyUsername.Length() > MAX_USERNAME_LEN) {
   604         LOGERROR(("socks username is too long"));
   605         HandshakeFinished(PR_UNKNOWN_ERROR);
   606         return PR_FAILURE;
   607     }
   609     nsCString password;
   610     mProxy->GetPassword(password);
   611     if (password.Length() > MAX_PASSWORD_LEN) {
   612         LOGERROR(("socks password is too long"));
   613         HandshakeFinished(PR_UNKNOWN_ERROR);
   614         return PR_FAILURE;
   615     }
   617     mDataLength = 0;
   618     mState = SOCKS5_WRITE_USERNAME_REQUEST;
   620     LOGDEBUG(("socks5: sending username and password"));
   621     // RFC 1929 Username/password auth for SOCKS 5
   622     WriteUint8(0x01); // version 1 (not 5)
   623     WriteUint8(mProxyUsername.Length()); // username length
   624     WriteString(mProxyUsername); // username
   625     WriteUint8(password.Length()); // password length
   626     WriteString(password); // password. WARNING: Sent unencrypted!
   628     return PR_SUCCESS;
   629 }
   631 PRStatus
   632 nsSOCKSSocketInfo::ReadV5UsernameResponse()
   633 {
   634     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_USERNAME_RESPONSE,
   635                       "Handling SOCKS 5 username/password reply in wrong state!");
   637     if (mDataLength != 2) {
   638         LOGERROR(("SOCKS 5 username reply must be 2 bytes"));
   639         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   640         return PR_FAILURE;
   641     }
   643     // Check version number, must be 1 (not 5)
   644     if (ReadUint8() != 0x01) {
   645         LOGERROR(("socks5: unexpected version in the reply"));
   646         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   647         return PR_FAILURE;
   648     }
   650     // Check whether username/password were accepted
   651     if (ReadUint8() != 0x00) { // 0 = success
   652         LOGERROR(("socks5: username/password not accepted"));
   653         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   654         return PR_FAILURE;
   655     }
   657     LOGDEBUG(("socks5: username/password accepted by server"));
   659     return WriteV5ConnectRequest();
   660 }
   662 PRStatus
   663 nsSOCKSSocketInfo::WriteV5ConnectRequest()
   664 {
   665     // Send SOCKS 5 connect request
   666     NetAddr *addr = &mDestinationAddr;
   667     int32_t proxy_resolve;
   668     proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
   670     LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
   671              proxy_resolve? "yes" : "no"));
   673     mDataLength = 0;
   674     mState = SOCKS5_WRITE_CONNECT_REQUEST;
   676     WriteUint8(0x05); // version -- 5
   677     WriteUint8(0x01); // command -- connect
   678     WriteUint8(0x00); // reserved
   680     // Add the address to the SOCKS 5 request. SOCKS 5 supports several
   681     // address types, so we pick the one that works best for us.
   682     if (proxy_resolve) {
   683         // Add the host name. Only a single byte is used to store the length,
   684         // so we must prevent long names from being used.
   685         if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
   686             LOGERROR(("socks5: destination host name is too long!"));
   687             HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   688             return PR_FAILURE;
   689         }
   690         WriteUint8(0x03); // addr type -- domainname
   691         WriteUint8(mDestinationHost.Length()); // name length
   692         WriteString(mDestinationHost);
   693     } else if (addr->raw.family == AF_INET) {
   694         WriteUint8(0x01); // addr type -- IPv4
   695         WriteNetAddr(addr);
   696     } else if (addr->raw.family == AF_INET6) {
   697         WriteUint8(0x04); // addr type -- IPv6
   698         WriteNetAddr(addr);
   699     } else {
   700         LOGERROR(("socks5: destination address of unknown type!"));
   701         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   702         return PR_FAILURE;
   703     }
   705     WriteNetPort(addr); // port
   707     return PR_SUCCESS;
   708 }
   710 PRStatus
   711 nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(uint8_t *type, uint32_t *len)
   712 {
   713     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP ||
   714                       mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
   715                       "Invalid state!");
   716     NS_ABORT_IF_FALSE(mDataLength >= 5,
   717                       "SOCKS 5 connection reply must be at least 5 bytes!");
   719     // Seek to the address location 
   720     mReadOffset = 3;
   722     *type = ReadUint8();
   724     switch (*type) {
   725         case 0x01: // ipv4
   726             *len = 4 - 1;
   727             break;
   728         case 0x04: // ipv6
   729             *len = 16 - 1;
   730             break;
   731         case 0x03: // fqdn
   732             *len = ReadUint8();
   733             break;
   734         default:   // wrong address type
   735             LOGERROR(("socks5: wrong address type in connection reply!"));
   736             return PR_FAILURE;
   737     }
   739     return PR_SUCCESS;
   740 }
   742 PRStatus
   743 nsSOCKSSocketInfo::ReadV5ConnectResponseTop()
   744 {
   745     uint8_t res;
   746     uint32_t len;
   748     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP,
   749                       "Invalid state!");
   750     NS_ABORT_IF_FALSE(mDataLength == 5,
   751                       "SOCKS 5 connection reply must be exactly 5 bytes!");
   753     LOGDEBUG(("socks5: checking connection reply"));
   755     // Check version number
   756     if (ReadUint8() != 0x05) {
   757         LOGERROR(("socks5: unexpected version in the reply"));
   758         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
   759         return PR_FAILURE;
   760     }
   762     // Check response
   763     res = ReadUint8();
   764     if (res != 0x00) {
   765         PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
   767         switch (res) {
   768             case 0x01:
   769                 LOGERROR(("socks5: connect failed: "
   770                           "01, General SOCKS server failure."));
   771                 break;
   772             case 0x02:
   773                 LOGERROR(("socks5: connect failed: "
   774                           "02, Connection not allowed by ruleset."));
   775                 break;
   776             case 0x03:
   777                 LOGERROR(("socks5: connect failed: 03, Network unreachable."));
   778                 c = PR_NETWORK_UNREACHABLE_ERROR;
   779                 break;
   780             case 0x04:
   781                 LOGERROR(("socks5: connect failed: 04, Host unreachable."));
   782                 break;
   783             case 0x05:
   784                 LOGERROR(("socks5: connect failed: 05, Connection refused."));
   785                 break;
   786             case 0x06:  
   787                 LOGERROR(("socks5: connect failed: 06, TTL expired."));
   788                 c = PR_CONNECT_TIMEOUT_ERROR;
   789                 break;
   790             case 0x07:
   791                 LOGERROR(("socks5: connect failed: "
   792                           "07, Command not supported."));
   793                 break;
   794             case 0x08:
   795                 LOGERROR(("socks5: connect failed: "
   796                           "08, Address type not supported."));
   797                 c = PR_BAD_ADDRESS_ERROR;
   798                 break;
   799             default:
   800                 LOGERROR(("socks5: connect failed."));
   801                 break;
   802         }
   804         HandshakeFinished(c);
   805         return PR_FAILURE;
   806     }
   808     if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) {
   809         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   810         return PR_FAILURE;
   811     }
   813     mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM;
   814     WantRead(len + 2);
   816     return PR_SUCCESS;
   817 }
   819 PRStatus
   820 nsSOCKSSocketInfo::ReadV5ConnectResponseBottom()
   821 {
   822     uint8_t type;
   823     uint32_t len;
   825     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
   826                       "Invalid state!");
   828     if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) {
   829         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
   830         return PR_FAILURE;
   831     }
   833     NS_ABORT_IF_FALSE(mDataLength == 7+len,
   834                       "SOCKS 5 unexpected length of connection reply!");
   836     LOGDEBUG(("socks5: loading source addr and port"));
   837     // Read what the proxy says is our source address
   838     switch (type) {
   839         case 0x01: // ipv4
   840             ReadNetAddr(&mExternalProxyAddr, AF_INET);
   841             break;
   842         case 0x04: // ipv6
   843             ReadNetAddr(&mExternalProxyAddr, AF_INET6);
   844             break;
   845         case 0x03: // fqdn (skip)
   846             mReadOffset += len;
   847             mExternalProxyAddr.raw.family = AF_INET;
   848             break;
   849     }
   851     ReadNetPort(&mExternalProxyAddr);
   853     LOGDEBUG(("socks5: connected!"));
   854     HandshakeFinished();
   856     return PR_SUCCESS;
   857 }
   859 void
   860 nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to)
   861 {
   862     mTimeout = to;
   863 }
   865 PRStatus
   866 nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, int16_t oflags)
   867 {
   868     LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
   870     switch (mState) {
   871         case SOCKS_INITIAL:
   872             return StartDNS(fd);
   873         case SOCKS_DNS_IN_PROGRESS:
   874             PR_SetError(PR_IN_PROGRESS_ERROR, 0);
   875             return PR_FAILURE;
   876         case SOCKS_DNS_COMPLETE:
   877             return ConnectToProxy(fd);
   878         case SOCKS_CONNECTING_TO_PROXY:
   879             return ContinueConnectingToProxy(fd, oflags);
   880         case SOCKS4_WRITE_CONNECT_REQUEST:
   881             if (WriteToSocket(fd) != PR_SUCCESS)
   882                 return PR_FAILURE;
   883             WantRead(8);
   884             mState = SOCKS4_READ_CONNECT_RESPONSE;
   885             return PR_SUCCESS;
   886         case SOCKS4_READ_CONNECT_RESPONSE:
   887             if (ReadFromSocket(fd) != PR_SUCCESS)
   888                 return PR_FAILURE;
   889             return ReadV4ConnectResponse();
   891         case SOCKS5_WRITE_AUTH_REQUEST:
   892             if (WriteToSocket(fd) != PR_SUCCESS)
   893                 return PR_FAILURE;
   894             WantRead(2);
   895             mState = SOCKS5_READ_AUTH_RESPONSE;
   896             return PR_SUCCESS;
   897         case SOCKS5_READ_AUTH_RESPONSE:
   898             if (ReadFromSocket(fd) != PR_SUCCESS)
   899                 return PR_FAILURE;
   900             return ReadV5AuthResponse();
   901         case SOCKS5_WRITE_USERNAME_REQUEST:
   902             if (WriteToSocket(fd) != PR_SUCCESS)
   903                 return PR_FAILURE;
   904             WantRead(2);
   905             mState = SOCKS5_READ_USERNAME_RESPONSE;
   906             return PR_SUCCESS;
   907         case SOCKS5_READ_USERNAME_RESPONSE:
   908             if (ReadFromSocket(fd) != PR_SUCCESS)
   909                 return PR_FAILURE;
   910             return ReadV5UsernameResponse();
   911         case SOCKS5_WRITE_CONNECT_REQUEST:
   912             if (WriteToSocket(fd) != PR_SUCCESS)
   913                 return PR_FAILURE;
   915             // The SOCKS 5 response to the connection request is variable
   916             // length. First, we'll read enough to tell how long the response
   917             // is, and will read the rest later.
   918             WantRead(5);
   919             mState = SOCKS5_READ_CONNECT_RESPONSE_TOP;
   920             return PR_SUCCESS;
   921         case SOCKS5_READ_CONNECT_RESPONSE_TOP:
   922             if (ReadFromSocket(fd) != PR_SUCCESS)
   923                 return PR_FAILURE;
   924             return ReadV5ConnectResponseTop();
   925         case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
   926             if (ReadFromSocket(fd) != PR_SUCCESS)
   927                 return PR_FAILURE;
   928             return ReadV5ConnectResponseBottom();
   930         case SOCKS_CONNECTED:
   931             LOGERROR(("socks: already connected"));
   932             HandshakeFinished(PR_IS_CONNECTED_ERROR);
   933             return PR_FAILURE;
   934         case SOCKS_FAILED:
   935             LOGERROR(("socks: already failed"));
   936             return PR_FAILURE;
   937     }
   939     LOGERROR(("socks: executing handshake in invalid state, %d", mState));
   940     HandshakeFinished(PR_INVALID_STATE_ERROR);
   942     return PR_FAILURE;
   943 }
   945 int16_t
   946 nsSOCKSSocketInfo::GetPollFlags() const
   947 {
   948     switch (mState) {
   949         case SOCKS_DNS_IN_PROGRESS:
   950         case SOCKS_DNS_COMPLETE:
   951         case SOCKS_CONNECTING_TO_PROXY:
   952             return PR_POLL_EXCEPT | PR_POLL_WRITE;
   953         case SOCKS4_WRITE_CONNECT_REQUEST:
   954         case SOCKS5_WRITE_AUTH_REQUEST:
   955         case SOCKS5_WRITE_USERNAME_REQUEST:
   956         case SOCKS5_WRITE_CONNECT_REQUEST:
   957             return PR_POLL_WRITE;
   958         case SOCKS4_READ_CONNECT_RESPONSE:
   959         case SOCKS5_READ_AUTH_RESPONSE:
   960         case SOCKS5_READ_USERNAME_RESPONSE:
   961         case SOCKS5_READ_CONNECT_RESPONSE_TOP:
   962         case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
   963             return PR_POLL_READ;
   964         default:
   965             break;
   966     }
   968     return 0;
   969 }
   971 inline void
   972 nsSOCKSSocketInfo::WriteUint8(uint8_t v)
   973 {
   974     MOZ_RELEASE_ASSERT(mDataLength + sizeof(v) <= BUFFER_SIZE,
   975                       "Can't write that much data!");
   976     mData[mDataLength] = v;
   977     mDataLength += sizeof(v);
   978 }
   980 inline void
   981 nsSOCKSSocketInfo::WriteUint16(uint16_t v)
   982 {
   983     MOZ_RELEASE_ASSERT(mDataLength + sizeof(v) <= BUFFER_SIZE,
   984                       "Can't write that much data!");
   985     memcpy(mData + mDataLength, &v, sizeof(v));
   986     mDataLength += sizeof(v);
   987 }
   989 inline void
   990 nsSOCKSSocketInfo::WriteUint32(uint32_t v)
   991 {
   992     MOZ_RELEASE_ASSERT(mDataLength + sizeof(v) <= BUFFER_SIZE,
   993                       "Can't write that much data!");
   994     memcpy(mData + mDataLength, &v, sizeof(v));
   995     mDataLength += sizeof(v);
   996 }
   998 void
   999 nsSOCKSSocketInfo::WriteNetAddr(const NetAddr *addr)
  1001     const char *ip = nullptr;
  1002     uint32_t len = 0;
  1004     if (addr->raw.family == AF_INET) {
  1005         ip = (const char*)&addr->inet.ip;
  1006         len = sizeof(addr->inet.ip);
  1007     } else if (addr->raw.family == AF_INET6) {
  1008         ip = (const char*)addr->inet6.ip.u8;
  1009         len = sizeof(addr->inet6.ip.u8);
  1012     MOZ_RELEASE_ASSERT(ip != nullptr, "Unknown address");
  1013     MOZ_RELEASE_ASSERT(mDataLength + len <= BUFFER_SIZE,
  1014                       "Can't write that much data!");
  1016     memcpy(mData + mDataLength, ip, len);
  1017     mDataLength += len;
  1020 void
  1021 nsSOCKSSocketInfo::WriteNetPort(const NetAddr *addr)
  1023     WriteUint16(addr->inet.port);
  1026 void
  1027 nsSOCKSSocketInfo::WriteString(const nsACString &str)
  1029     MOZ_RELEASE_ASSERT(mDataLength + str.Length() <= BUFFER_SIZE,
  1030                       "Can't write that much data!");
  1031     memcpy(mData + mDataLength, str.Data(), str.Length());
  1032     mDataLength += str.Length();
  1035 inline uint8_t
  1036 nsSOCKSSocketInfo::ReadUint8()
  1038     uint8_t rv;
  1039     MOZ_RELEASE_ASSERT(mReadOffset + sizeof(rv) <= mDataLength,
  1040                       "Not enough space to pop a uint8_t!");
  1041     rv = mData[mReadOffset];
  1042     mReadOffset += sizeof(rv);
  1043     return rv;
  1046 inline uint16_t
  1047 nsSOCKSSocketInfo::ReadUint16()
  1049     uint16_t rv;
  1050     MOZ_RELEASE_ASSERT(mReadOffset + sizeof(rv) <= mDataLength,
  1051                       "Not enough space to pop a uint16_t!");
  1052     memcpy(&rv, mData + mReadOffset, sizeof(rv));
  1053     mReadOffset += sizeof(rv);
  1054     return rv;
  1057 inline uint32_t
  1058 nsSOCKSSocketInfo::ReadUint32()
  1060     uint32_t rv;
  1061     MOZ_RELEASE_ASSERT(mReadOffset + sizeof(rv) <= mDataLength,
  1062                       "Not enough space to pop a uint32_t!");
  1063     memcpy(&rv, mData + mReadOffset, sizeof(rv));
  1064     mReadOffset += sizeof(rv);
  1065     return rv;
  1068 void
  1069 nsSOCKSSocketInfo::ReadNetAddr(NetAddr *addr, uint16_t fam)
  1071     uint32_t amt = 0;
  1072     const uint8_t *ip = mData + mReadOffset;
  1074     addr->raw.family = fam;
  1075     if (fam == AF_INET) {
  1076         amt = sizeof(addr->inet.ip);
  1077         MOZ_RELEASE_ASSERT(mReadOffset + amt <= mDataLength,
  1078                           "Not enough space to pop an ipv4 addr!");
  1079         memcpy(&addr->inet.ip, ip, amt);
  1080     } else if (fam == AF_INET6) {
  1081         amt = sizeof(addr->inet6.ip.u8);
  1082         MOZ_RELEASE_ASSERT(mReadOffset + amt <= mDataLength,
  1083                           "Not enough space to pop an ipv6 addr!");
  1084         memcpy(addr->inet6.ip.u8, ip, amt);
  1087     mReadOffset += amt;
  1090 void
  1091 nsSOCKSSocketInfo::ReadNetPort(NetAddr *addr)
  1093     addr->inet.port = ReadUint16();
  1096 void
  1097 nsSOCKSSocketInfo::WantRead(uint32_t sz)
  1099     NS_ABORT_IF_FALSE(mDataIoPtr == nullptr,
  1100                       "WantRead() called while I/O already in progress!");
  1101     MOZ_RELEASE_ASSERT(mDataLength + sz <= BUFFER_SIZE,
  1102                       "Can't read that much data!");
  1103     mAmountToRead = sz;
  1106 PRStatus
  1107 nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc *fd)
  1109     int32_t rc;
  1110     const uint8_t *end;
  1112     if (!mAmountToRead) {
  1113         LOGDEBUG(("socks: ReadFromSocket(), nothing to do"));
  1114         return PR_SUCCESS;
  1117     if (!mDataIoPtr) {
  1118         mDataIoPtr = mData + mDataLength;
  1119         mDataLength += mAmountToRead;
  1122     end = mData + mDataLength;
  1124     while (mDataIoPtr < end) {
  1125         rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr);
  1126         if (rc <= 0) {
  1127             if (rc == 0) {
  1128                 LOGERROR(("socks: proxy server closed connection"));
  1129                 HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
  1130                 return PR_FAILURE;
  1131             } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
  1132                 LOGDEBUG(("socks: ReadFromSocket(), want read"));
  1134             break;
  1137         mDataIoPtr += rc;
  1140     LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total",
  1141              unsigned(mDataIoPtr - mData)));
  1142     if (mDataIoPtr == end) {
  1143         mDataIoPtr = nullptr;
  1144         mAmountToRead = 0;
  1145         mReadOffset = 0;
  1146         return PR_SUCCESS;
  1149     return PR_FAILURE;
  1152 PRStatus
  1153 nsSOCKSSocketInfo::WriteToSocket(PRFileDesc *fd)
  1155     int32_t rc;
  1156     const uint8_t *end;
  1158     if (!mDataLength) {
  1159         LOGDEBUG(("socks: WriteToSocket(), nothing to do"));
  1160         return PR_SUCCESS;
  1163     if (!mDataIoPtr)
  1164         mDataIoPtr = mData;
  1166     end = mData + mDataLength;
  1168     while (mDataIoPtr < end) {
  1169         rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr);
  1170         if (rc < 0) {
  1171             if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
  1172                 LOGDEBUG(("socks: WriteToSocket(), want write"));
  1174             break;
  1177         mDataIoPtr += rc;
  1180     if (mDataIoPtr == end) {
  1181         mDataIoPtr = nullptr;
  1182         mDataLength = 0;
  1183         mReadOffset = 0;
  1184         return PR_SUCCESS;
  1187     return PR_FAILURE;
  1190 static PRStatus
  1191 nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
  1193     PRStatus status;
  1194     NetAddr dst;
  1196     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1197     if (info == nullptr) return PR_FAILURE;
  1199     if (addr->raw.family == PR_AF_INET6 &&
  1200         PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
  1201         const uint8_t *srcp;
  1203         LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
  1205         // copied from _PR_ConvertToIpv4NetAddr()
  1206         dst.raw.family = AF_INET;
  1207         dst.inet.ip = htonl(INADDR_ANY);
  1208         dst.inet.port = htons(0);
  1209         srcp = addr->ipv6.ip.pr_s6_addr;
  1210         memcpy(&dst.inet.ip, srcp + 12, 4);
  1211         dst.inet.family = AF_INET;
  1212         dst.inet.port = addr->ipv6.port;
  1213     } else {
  1214         memcpy(&dst, addr, sizeof(dst));
  1217     info->SetDestinationAddr(&dst);
  1218     info->SetConnectTimeout(to);
  1220     do {
  1221         status = info->DoHandshake(fd, -1);
  1222     } while (status == PR_SUCCESS && !info->IsConnected());
  1224     return status;
  1227 static PRStatus
  1228 nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, int16_t oflags)
  1230     PRStatus status;
  1232     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1233     if (info == nullptr) return PR_FAILURE;
  1235     do { 
  1236         status = info->DoHandshake(fd, oflags);
  1237     } while (status == PR_SUCCESS && !info->IsConnected());
  1239     return status;
  1242 static int16_t
  1243 nsSOCKSIOLayerPoll(PRFileDesc *fd, int16_t in_flags, int16_t *out_flags)
  1245     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1246     if (info == nullptr) return PR_FAILURE;
  1248     if (!info->IsConnected()) {
  1249         *out_flags = 0;
  1250         return info->GetPollFlags();
  1253     return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
  1256 static PRStatus
  1257 nsSOCKSIOLayerClose(PRFileDesc *fd)
  1259     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1260     PRDescIdentity id = PR_GetLayersIdentity(fd);
  1262     if (info && id == nsSOCKSIOLayerIdentity)
  1264         info->ForgetFD();
  1265         NS_RELEASE(info);
  1266         fd->identity = PR_INVALID_IO_LAYER;
  1269     return fd->lower->methods->close(fd->lower);
  1272 static PRFileDesc*
  1273 nsSOCKSIOLayerAccept(PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
  1275     // TODO: implement SOCKS support for accept
  1276     return fd->lower->methods->accept(fd->lower, addr, timeout);
  1279 static int32_t
  1280 nsSOCKSIOLayerAcceptRead(PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, int32_t amount, PRIntervalTime timeout)
  1282     // TODO: implement SOCKS support for accept, then read from it
  1283     return sd->lower->methods->acceptread(sd->lower, nd, raddr, buf, amount, timeout);
  1286 static PRStatus
  1287 nsSOCKSIOLayerBind(PRFileDesc *fd, const PRNetAddr *addr)
  1289     // TODO: implement SOCKS support for bind (very similar to connect)
  1290     return fd->lower->methods->bind(fd->lower, addr);
  1293 static PRStatus
  1294 nsSOCKSIOLayerGetName(PRFileDesc *fd, PRNetAddr *addr)
  1296     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1298     if (info != nullptr && addr != nullptr) {
  1299         NetAddr temp;
  1300         NetAddr *tempPtr = &temp;
  1301         if (info->GetExternalProxyAddr(&tempPtr) == NS_OK) {
  1302             NetAddrToPRNetAddr(tempPtr, addr);
  1303             return PR_SUCCESS;
  1307     return PR_FAILURE;
  1310 static PRStatus
  1311 nsSOCKSIOLayerGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  1313     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1315     if (info != nullptr && addr != nullptr) {
  1316         NetAddr temp;
  1317         NetAddr *tempPtr = &temp;
  1318         if (info->GetDestinationAddr(&tempPtr) == NS_OK) {
  1319             NetAddrToPRNetAddr(tempPtr, addr);
  1320             return PR_SUCCESS;
  1324     return PR_FAILURE;
  1327 static PRStatus
  1328 nsSOCKSIOLayerListen(PRFileDesc *fd, int backlog)
  1330     // TODO: implement SOCKS support for listen
  1331     return fd->lower->methods->listen(fd->lower, backlog);
  1334 // add SOCKS IO layer to an existing socket
  1335 nsresult
  1336 nsSOCKSIOLayerAddToSocket(int32_t family,
  1337                           const char *host, 
  1338                           int32_t port,
  1339                           nsIProxyInfo *proxy,
  1340                           int32_t socksVersion,
  1341                           uint32_t flags,
  1342                           PRFileDesc *fd, 
  1343                           nsISupports** info)
  1345     NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), NS_ERROR_NOT_INITIALIZED);
  1348     if (firstTime)
  1350         //XXX hack until NSPR provides an official way to detect system IPv6
  1351         // support (bug 388519)
  1352         PRFileDesc *tmpfd = PR_OpenTCPSocket(PR_AF_INET6);
  1353         if (!tmpfd) {
  1354             ipv6Supported = false;
  1355         } else {
  1356             // If the system does not support IPv6, NSPR will push
  1357             // IPv6-to-IPv4 emulation layer onto the native layer
  1358             ipv6Supported = PR_GetIdentitiesLayer(tmpfd, PR_NSPR_IO_LAYER) == tmpfd;
  1359             PR_Close(tmpfd);
  1362         nsSOCKSIOLayerIdentity = PR_GetUniqueIdentity("SOCKS layer");
  1363         nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods();
  1365         nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect;
  1366         nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue;
  1367         nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll;
  1368         nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind;
  1369         nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
  1370         nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
  1371         nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName;
  1372         nsSOCKSIOLayerMethods.accept = nsSOCKSIOLayerAccept;
  1373         nsSOCKSIOLayerMethods.listen = nsSOCKSIOLayerListen;
  1374         nsSOCKSIOLayerMethods.close = nsSOCKSIOLayerClose;
  1376         firstTime = false;
  1378 #if defined(PR_LOGGING)
  1379         gSOCKSLog = PR_NewLogModule("SOCKS");
  1380 #endif
  1384     LOGDEBUG(("Entering nsSOCKSIOLayerAddToSocket()."));
  1386     PRFileDesc *layer;
  1387     PRStatus rv;
  1389     layer = PR_CreateIOLayerStub(nsSOCKSIOLayerIdentity, &nsSOCKSIOLayerMethods);
  1390     if (! layer)
  1392         LOGERROR(("PR_CreateIOLayerStub() failed."));
  1393         return NS_ERROR_FAILURE;
  1396     nsSOCKSSocketInfo * infoObject = new nsSOCKSSocketInfo();
  1397     if (!infoObject)
  1399         // clean up IOLayerStub
  1400         LOGERROR(("Failed to create nsSOCKSSocketInfo()."));
  1401         PR_DELETE(layer);
  1402         return NS_ERROR_FAILURE;
  1405     NS_ADDREF(infoObject);
  1406     infoObject->Init(socksVersion, family, proxy, host, flags);
  1407     layer->secret = (PRFilePrivate*) infoObject;
  1408     rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer);
  1410     if (rv == PR_FAILURE) {
  1411         LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv));
  1412         NS_RELEASE(infoObject);
  1413         PR_DELETE(layer);
  1414         return NS_ERROR_FAILURE;
  1417     *info = static_cast<nsISOCKSSocketInfo*>(infoObject);
  1418     NS_ADDREF(*info);
  1419     return NS_OK;

mercurial