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 : }
|