LCOV - app.info - netwerk/socket/nsSOCKSIOLayer.cpp

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-04-21 | 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