LCOV - code coverage report
Current view: directory - netwerk/socket - nsSOCKSIOLayer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 516 0 0.0 %
Date: 2012-06-02 Functions: 52 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Justin Bradford <jab@atdot.org>
      25                 :  *   Bradley Baetz <bbaetz@acm.org>
      26                 :  *   Darin Fisher <darin@meer.net>
      27                 :  *   Malcolm Smith <malsmith@cs.rmit.edu.au>
      28                 :  *   Christopher Davis <chrisd@torproject.org>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      32                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK ***** */
      43                 : 
      44                 : #include "nspr.h"
      45                 : #include "nsString.h"
      46                 : #include "nsCRT.h"
      47                 : 
      48                 : #include "nsIServiceManager.h"
      49                 : #include "nsIDNSService.h"
      50                 : #include "nsIDNSRecord.h"
      51                 : #include "nsISOCKSSocketInfo.h"
      52                 : #include "nsISocketProvider.h"
      53                 : #include "nsSOCKSIOLayer.h"
      54                 : #include "nsNetCID.h"
      55                 : 
      56                 : static PRDescIdentity   nsSOCKSIOLayerIdentity;
      57                 : static PRIOMethods      nsSOCKSIOLayerMethods;
      58                 : static bool firstTime = true;
      59                 : 
      60                 : #if defined(PR_LOGGING)
      61                 : static PRLogModuleInfo *gSOCKSLog;
      62                 : #define LOGDEBUG(args) PR_LOG(gSOCKSLog, PR_LOG_DEBUG, args)
      63                 : #define LOGERROR(args) PR_LOG(gSOCKSLog, PR_LOG_ERROR , args)
      64                 : 
      65                 : #else
      66                 : #define LOGDEBUG(args)
      67                 : #define LOGERROR(args)
      68                 : #endif
      69                 : 
      70                 : class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
      71                 : {
      72                 :     enum State {
      73                 :         SOCKS_INITIAL,
      74                 :         SOCKS_CONNECTING_TO_PROXY,
      75                 :         SOCKS4_WRITE_CONNECT_REQUEST,
      76                 :         SOCKS4_READ_CONNECT_RESPONSE,
      77                 :         SOCKS5_WRITE_AUTH_REQUEST,
      78                 :         SOCKS5_READ_AUTH_RESPONSE,
      79                 :         SOCKS5_WRITE_CONNECT_REQUEST,
      80                 :         SOCKS5_READ_CONNECT_RESPONSE_TOP,
      81                 :         SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
      82                 :         SOCKS_CONNECTED,
      83                 :         SOCKS_FAILED
      84                 :     };
      85                 : 
      86                 :     // A buffer of 262 bytes should be enough for any request and response
      87                 :     // in case of SOCKS4 as well as SOCKS5
      88                 :     static const PRUint32 BUFFER_SIZE = 262;
      89                 :     static const PRUint32 MAX_HOSTNAME_LEN = 255;
      90                 : 
      91                 : public:
      92                 :     nsSOCKSSocketInfo();
      93               0 :     virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); }
      94                 : 
      95                 :     NS_DECL_ISUPPORTS
      96                 :     NS_DECL_NSISOCKSSOCKETINFO
      97                 : 
      98                 :     void Init(PRInt32 version,
      99                 :               const char *proxyHost,
     100                 :               PRInt32 proxyPort,
     101                 :               const char *destinationHost,
     102                 :               PRUint32 flags);
     103                 : 
     104                 :     void SetConnectTimeout(PRIntervalTime to);
     105                 :     PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1);
     106                 :     PRInt16 GetPollFlags() const;
     107               0 :     bool IsConnected() const { return mState == SOCKS_CONNECTED; }
     108                 : 
     109                 : private:
     110                 :     void HandshakeFinished(PRErrorCode err = 0);
     111                 :     PRStatus ConnectToProxy(PRFileDesc *fd);
     112                 :     PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags);
     113                 :     PRStatus WriteV4ConnectRequest();
     114                 :     PRStatus ReadV4ConnectResponse();
     115                 :     PRStatus WriteV5AuthRequest();
     116                 :     PRStatus ReadV5AuthResponse();
     117                 :     PRStatus WriteV5ConnectRequest();
     118                 :     PRStatus ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len);
     119                 :     PRStatus ReadV5ConnectResponseTop();
     120                 :     PRStatus ReadV5ConnectResponseBottom();
     121                 : 
     122                 :     void WriteUint8(PRUint8 d);
     123                 :     void WriteUint16(PRUint16 d);
     124                 :     void WriteUint32(PRUint32 d);
     125                 :     void WriteNetAddr(const PRNetAddr *addr);
     126                 :     void WriteNetPort(const PRNetAddr *addr);
     127                 :     void WriteString(const nsACString &str);
     128                 : 
     129                 :     PRUint8 ReadUint8();
     130                 :     PRUint16 ReadUint16();
     131                 :     PRUint32 ReadUint32();
     132                 :     void ReadNetAddr(PRNetAddr *addr, PRUint16 fam);
     133                 :     void ReadNetPort(PRNetAddr *addr);
     134                 : 
     135                 :     void WantRead(PRUint32 sz);
     136                 :     PRStatus ReadFromSocket(PRFileDesc *fd);
     137                 :     PRStatus WriteToSocket(PRFileDesc *fd);
     138                 : 
     139                 : private:
     140                 :     State     mState;
     141                 :     PRUint8 * mData;
     142                 :     PRUint8 * mDataIoPtr;
     143                 :     PRUint32  mDataLength;
     144                 :     PRUint32  mReadOffset;
     145                 :     PRUint32  mAmountToRead;
     146                 :     nsCOMPtr<nsIDNSRecord> mDnsRec;
     147                 : 
     148                 :     nsCString mDestinationHost;
     149                 :     nsCString mProxyHost;
     150                 :     PRInt32   mProxyPort;
     151                 :     PRInt32   mVersion;   // SOCKS version 4 or 5
     152                 :     PRUint32  mFlags;
     153                 :     PRNetAddr mInternalProxyAddr;
     154                 :     PRNetAddr mExternalProxyAddr;
     155                 :     PRNetAddr mDestinationAddr;
     156                 :     PRIntervalTime mTimeout;
     157                 : };
     158                 : 
     159               0 : nsSOCKSSocketInfo::nsSOCKSSocketInfo()
     160                 :     : mState(SOCKS_INITIAL)
     161                 :     , mDataIoPtr(nsnull)
     162                 :     , mDataLength(0)
     163                 :     , mReadOffset(0)
     164                 :     , mAmountToRead(0)
     165                 :     , mProxyPort(-1)
     166                 :     , mVersion(-1)
     167                 :     , mFlags(0)
     168               0 :     , mTimeout(PR_INTERVAL_NO_TIMEOUT)
     169                 : {
     170               0 :     mData = new PRUint8[BUFFER_SIZE];
     171               0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
     172               0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
     173               0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr);
     174               0 : }
     175                 : 
     176                 : void
     177               0 : nsSOCKSSocketInfo::Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort, const char *host, PRUint32 flags)
     178                 : {
     179               0 :     mVersion         = version;
     180               0 :     mProxyHost       = proxyHost;
     181               0 :     mProxyPort       = proxyPort;
     182               0 :     mDestinationHost = host;
     183               0 :     mFlags           = flags;
     184               0 : }
     185                 : 
     186               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsSOCKSSocketInfo, nsISOCKSSocketInfo)
     187                 : 
     188                 : NS_IMETHODIMP 
     189               0 : nsSOCKSSocketInfo::GetExternalProxyAddr(PRNetAddr * *aExternalProxyAddr)
     190                 : {
     191               0 :     memcpy(*aExternalProxyAddr, &mExternalProxyAddr, sizeof(PRNetAddr));
     192               0 :     return NS_OK;
     193                 : }
     194                 : 
     195                 : NS_IMETHODIMP 
     196               0 : nsSOCKSSocketInfo::SetExternalProxyAddr(PRNetAddr *aExternalProxyAddr)
     197                 : {
     198               0 :     memcpy(&mExternalProxyAddr, aExternalProxyAddr, sizeof(PRNetAddr));
     199               0 :     return NS_OK;
     200                 : }
     201                 : 
     202                 : NS_IMETHODIMP 
     203               0 : nsSOCKSSocketInfo::GetDestinationAddr(PRNetAddr * *aDestinationAddr)
     204                 : {
     205               0 :     memcpy(*aDestinationAddr, &mDestinationAddr, sizeof(PRNetAddr));
     206               0 :     return NS_OK;
     207                 : }
     208                 : 
     209                 : NS_IMETHODIMP 
     210               0 : nsSOCKSSocketInfo::SetDestinationAddr(PRNetAddr *aDestinationAddr)
     211                 : {
     212               0 :     memcpy(&mDestinationAddr, aDestinationAddr, sizeof(PRNetAddr));
     213               0 :     return NS_OK;
     214                 : }
     215                 : 
     216                 : NS_IMETHODIMP 
     217               0 : nsSOCKSSocketInfo::GetInternalProxyAddr(PRNetAddr * *aInternalProxyAddr)
     218                 : {
     219               0 :     memcpy(*aInternalProxyAddr, &mInternalProxyAddr, sizeof(PRNetAddr));
     220               0 :     return NS_OK;
     221                 : }
     222                 : 
     223                 : NS_IMETHODIMP 
     224               0 : nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
     225                 : {
     226               0 :     memcpy(&mInternalProxyAddr, aInternalProxyAddr, sizeof(PRNetAddr));
     227               0 :     return NS_OK;
     228                 : }
     229                 : 
     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               0 : nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err)
     239                 : {
     240               0 :     if (err == 0) {
     241               0 :         mState = SOCKS_CONNECTED;
     242                 :     } else {
     243               0 :         mState = SOCKS_FAILED;
     244               0 :         PR_SetError(PR_UNKNOWN_ERROR, err);
     245                 :     }
     246                 : 
     247                 :     // We don't need the buffer any longer, so free it.
     248               0 :     delete [] mData;
     249               0 :     mData = nsnull;
     250               0 :     mDataIoPtr = nsnull;
     251               0 :     mDataLength = 0;
     252               0 :     mReadOffset = 0;
     253               0 :     mAmountToRead = 0;
     254               0 : }
     255                 : 
     256                 : PRStatus
     257               0 : nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
     258                 : {
     259                 :     PRStatus status;
     260                 :     nsresult rv;
     261                 : 
     262               0 :     NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL,
     263                 :                       "Must be in initial state to make connection!");
     264                 : 
     265                 :     // If we haven't performed the DNS lookup, do that now.
     266               0 :     if (!mDnsRec) {
     267               0 :         nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
     268               0 :         if (!dns)
     269               0 :             return PR_FAILURE;
     270                 : 
     271               0 :         rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec));
     272               0 :         if (NS_FAILED(rv)) {
     273               0 :             LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
     274                 :                      mProxyHost.get()));
     275               0 :             return PR_FAILURE;
     276                 :         }
     277                 :     }
     278                 : 
     279               0 :     PRInt32 addresses = 0;
     280               0 :     do {
     281               0 :         if (addresses++)
     282               0 :             mDnsRec->ReportUnusable(mProxyPort);
     283                 :         
     284               0 :         rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
     285                 :         // No more addresses to try? If so, we'll need to bail
     286               0 :         if (NS_FAILED(rv)) {
     287               0 :             LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
     288                 :                      mProxyHost.get()));
     289               0 :             return PR_FAILURE;
     290                 :         }
     291                 : 
     292                 : #if defined(PR_LOGGING)
     293                 :         char buf[64];
     294               0 :         PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
     295               0 :         LOGDEBUG(("socks: trying proxy server, %s:%hu",
     296                 :                  buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
     297                 : #endif
     298                 :         status = fd->lower->methods->connect(fd->lower,
     299               0 :                         &mInternalProxyAddr, mTimeout);
     300               0 :         if (status != PR_SUCCESS) {
     301               0 :             PRErrorCode c = PR_GetError();
     302                 :             // If EINPROGRESS, return now and check back later after polling
     303               0 :             if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
     304               0 :                 mState = SOCKS_CONNECTING_TO_PROXY;
     305               0 :                 return status;
     306                 :             }
     307                 :         }
     308                 :     } while (status != PR_SUCCESS);
     309                 : 
     310                 :     // Connected now, start SOCKS
     311               0 :     if (mVersion == 4)
     312               0 :         return WriteV4ConnectRequest();
     313               0 :     return WriteV5AuthRequest();
     314                 : }
     315                 : 
     316                 : PRStatus
     317               0 : nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags)
     318                 : {
     319                 :     PRStatus status;
     320                 : 
     321               0 :     NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
     322                 :                       "Continuing connection in wrong state!");
     323                 : 
     324               0 :     LOGDEBUG(("socks: continuing connection to proxy"));
     325                 : 
     326               0 :     status = fd->lower->methods->connectcontinue(fd->lower, oflags);
     327               0 :     if (status != PR_SUCCESS) {
     328               0 :         PRErrorCode c = PR_GetError();
     329               0 :         if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
     330                 :             // A connection failure occured, try another address
     331               0 :             mState = SOCKS_INITIAL;
     332               0 :             return ConnectToProxy(fd);
     333                 :         }
     334                 : 
     335                 :         // We're still connecting
     336               0 :         return PR_FAILURE;
     337                 :     }
     338                 : 
     339                 :     // Connected now, start SOCKS
     340               0 :     if (mVersion == 4)
     341               0 :         return WriteV4ConnectRequest();
     342               0 :     return WriteV5AuthRequest();
     343                 : }
     344                 : 
     345                 : PRStatus
     346               0 : nsSOCKSSocketInfo::WriteV4ConnectRequest()
     347                 : {
     348               0 :     PRNetAddr *addr = &mDestinationAddr;
     349                 :     PRInt32 proxy_resolve;
     350                 : 
     351               0 :     NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
     352                 :                       "Invalid state!");
     353                 :     
     354               0 :     proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
     355                 : 
     356               0 :     mDataLength = 0;
     357               0 :     mState = SOCKS4_WRITE_CONNECT_REQUEST;
     358                 : 
     359               0 :     LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
     360                 :              proxy_resolve? "yes" : "no"));
     361                 : 
     362                 :     // Send a SOCKS 4 connect request.
     363               0 :     WriteUint8(0x04); // version -- 4
     364               0 :     WriteUint8(0x01); // command -- connect
     365               0 :     WriteNetPort(addr);
     366               0 :     if (proxy_resolve) {
     367                 :         // Add the full name, null-terminated, to the request
     368                 :         // according to SOCKS 4a. A fake IP address, with the first
     369                 :         // four bytes set to 0 and the last byte set to something other
     370                 :         // than 0, is used to notify the proxy that this is a SOCKS 4a
     371                 :         // request. This request type works for Tor and perhaps others.
     372               0 :         WriteUint32(PR_htonl(0x00000001)); // Fake IP
     373               0 :         WriteUint8(0x00); // Send an emtpy username
     374               0 :         if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
     375               0 :             LOGERROR(("socks4: destination host name is too long!"));
     376               0 :             HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     377               0 :             return PR_FAILURE;
     378                 :         }
     379               0 :         WriteString(mDestinationHost); // Hostname
     380               0 :         WriteUint8(0x00);
     381               0 :     } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
     382               0 :         WriteNetAddr(addr); // Add the IPv4 address
     383               0 :         WriteUint8(0x00); // Send an emtpy username
     384               0 :     } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
     385               0 :         LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
     386               0 :         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     387               0 :         return PR_FAILURE;
     388                 :     }
     389                 : 
     390               0 :     return PR_SUCCESS;
     391                 : }
     392                 : 
     393                 : PRStatus
     394               0 : nsSOCKSSocketInfo::ReadV4ConnectResponse()
     395                 : {
     396               0 :     NS_ABORT_IF_FALSE(mState == SOCKS4_READ_CONNECT_RESPONSE,
     397                 :                       "Handling SOCKS 4 connection reply in wrong state!");
     398               0 :     NS_ABORT_IF_FALSE(mDataLength == 8,
     399                 :                       "SOCKS 4 connection reply must be 8 bytes!");
     400                 : 
     401               0 :     LOGDEBUG(("socks4: checking connection reply"));
     402                 : 
     403               0 :     if (ReadUint8() != 0x00) {
     404               0 :         LOGERROR(("socks4: wrong connection reply"));
     405               0 :         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     406               0 :         return PR_FAILURE;
     407                 :     }
     408                 : 
     409                 :     // See if our connection request was granted
     410               0 :     if (ReadUint8() == 90) {
     411               0 :         LOGDEBUG(("socks4: connection successful!"));
     412               0 :         HandshakeFinished();
     413               0 :         return PR_SUCCESS;
     414                 :     }
     415                 : 
     416               0 :     LOGERROR(("socks4: unable to connect"));
     417               0 :     HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     418               0 :     return PR_FAILURE;
     419                 : }
     420                 : 
     421                 : PRStatus
     422               0 : nsSOCKSSocketInfo::WriteV5AuthRequest()
     423                 : {
     424               0 :     NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
     425                 : 
     426               0 :     mState = SOCKS5_WRITE_AUTH_REQUEST;
     427                 : 
     428                 :     // Send an initial SOCKS 5 greeting
     429               0 :     LOGDEBUG(("socks5: sending auth methods"));
     430               0 :     WriteUint8(0x05); // version -- 5
     431               0 :     WriteUint8(0x01); // # auth methods -- 1
     432               0 :     WriteUint8(0x00); // we don't support authentication
     433                 : 
     434               0 :     return PR_SUCCESS;
     435                 : }
     436                 : 
     437                 : PRStatus
     438               0 : nsSOCKSSocketInfo::ReadV5AuthResponse()
     439                 : {
     440               0 :     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_AUTH_RESPONSE,
     441                 :                       "Handling SOCKS 5 auth method reply in wrong state!");
     442               0 :     NS_ABORT_IF_FALSE(mDataLength == 2,
     443                 :                       "SOCKS 5 auth method reply must be 2 bytes!");
     444                 : 
     445               0 :     LOGDEBUG(("socks5: checking auth method reply"));
     446                 : 
     447                 :     // Check version number
     448               0 :     if (ReadUint8() != 0x05) {
     449               0 :         LOGERROR(("socks5: unexpected version in the reply"));
     450               0 :         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     451               0 :         return PR_FAILURE;
     452                 :     }
     453                 : 
     454                 :     // Make sure our authentication choice was accepted
     455               0 :     if (ReadUint8() != 0x00) {
     456               0 :         LOGERROR(("socks5: server did not accept our authentication method"));
     457               0 :         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     458               0 :         return PR_FAILURE;
     459                 :     }
     460                 : 
     461               0 :     return WriteV5ConnectRequest();
     462                 : }
     463                 : 
     464                 : PRStatus
     465               0 : nsSOCKSSocketInfo::WriteV5ConnectRequest()
     466                 : {
     467                 :     // Send SOCKS 5 connect request
     468               0 :     PRNetAddr *addr = &mDestinationAddr;
     469                 :     PRInt32 proxy_resolve;
     470               0 :     proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
     471                 : 
     472               0 :     LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
     473                 :              proxy_resolve? "yes" : "no"));
     474                 : 
     475               0 :     mDataLength = 0;
     476               0 :     mState = SOCKS5_WRITE_CONNECT_REQUEST;
     477                 : 
     478               0 :     WriteUint8(0x05); // version -- 5
     479               0 :     WriteUint8(0x01); // command -- connect
     480               0 :     WriteUint8(0x00); // reserved
     481                 :    
     482                 :     // Add the address to the SOCKS 5 request. SOCKS 5 supports several
     483                 :     // address types, so we pick the one that works best for us.
     484               0 :     if (proxy_resolve) {
     485                 :         // Add the host name. Only a single byte is used to store the length,
     486                 :         // so we must prevent long names from being used.
     487               0 :         if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
     488               0 :             LOGERROR(("socks5: destination host name is too long!"));
     489               0 :             HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     490               0 :             return PR_FAILURE;
     491                 :         }
     492               0 :         WriteUint8(0x03); // addr type -- domainname
     493               0 :         WriteUint8(mDestinationHost.Length()); // name length
     494               0 :         WriteString(mDestinationHost);
     495               0 :     } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
     496               0 :         WriteUint8(0x01); // addr type -- IPv4
     497               0 :         WriteNetAddr(addr);
     498               0 :     } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
     499               0 :         WriteUint8(0x04); // addr type -- IPv6
     500               0 :         WriteNetAddr(addr);
     501                 :     } else {
     502               0 :         LOGERROR(("socks5: destination address of unknown type!"));
     503               0 :         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     504               0 :         return PR_FAILURE;
     505                 :     }
     506                 : 
     507               0 :     WriteNetPort(addr); // port
     508                 : 
     509               0 :     return PR_SUCCESS;
     510                 : }
     511                 : 
     512                 : PRStatus
     513               0 : nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len)
     514                 : {
     515               0 :     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP ||
     516                 :                       mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
     517                 :                       "Invalid state!");
     518               0 :     NS_ABORT_IF_FALSE(mDataLength >= 5,
     519                 :                       "SOCKS 5 connection reply must be at least 5 bytes!");
     520                 :  
     521                 :     // Seek to the address location 
     522               0 :     mReadOffset = 3;
     523                 :    
     524               0 :     *type = ReadUint8();
     525                 : 
     526               0 :     switch (*type) {
     527                 :         case 0x01: // ipv4
     528               0 :             *len = 4 - 1;
     529               0 :             break;
     530                 :         case 0x04: // ipv6
     531               0 :             *len = 16 - 1;
     532               0 :             break;
     533                 :         case 0x03: // fqdn
     534               0 :             *len = ReadUint8();
     535               0 :             break;
     536                 :         default:   // wrong address type
     537               0 :             LOGERROR(("socks5: wrong address type in connection reply!"));
     538               0 :             return PR_FAILURE;
     539                 :     }
     540                 : 
     541               0 :     return PR_SUCCESS;
     542                 : }
     543                 : 
     544                 : PRStatus
     545               0 : nsSOCKSSocketInfo::ReadV5ConnectResponseTop()
     546                 : {
     547                 :     PRUint8 res;
     548                 :     PRUint32 len;
     549                 : 
     550               0 :     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP,
     551                 :                       "Invalid state!");
     552               0 :     NS_ABORT_IF_FALSE(mDataLength == 5,
     553                 :                       "SOCKS 5 connection reply must be exactly 5 bytes!");
     554                 : 
     555               0 :     LOGDEBUG(("socks5: checking connection reply"));
     556                 : 
     557                 :     // Check version number
     558               0 :     if (ReadUint8() != 0x05) {
     559               0 :         LOGERROR(("socks5: unexpected version in the reply"));
     560               0 :         HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     561               0 :         return PR_FAILURE;
     562                 :     }
     563                 : 
     564                 :     // Check response
     565               0 :     res = ReadUint8();
     566               0 :     if (res != 0x00) {
     567               0 :         PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
     568                 : 
     569               0 :         switch (res) {
     570                 :             case 0x01:
     571               0 :                 LOGERROR(("socks5: connect failed: "
     572                 :                           "01, General SOCKS server failure."));
     573               0 :                 break;
     574                 :             case 0x02:
     575               0 :                 LOGERROR(("socks5: connect failed: "
     576                 :                           "02, Connection not allowed by ruleset."));
     577               0 :                 break;
     578                 :             case 0x03:
     579               0 :                 LOGERROR(("socks5: connect failed: 03, Network unreachable."));
     580               0 :                 c = PR_NETWORK_UNREACHABLE_ERROR;
     581               0 :                 break;
     582                 :             case 0x04:
     583               0 :                 LOGERROR(("socks5: connect failed: 04, Host unreachable."));
     584               0 :                 break;
     585                 :             case 0x05:
     586               0 :                 LOGERROR(("socks5: connect failed: 05, Connection refused."));
     587               0 :                 break;
     588                 :             case 0x06:  
     589               0 :                 LOGERROR(("socks5: connect failed: 06, TTL expired."));
     590               0 :                 c = PR_CONNECT_TIMEOUT_ERROR;
     591               0 :                 break;
     592                 :             case 0x07:
     593               0 :                 LOGERROR(("socks5: connect failed: "
     594                 :                           "07, Command not supported."));
     595               0 :                 break;
     596                 :             case 0x08:
     597               0 :                 LOGERROR(("socks5: connect failed: "
     598                 :                           "08, Address type not supported."));
     599               0 :                 c = PR_BAD_ADDRESS_ERROR;
     600               0 :                 break;
     601                 :             default:
     602               0 :                 LOGERROR(("socks5: connect failed."));
     603               0 :                 break;
     604                 :         }
     605                 : 
     606               0 :         HandshakeFinished(c);
     607               0 :         return PR_FAILURE;
     608                 :     }
     609                 : 
     610               0 :     if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) {
     611               0 :         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     612               0 :         return PR_FAILURE;
     613                 :     }
     614                 : 
     615               0 :     mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM;
     616               0 :     WantRead(len + 2);
     617                 : 
     618               0 :     return PR_SUCCESS;
     619                 : }
     620                 : 
     621                 : PRStatus
     622               0 : nsSOCKSSocketInfo::ReadV5ConnectResponseBottom()
     623                 : {
     624                 :     PRUint8 type;
     625                 :     PRUint32 len;
     626                 : 
     627               0 :     NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
     628                 :                       "Invalid state!");
     629                 : 
     630               0 :     if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) {
     631               0 :         HandshakeFinished(PR_BAD_ADDRESS_ERROR);
     632               0 :         return PR_FAILURE;
     633                 :     }
     634                 : 
     635               0 :     NS_ABORT_IF_FALSE(mDataLength == 7+len,
     636                 :                       "SOCKS 5 unexpected length of connection reply!");
     637                 : 
     638               0 :     LOGDEBUG(("socks5: loading source addr and port"));
     639                 :     // Read what the proxy says is our source address
     640               0 :     switch (type) {
     641                 :         case 0x01: // ipv4
     642               0 :             ReadNetAddr(&mExternalProxyAddr, PR_AF_INET);
     643               0 :             break;
     644                 :         case 0x04: // ipv6
     645               0 :             ReadNetAddr(&mExternalProxyAddr, PR_AF_INET6);
     646               0 :             break;
     647                 :         case 0x03: // fqdn (skip)
     648               0 :             mReadOffset += len;
     649               0 :             mExternalProxyAddr.raw.family = PR_AF_INET;
     650               0 :             break;
     651                 :     }
     652                 : 
     653               0 :     ReadNetPort(&mExternalProxyAddr);
     654                 : 
     655               0 :     LOGDEBUG(("socks5: connected!"));
     656               0 :     HandshakeFinished();
     657                 : 
     658               0 :     return PR_SUCCESS;
     659                 : }
     660                 : 
     661                 : void
     662               0 : nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to)
     663                 : {
     664               0 :     mTimeout = to;
     665               0 : }
     666                 : 
     667                 : PRStatus
     668               0 : nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags)
     669                 : {
     670               0 :     LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
     671                 : 
     672               0 :     switch (mState) {
     673                 :         case SOCKS_INITIAL:
     674               0 :             return ConnectToProxy(fd);
     675                 :         case SOCKS_CONNECTING_TO_PROXY:
     676               0 :             return ContinueConnectingToProxy(fd, oflags);
     677                 :         case SOCKS4_WRITE_CONNECT_REQUEST:
     678               0 :             if (WriteToSocket(fd) != PR_SUCCESS)
     679               0 :                 return PR_FAILURE;
     680               0 :             WantRead(8);
     681               0 :             mState = SOCKS4_READ_CONNECT_RESPONSE;
     682               0 :             return PR_SUCCESS;
     683                 :         case SOCKS4_READ_CONNECT_RESPONSE:
     684               0 :             if (ReadFromSocket(fd) != PR_SUCCESS)
     685               0 :                 return PR_FAILURE;
     686               0 :             return ReadV4ConnectResponse();
     687                 : 
     688                 :         case SOCKS5_WRITE_AUTH_REQUEST:
     689               0 :             if (WriteToSocket(fd) != PR_SUCCESS)
     690               0 :                 return PR_FAILURE;
     691               0 :             WantRead(2);
     692               0 :             mState = SOCKS5_READ_AUTH_RESPONSE;
     693               0 :             return PR_SUCCESS;
     694                 :         case SOCKS5_READ_AUTH_RESPONSE:
     695               0 :             if (ReadFromSocket(fd) != PR_SUCCESS)
     696               0 :                 return PR_FAILURE;
     697               0 :             return ReadV5AuthResponse();
     698                 :         case SOCKS5_WRITE_CONNECT_REQUEST:
     699               0 :             if (WriteToSocket(fd) != PR_SUCCESS)
     700               0 :                 return PR_FAILURE;
     701                 : 
     702                 :             // The SOCKS 5 response to the connection request is variable
     703                 :             // length. First, we'll read enough to tell how long the response
     704                 :             // is, and will read the rest later.
     705               0 :             WantRead(5);
     706               0 :             mState = SOCKS5_READ_CONNECT_RESPONSE_TOP;
     707               0 :             return PR_SUCCESS;
     708                 :         case SOCKS5_READ_CONNECT_RESPONSE_TOP:
     709               0 :             if (ReadFromSocket(fd) != PR_SUCCESS)
     710               0 :                 return PR_FAILURE;
     711               0 :             return ReadV5ConnectResponseTop();
     712                 :         case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
     713               0 :             if (ReadFromSocket(fd) != PR_SUCCESS)
     714               0 :                 return PR_FAILURE;
     715               0 :             return ReadV5ConnectResponseBottom();
     716                 : 
     717                 :         case SOCKS_CONNECTED:
     718               0 :             LOGERROR(("socks: already connected"));
     719               0 :             HandshakeFinished(PR_IS_CONNECTED_ERROR);
     720               0 :             return PR_FAILURE;
     721                 :         case SOCKS_FAILED:
     722               0 :             LOGERROR(("socks: already failed"));
     723               0 :             return PR_FAILURE;
     724                 :     }
     725                 : 
     726               0 :     LOGERROR(("socks: executing handshake in invalid state, %d", mState));
     727               0 :     HandshakeFinished(PR_INVALID_STATE_ERROR);
     728                 : 
     729               0 :     return PR_FAILURE;
     730                 : }
     731                 : 
     732                 : PRInt16
     733               0 : nsSOCKSSocketInfo::GetPollFlags() const
     734                 : {
     735               0 :     switch (mState) {
     736                 :         case SOCKS_CONNECTING_TO_PROXY:
     737               0 :             return PR_POLL_EXCEPT | PR_POLL_WRITE;
     738                 :         case SOCKS4_WRITE_CONNECT_REQUEST:
     739                 :         case SOCKS5_WRITE_AUTH_REQUEST:
     740                 :         case SOCKS5_WRITE_CONNECT_REQUEST:
     741               0 :             return PR_POLL_WRITE;
     742                 :         case SOCKS4_READ_CONNECT_RESPONSE:
     743                 :         case SOCKS5_READ_AUTH_RESPONSE:
     744                 :         case SOCKS5_READ_CONNECT_RESPONSE_TOP:
     745                 :         case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
     746               0 :             return PR_POLL_READ;
     747                 :         default:
     748                 :             break;
     749                 :     }
     750                 : 
     751               0 :     return 0;
     752                 : }
     753                 : 
     754                 : inline void
     755               0 : nsSOCKSSocketInfo::WriteUint8(PRUint8 v)
     756                 : {
     757               0 :     NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
     758                 :                       "Can't write that much data!");
     759               0 :     mData[mDataLength] = v;
     760               0 :     mDataLength += sizeof(v);
     761               0 : }
     762                 : 
     763                 : inline void
     764               0 : nsSOCKSSocketInfo::WriteUint16(PRUint16 v)
     765                 : {
     766               0 :     NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
     767                 :                       "Can't write that much data!");
     768               0 :     memcpy(mData + mDataLength, &v, sizeof(v));
     769               0 :     mDataLength += sizeof(v);
     770               0 : }
     771                 : 
     772                 : inline void
     773               0 : nsSOCKSSocketInfo::WriteUint32(PRUint32 v)
     774                 : {
     775               0 :     NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
     776                 :                       "Can't write that much data!");
     777               0 :     memcpy(mData + mDataLength, &v, sizeof(v));
     778               0 :     mDataLength += sizeof(v);
     779               0 : }
     780                 : 
     781                 : void
     782               0 : nsSOCKSSocketInfo::WriteNetAddr(const PRNetAddr *addr)
     783                 : {
     784               0 :     const char *ip = NULL;
     785               0 :     PRUint32 len = 0;
     786                 : 
     787               0 :     if (PR_NetAddrFamily(addr) == PR_AF_INET) {
     788               0 :         ip = (const char*)&addr->inet.ip;
     789               0 :         len = sizeof(addr->inet.ip);
     790               0 :     } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
     791               0 :         ip = (const char*)addr->ipv6.ip.pr_s6_addr;
     792               0 :         len = sizeof(addr->ipv6.ip.pr_s6_addr);
     793                 :     }
     794                 : 
     795               0 :     NS_ABORT_IF_FALSE(ip != NULL, "Unknown address");
     796               0 :     NS_ABORT_IF_FALSE(mDataLength + len <= BUFFER_SIZE,
     797                 :                       "Can't write that much data!");
     798                 :  
     799               0 :     memcpy(mData + mDataLength, ip, len);
     800               0 :     mDataLength += len;
     801               0 : }
     802                 : 
     803                 : void
     804               0 : nsSOCKSSocketInfo::WriteNetPort(const PRNetAddr *addr)
     805                 : {
     806               0 :     WriteUint16(PR_NetAddrInetPort(addr));
     807               0 : }
     808                 : 
     809                 : void
     810               0 : nsSOCKSSocketInfo::WriteString(const nsACString &str)
     811                 : {
     812               0 :     NS_ABORT_IF_FALSE(mDataLength + str.Length() <= BUFFER_SIZE,
     813                 :                       "Can't write that much data!");
     814               0 :     memcpy(mData + mDataLength, str.Data(), str.Length());
     815               0 :     mDataLength += str.Length();
     816               0 : }
     817                 : 
     818                 : inline PRUint8
     819               0 : nsSOCKSSocketInfo::ReadUint8()
     820                 : {
     821                 :     PRUint8 rv;
     822               0 :     NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
     823                 :                       "Not enough space to pop a uint8!");
     824               0 :     rv = mData[mReadOffset];
     825               0 :     mReadOffset += sizeof(rv);
     826               0 :     return rv;
     827                 : }
     828                 : 
     829                 : inline PRUint16
     830               0 : nsSOCKSSocketInfo::ReadUint16()
     831                 : {
     832                 :     PRUint16 rv;
     833               0 :     NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
     834                 :                       "Not enough space to pop a uint16!");
     835               0 :     memcpy(&rv, mData + mReadOffset, sizeof(rv));
     836               0 :     mReadOffset += sizeof(rv);
     837               0 :     return rv;
     838                 : }
     839                 : 
     840                 : inline PRUint32
     841                 : nsSOCKSSocketInfo::ReadUint32()
     842                 : {
     843                 :     PRUint32 rv;
     844                 :     NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
     845                 :                       "Not enough space to pop a uint32!");
     846                 :     memcpy(&rv, mData + mReadOffset, sizeof(rv));
     847                 :     mReadOffset += sizeof(rv);
     848                 :     return rv;
     849                 : }
     850                 : 
     851                 : void
     852               0 : nsSOCKSSocketInfo::ReadNetAddr(PRNetAddr *addr, PRUint16 fam)
     853                 : {
     854                 :     PRUint32 amt;
     855               0 :     const PRUint8 *ip = mData + mReadOffset;
     856                 : 
     857               0 :     addr->raw.family = fam;
     858               0 :     if (fam == PR_AF_INET) {
     859               0 :         amt = sizeof(addr->inet.ip);
     860               0 :         NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
     861                 :                           "Not enough space to pop an ipv4 addr!");
     862               0 :         memcpy(&addr->inet.ip, ip, amt);
     863               0 :     } else if (fam == PR_AF_INET6) {
     864               0 :         amt = sizeof(addr->ipv6.ip.pr_s6_addr);
     865               0 :         NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
     866                 :                           "Not enough space to pop an ipv6 addr!");
     867               0 :         memcpy(addr->ipv6.ip.pr_s6_addr, ip, amt);
     868                 :     }
     869                 : 
     870               0 :     mReadOffset += amt;
     871               0 : }
     872                 : 
     873                 : void
     874               0 : nsSOCKSSocketInfo::ReadNetPort(PRNetAddr *addr)
     875                 : {
     876               0 :     addr->inet.port = ReadUint16();
     877               0 : }
     878                 : 
     879                 : void
     880               0 : nsSOCKSSocketInfo::WantRead(PRUint32 sz)
     881                 : {
     882               0 :     NS_ABORT_IF_FALSE(mDataIoPtr == NULL,
     883                 :                       "WantRead() called while I/O already in progress!");
     884               0 :     NS_ABORT_IF_FALSE(mDataLength + sz <= BUFFER_SIZE,
     885                 :                       "Can't read that much data!");
     886               0 :     mAmountToRead = sz;
     887               0 : }
     888                 : 
     889                 : PRStatus
     890               0 : nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc *fd)
     891                 : {
     892                 :     PRInt32 rc;
     893                 :     const PRUint8 *end;
     894                 : 
     895               0 :     if (!mAmountToRead) {
     896               0 :         LOGDEBUG(("socks: ReadFromSocket(), nothing to do"));
     897               0 :         return PR_SUCCESS;
     898                 :     }
     899                 : 
     900               0 :     if (!mDataIoPtr) {
     901               0 :         mDataIoPtr = mData + mDataLength;
     902               0 :         mDataLength += mAmountToRead;
     903                 :     }
     904                 : 
     905               0 :     end = mData + mDataLength;
     906                 : 
     907               0 :     while (mDataIoPtr < end) {
     908               0 :         rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr);
     909               0 :         if (rc <= 0) {
     910               0 :             if (rc == 0) {
     911               0 :                 LOGERROR(("socks: proxy server closed connection"));
     912               0 :                 HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
     913               0 :                 return PR_FAILURE;
     914               0 :             } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
     915               0 :                 LOGDEBUG(("socks: ReadFromSocket(), want read"));
     916                 :             }
     917               0 :             break;
     918                 :         }
     919                 : 
     920               0 :         mDataIoPtr += rc;
     921                 :     }
     922                 : 
     923               0 :     LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total",
     924                 :              unsigned(mDataIoPtr - mData)));
     925               0 :     if (mDataIoPtr == end) {
     926               0 :         mDataIoPtr = nsnull;
     927               0 :         mAmountToRead = 0;
     928               0 :         mReadOffset = 0;
     929               0 :         return PR_SUCCESS;
     930                 :     }
     931                 : 
     932               0 :     return PR_FAILURE;
     933                 : }
     934                 : 
     935                 : PRStatus
     936               0 : nsSOCKSSocketInfo::WriteToSocket(PRFileDesc *fd)
     937                 : {
     938                 :     PRInt32 rc;
     939                 :     const PRUint8 *end;
     940                 : 
     941               0 :     if (!mDataLength) {
     942               0 :         LOGDEBUG(("socks: WriteToSocket(), nothing to do"));
     943               0 :         return PR_SUCCESS;
     944                 :     }
     945                 : 
     946               0 :     if (!mDataIoPtr)
     947               0 :         mDataIoPtr = mData;
     948                 : 
     949               0 :     end = mData + mDataLength;
     950                 : 
     951               0 :     while (mDataIoPtr < end) {
     952               0 :         rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr);
     953               0 :         if (rc < 0) {
     954               0 :             if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
     955               0 :                 LOGDEBUG(("socks: WriteToSocket(), want write"));
     956                 :             }
     957               0 :             break;
     958                 :         }
     959                 :         
     960               0 :         mDataIoPtr += rc;
     961                 :     }
     962                 : 
     963               0 :     if (mDataIoPtr == end) {
     964               0 :         mDataIoPtr = nsnull;
     965               0 :         mDataLength = 0;
     966               0 :         mReadOffset = 0;
     967               0 :         return PR_SUCCESS;
     968                 :     }
     969                 :     
     970               0 :     return PR_FAILURE;
     971                 : }
     972                 : 
     973                 : static PRStatus
     974               0 : nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
     975                 : {
     976                 :     PRStatus status;
     977                 :     PRNetAddr dst;
     978                 : 
     979               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
     980               0 :     if (info == NULL) return PR_FAILURE;
     981                 : 
     982               0 :     if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
     983               0 :         PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
     984                 :         const PRUint8 *srcp;
     985                 : 
     986               0 :         LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
     987                 : 
     988                 :         // copied from _PR_ConvertToIpv4NetAddr()
     989               0 :         PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
     990               0 :         srcp = addr->ipv6.ip.pr_s6_addr;
     991               0 :         memcpy(&dst.inet.ip, srcp + 12, 4);
     992               0 :         dst.inet.family = PR_AF_INET;
     993               0 :         dst.inet.port = addr->ipv6.port;
     994                 :     } else {
     995               0 :         memcpy(&dst, addr, sizeof(dst));
     996                 :     }
     997                 : 
     998               0 :     info->SetDestinationAddr(&dst);
     999               0 :     info->SetConnectTimeout(to);
    1000                 : 
    1001               0 :     do {
    1002               0 :         status = info->DoHandshake(fd, -1);
    1003               0 :     } while (status == PR_SUCCESS && !info->IsConnected());
    1004                 : 
    1005               0 :     return status;
    1006                 : }
    1007                 : 
    1008                 : static PRStatus
    1009               0 : nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, PRInt16 oflags)
    1010                 : {
    1011                 :     PRStatus status;
    1012                 : 
    1013               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    1014               0 :     if (info == NULL) return PR_FAILURE;
    1015                 : 
    1016               0 :     do { 
    1017               0 :         status = info->DoHandshake(fd, oflags);
    1018               0 :     } while (status == PR_SUCCESS && !info->IsConnected());
    1019                 : 
    1020               0 :     return status;
    1021                 : }
    1022                 : 
    1023                 : static PRInt16
    1024               0 : nsSOCKSIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
    1025                 : {
    1026               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    1027               0 :     if (info == NULL) return PR_FAILURE;
    1028                 : 
    1029               0 :     if (!info->IsConnected()) {
    1030               0 :         *out_flags = 0;
    1031               0 :         return info->GetPollFlags();
    1032                 :     }
    1033                 : 
    1034               0 :     return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
    1035                 : }
    1036                 : 
    1037                 : static PRStatus
    1038               0 : nsSOCKSIOLayerClose(PRFileDesc *fd)
    1039                 : {
    1040               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    1041               0 :     PRDescIdentity id = PR_GetLayersIdentity(fd);
    1042                 : 
    1043               0 :     if (info && id == nsSOCKSIOLayerIdentity)
    1044                 :     {
    1045               0 :         NS_RELEASE(info);
    1046               0 :         fd->identity = PR_INVALID_IO_LAYER;
    1047                 :     }
    1048                 : 
    1049               0 :     return fd->lower->methods->close(fd->lower);
    1050                 : }
    1051                 : 
    1052                 : static PRFileDesc*
    1053               0 : nsSOCKSIOLayerAccept(PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
    1054                 : {
    1055                 :     // TODO: implement SOCKS support for accept
    1056               0 :     return fd->lower->methods->accept(fd->lower, addr, timeout);
    1057                 : }
    1058                 : 
    1059                 : static PRInt32
    1060               0 : nsSOCKSIOLayerAcceptRead(PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout)
    1061                 : {
    1062                 :     // TODO: implement SOCKS support for accept, then read from it
    1063               0 :     return sd->lower->methods->acceptread(sd->lower, nd, raddr, buf, amount, timeout);
    1064                 : }
    1065                 : 
    1066                 : static PRStatus
    1067               0 : nsSOCKSIOLayerBind(PRFileDesc *fd, const PRNetAddr *addr)
    1068                 : {
    1069                 :     // TODO: implement SOCKS support for bind (very similar to connect)
    1070               0 :     return fd->lower->methods->bind(fd->lower, addr);
    1071                 : }
    1072                 : 
    1073                 : static PRStatus
    1074               0 : nsSOCKSIOLayerGetName(PRFileDesc *fd, PRNetAddr *addr)
    1075                 : {
    1076               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    1077                 :     
    1078               0 :     if (info != NULL && addr != NULL) {
    1079               0 :         if (info->GetExternalProxyAddr(&addr) == NS_OK)
    1080               0 :             return PR_SUCCESS;
    1081                 :     }
    1082                 : 
    1083               0 :     return PR_FAILURE;
    1084                 : }
    1085                 : 
    1086                 : static PRStatus
    1087               0 : nsSOCKSIOLayerGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
    1088                 : {
    1089               0 :     nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    1090                 : 
    1091               0 :     if (info != NULL && addr != NULL) {
    1092               0 :         if (info->GetDestinationAddr(&addr) == NS_OK)
    1093               0 :             return PR_SUCCESS;
    1094                 :     }
    1095                 : 
    1096               0 :     return PR_FAILURE;
    1097                 : }
    1098                 : 
    1099                 : static PRStatus
    1100               0 : nsSOCKSIOLayerListen(PRFileDesc *fd, PRIntn backlog)
    1101                 : {
    1102                 :     // TODO: implement SOCKS support for listen
    1103               0 :     return fd->lower->methods->listen(fd->lower, backlog);
    1104                 : }
    1105                 : 
    1106                 : // add SOCKS IO layer to an existing socket
    1107                 : nsresult
    1108               0 : nsSOCKSIOLayerAddToSocket(PRInt32 family,
    1109                 :                           const char *host, 
    1110                 :                           PRInt32 port,
    1111                 :                           const char *proxyHost,
    1112                 :                           PRInt32 proxyPort,
    1113                 :                           PRInt32 socksVersion,
    1114                 :                           PRUint32 flags,
    1115                 :                           PRFileDesc *fd, 
    1116                 :                           nsISupports** info)
    1117                 : {
    1118               0 :     NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), NS_ERROR_NOT_INITIALIZED);
    1119                 : 
    1120                 : 
    1121               0 :     if (firstTime)
    1122                 :     {
    1123               0 :         nsSOCKSIOLayerIdentity          = PR_GetUniqueIdentity("SOCKS layer");
    1124               0 :         nsSOCKSIOLayerMethods           = *PR_GetDefaultIOMethods();
    1125                 : 
    1126               0 :         nsSOCKSIOLayerMethods.connect   = nsSOCKSIOLayerConnect;
    1127               0 :         nsSOCKSIOLayerMethods.connectcontinue   = nsSOCKSIOLayerConnectContinue;
    1128               0 :         nsSOCKSIOLayerMethods.poll      = nsSOCKSIOLayerPoll;
    1129               0 :         nsSOCKSIOLayerMethods.bind      = nsSOCKSIOLayerBind;
    1130               0 :         nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
    1131               0 :         nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
    1132               0 :         nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName;
    1133               0 :         nsSOCKSIOLayerMethods.accept    = nsSOCKSIOLayerAccept;
    1134               0 :         nsSOCKSIOLayerMethods.listen    = nsSOCKSIOLayerListen;
    1135               0 :         nsSOCKSIOLayerMethods.close     = nsSOCKSIOLayerClose;
    1136                 : 
    1137               0 :         firstTime                       = false;
    1138                 : 
    1139                 : #if defined(PR_LOGGING)
    1140               0 :         gSOCKSLog = PR_NewLogModule("SOCKS");
    1141                 : #endif
    1142                 : 
    1143                 :     }
    1144                 : 
    1145               0 :     LOGDEBUG(("Entering nsSOCKSIOLayerAddToSocket()."));
    1146                 : 
    1147                 :     PRFileDesc *        layer;
    1148                 :     PRStatus    rv;
    1149                 : 
    1150               0 :     layer = PR_CreateIOLayerStub(nsSOCKSIOLayerIdentity, &nsSOCKSIOLayerMethods);
    1151               0 :     if (! layer)
    1152                 :     {
    1153               0 :         LOGERROR(("PR_CreateIOLayerStub() failed."));
    1154               0 :         return NS_ERROR_FAILURE;
    1155                 :     }
    1156                 : 
    1157               0 :     nsSOCKSSocketInfo * infoObject = new nsSOCKSSocketInfo();
    1158               0 :     if (!infoObject)
    1159                 :     {
    1160                 :         // clean up IOLayerStub
    1161               0 :         LOGERROR(("Failed to create nsSOCKSSocketInfo()."));
    1162               0 :         PR_DELETE(layer);
    1163               0 :         return NS_ERROR_FAILURE;
    1164                 :     }
    1165                 : 
    1166               0 :     NS_ADDREF(infoObject);
    1167               0 :     infoObject->Init(socksVersion, proxyHost, proxyPort, host, flags);
    1168               0 :     layer->secret = (PRFilePrivate*) infoObject;
    1169               0 :     rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer);
    1170                 : 
    1171               0 :     if (NS_FAILED(rv))
    1172                 :     {
    1173               0 :         LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv));
    1174               0 :         NS_RELEASE(infoObject);
    1175               0 :         PR_DELETE(layer);
    1176               0 :         return NS_ERROR_FAILURE;
    1177                 :     }
    1178                 : 
    1179               0 :     *info = infoObject;
    1180               0 :     NS_ADDREF(*info);
    1181               0 :     return NS_OK;
    1182                 : }

Generated by: LCOV version 1.7