Guest User

Untitled

a guest
Jul 16th, 2018
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.03 KB | None | 0 0
  1. diff -r 59f917fd649f netwerk/socket/base/nsSOCKSIOLayer.cpp
  2. --- a/netwerk/socket/base/nsSOCKSIOLayer.cpp Fri Oct 23 09:50:43 2009 -0700
  3. +++ b/netwerk/socket/base/nsSOCKSIOLayer.cpp Sun Oct 25 20:37:15 2009 -0700
  4. @@ -63,48 +63,101 @@ static PRLogModuleInfo *gSOCKSLog;
  5.  
  6. #else
  7. #define LOGDEBUG(args)
  8. #define LOGERROR(args)
  9. #endif
  10.  
  11. class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
  12. {
  13. + enum State {
  14. + SOCKS_INITIAL,
  15. + SOCKS_CONNECTING_TO_PROXY,
  16. + SOCKS4_WANT_CONNECT_OK,
  17. + SOCKS5_WANT_AUTH_NONE,
  18. + SOCKS5_WANT_CONNECT_OK,
  19. + SOCKS_CONNECTED
  20. + };
  21. +
  22. public:
  23. nsSOCKSSocketInfo();
  24. virtual ~nsSOCKSSocketInfo() {}
  25.  
  26. NS_DECL_ISUPPORTS
  27. NS_DECL_NSISOCKSSOCKETINFO
  28.  
  29. void Init(PRInt32 version,
  30. const char *proxyHost,
  31. PRInt32 proxyPort,
  32. const char *destinationHost,
  33. PRUint32 flags);
  34. +
  35. + const char *StateToStr() const;
  36. + PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1,
  37. + PRIntervalTime to = PR_INTERVAL_NO_TIMEOUT);
  38. + PRInt16 HowToPoll() const { return mPollFlags; }
  39. + PRInt32 IsConnected() const { return mState == SOCKS_CONNECTED; }
  40.  
  41. const nsCString &DestinationHost() { return mDestinationHost; }
  42. const nsCString &ProxyHost() { return mProxyHost; }
  43. PRInt32 ProxyPort() { return mProxyPort; }
  44. PRInt32 Version() { return mVersion; }
  45. PRUint32 Flags() { return mFlags; }
  46.  
  47. private:
  48. + PRStatus SendGreeting(PRFileDesc *fd);
  49. + PRStatus ConnectToProxy(PRFileDesc *fd, PRIntervalTime to);
  50. + PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags);
  51. + PRStatus HandleSocks4Connect(PRFileDesc *fd);
  52. + PRStatus HandleSocks5Auth(PRFileDesc *fd);
  53. + PRStatus HandleSocks5Connect(PRFileDesc *fd);
  54. +
  55. + void PushUint8(PRUint8 d);
  56. + void PushUint16(PRUint16 d);
  57. + void PushUint32(PRUint32 d);
  58. + void PushNetAddr(const PRNetAddr *addr);
  59. + void PushNetPort(const PRNetAddr *addr);
  60. +
  61. + PRUint8 PopUint8();
  62. + PRUint16 PopUint16();
  63. + PRUint32 PopUint32();
  64. + void PopNetAddr(PRNetAddr *addr, PRUint16 fam);
  65. + void PopNetPort(PRNetAddr *addr);
  66. +
  67. + void WantRead(PRInt32 sz);
  68. + PRStatus Fill(PRFileDesc *fd);
  69. + PRStatus Flush(PRFileDesc *fd);
  70. +
  71. +private:
  72. + State mState;
  73. + nsCString mInBuf;
  74. + nsCString mOutBuf;
  75. + PRInt32 mAmountToRead;
  76. + PRUint32 mPopOffset;
  77. + char * mReadPtr;
  78. + PRInt16 mPollFlags;
  79. + nsCOMPtr<nsIDNSRecord> mDnsRec;
  80. +
  81. nsCString mDestinationHost;
  82. nsCString mProxyHost;
  83. PRInt32 mProxyPort;
  84. PRInt32 mVersion; // SOCKS version 4 or 5
  85. PRUint32 mFlags;
  86. PRNetAddr mInternalProxyAddr;
  87. PRNetAddr mExternalProxyAddr;
  88. PRNetAddr mDestinationAddr;
  89. };
  90.  
  91. nsSOCKSSocketInfo::nsSOCKSSocketInfo()
  92. - : mProxyPort(-1)
  93. + : mState(SOCKS_INITIAL)
  94. + , mAmountToRead(0)
  95. + , mPopOffset(0)
  96. + , mReadPtr(nsnull)
  97. + , mPollFlags(0)
  98. + , mProxyPort(-1)
  99. , mVersion(-1)
  100. , mFlags(0)
  101. {
  102. PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
  103. PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
  104. PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr);
  105. }
  106.  
  107. @@ -157,647 +210,667 @@ nsSOCKSSocketInfo::GetInternalProxyAddr(
  108.  
  109. NS_IMETHODIMP
  110. nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
  111. {
  112. memcpy(&mInternalProxyAddr, aInternalProxyAddr, sizeof(PRNetAddr));
  113. return NS_OK;
  114. }
  115.  
  116. -static PRInt32
  117. -pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags,
  118. - PRIntervalTime *timeout)
  119. +PRStatus
  120. +nsSOCKSSocketInfo::SendGreeting(PRFileDesc *fd)
  121. {
  122. - PRInt32 bytesRead = 0;
  123. - PRInt32 offset = 0;
  124. + NS_ABORT_IF_FALSE(mVersion == 4 || mVersion == 5,
  125. + "SOCKS version must be 4 or 5!");
  126. + NS_ABORT_IF_FALSE(mState <= SOCKS_CONNECTING_TO_PROXY,
  127. + "Can only send SOCKS greeting in initial state");
  128. +
  129. + if (mVersion == 4) {
  130. + PRNetAddr *addr = &mDestinationAddr;
  131. + PRInt32 proxy_resolve;
  132. + proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
  133.  
  134. - while (offset < amount) {
  135. - PRIntervalTime start_time = PR_IntervalNow();
  136. - bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, *timeout);
  137. - PRIntervalTime elapsed = PR_IntervalNow() - start_time;
  138. + LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
  139. + proxy_resolve? "yes" : "no"));
  140.  
  141. - if (elapsed > *timeout) {
  142. - *timeout = 0;
  143. - } else {
  144. - *timeout -= elapsed;
  145. + // Send a SOCKS 4 connect request.
  146. + PushUint8(0x04); // version -- 4
  147. + PushUint8(0x01); // command -- connect
  148. + PushNetPort(addr);
  149. + if (proxy_resolve) {
  150. + // Add the full name, null-terminated, to the request
  151. + // according to SOCKS 4a
  152. + PushUint32(PR_htonl(0x00000001));
  153. + PushUint8(0x00); // Send an emtpy username
  154. + mOutBuf.Append(mDestinationHost);
  155. + PushUint8(0x00);
  156. + } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
  157. + // Add the IPv4 address
  158. + PushNetAddr(addr);
  159. + PushUint8(0x00); // Send an emtpy username
  160. + } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
  161. + LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
  162. + PR_SetError(PR_BAD_ADDRESS_ERROR, 0);
  163. + return PR_FAILURE;
  164. }
  165. +
  166. + WantRead(8);
  167. + mState = SOCKS4_WANT_CONNECT_OK;
  168. + } else {
  169. + // Send an initial SOCKS 5 greeting
  170. + LOGDEBUG(("socks5: sending auth methods"));
  171. + PushUint8(0x05); // version -- 5
  172. + PushUint8(0x01); // # auth methods -- 1
  173. + PushUint8(0x00); // we don't support authentication
  174.  
  175. - if (bytesRead > 0) {
  176. - offset += bytesRead;
  177. - } else if (bytesRead == 0 || offset != 0) {
  178. - return offset;
  179. - } else {
  180. - return bytesRead;
  181. - }
  182. + WantRead(2);
  183. + mState = SOCKS5_WANT_AUTH_NONE;
  184. + }
  185.  
  186. - if (*timeout == 0) {
  187. - LOGERROR(("PR_Recv() timed out. amount = %d. offset = %d.",
  188. - amount, offset));
  189. - return offset;
  190. - }
  191. - }
  192. - return offset;
  193. + return Flush(fd);
  194. }
  195.  
  196. -static PRInt32
  197. -pr_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
  198. - PRIntervalTime *timeout)
  199. +PRStatus
  200. +nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd, PRIntervalTime to)
  201. {
  202. - PRIntervalTime start_time = PR_IntervalNow();
  203. - PRInt32 retval = PR_Send(fd, buf, amount, flags, *timeout);
  204. - PRIntervalTime elapsed = PR_IntervalNow() - start_time;
  205. + PRStatus status;
  206. + nsresult rv;
  207.  
  208. - if (elapsed > *timeout) {
  209. - *timeout = 0;
  210. - LOGERROR(("PR_Send() timed out. amount = %d. retval = %d.",
  211. - amount, retval));
  212. - return retval;
  213. - } else {
  214. - *timeout -= elapsed;
  215. - }
  216. + NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL,
  217. + "Must be in initial state to make connection!");
  218.  
  219. - if (retval <= 0) {
  220. - LOGERROR(("PR_Send() failed. amount = %d. retval = %d.",
  221. - amount, retval));
  222. - }
  223. + // If we haven't performed the DNS lookup, do that now.
  224. + if (!mDnsRec) {
  225. + nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
  226. + if (!dns)
  227. + return PR_FAILURE;
  228.  
  229. - return retval;
  230. -}
  231. -
  232. -// Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks
  233. -// server port has been established.
  234. -static nsresult
  235. -ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout)
  236. -{
  237. - int request_len = 0;
  238. - int response_len = 0;
  239. - int desired_len = 0;
  240. - unsigned char request[22];
  241. - unsigned char response[262];
  242. -
  243. - NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
  244. - NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
  245. - NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED);
  246. -
  247. - request[0] = 0x05; // SOCKS version 5
  248. - request[1] = 0x01; // number of auth procotols we recognize
  249. - // auth protocols
  250. - request[2] = 0x00; // no authentication required
  251. - // compliant implementations MUST implement GSSAPI
  252. - // and SHOULD implement username/password and MAY
  253. - // implement CHAP
  254. - // TODO: we don't implement these
  255. - //request[3] = 0x01; // GSSAPI
  256. - //request[4] = 0x02; // username/password
  257. - //request[5] = 0x03; // CHAP
  258. -
  259. - request_len = 2 + request[1];
  260. - int write_len = pr_Send(fd, request, request_len, 0, &timeout);
  261. - if (write_len != request_len) {
  262. - return NS_ERROR_FAILURE;
  263. - }
  264. -
  265. - // get the server's response.
  266. - desired_len = 2;
  267. - response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
  268. -
  269. - if (response_len < desired_len) {
  270. - LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
  271. - return NS_ERROR_FAILURE;
  272. - }
  273. -
  274. - if (response[0] != 0x05) {
  275. - // it's a either not SOCKS or not our version
  276. - LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
  277. - return NS_ERROR_FAILURE;
  278. - }
  279. - switch (response[1]) {
  280. - case 0x00:
  281. - // no auth
  282. - break;
  283. - case 0x01:
  284. - // GSSAPI
  285. - // TODO: implement
  286. - LOGERROR(("Server want to use GSSAPI to authenticate, but we don't support it."));
  287. - return NS_ERROR_FAILURE;
  288. - case 0x02:
  289. - // username/password
  290. - // TODO: implement
  291. - LOGERROR(("Server want to use username/password to authenticate, but we don't support it."));
  292. - return NS_ERROR_FAILURE;
  293. - case 0x03:
  294. - // CHAP
  295. - // TODO: implement?
  296. - LOGERROR(("Server want to use CHAP to authenticate, but we don't support it."));
  297. - return NS_ERROR_FAILURE;
  298. - default:
  299. - // unrecognized auth method
  300. - LOGERROR(("Uncrecognized authentication method received: %x", response[1]));
  301. - return NS_ERROR_FAILURE;
  302. - }
  303. -
  304. - // we are now authenticated, so lets tell
  305. - // the server where to connect to
  306. -
  307. - request_len = 0;
  308. -
  309. - request[0] = 0x05; // SOCKS version 5
  310. - request[1] = 0x01; // CONNECT command
  311. - request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)
  312. -
  313. - // get destination port
  314. - PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
  315. - nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  316. -
  317. - if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
  318. -
  319. - LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
  320. -
  321. - // if the PROXY_RESOLVES_HOST flag is set, we assume
  322. - // that the transport wants us to pass the SOCKS server the
  323. - // hostname and port and let it do the name resolution.
  324. -
  325. - // the real destination hostname and port was stored
  326. - // in our info object earlier when this layer was created.
  327. -
  328. - const nsCString& destHost = info->DestinationHost();
  329. -
  330. - LOGDEBUG(("host:port -> %s:%li", destHost.get(), destPort));
  331. -
  332. - request[3] = 0x03; // encoding of destination address (3 == hostname)
  333. -
  334. - int host_len = destHost.Length();
  335. - if (host_len > 255) {
  336. - // SOCKS5 transmits the length of the hostname in a single char.
  337. - // This gives us an absolute limit of 255 chars in a hostname, and
  338. - // there's nothing we can do to extend it. I don't think many
  339. - // hostnames will ever be bigger than this, so hopefully it's an
  340. - // uneventful abort condition.
  341. - LOGERROR (("Hostname too big for SOCKS5."));
  342. - return NS_ERROR_INVALID_ARG;
  343. - }
  344. - request[4] = (char) host_len;
  345. - request_len = 5;
  346. -
  347. - // Send the initial header first...
  348. - write_len = pr_Send(fd, request, request_len, 0, &timeout);
  349. - if (write_len != request_len) {
  350. - // bad write
  351. - return NS_ERROR_FAILURE;
  352. - }
  353. -
  354. - // Now send the hostname...
  355. - write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
  356. - if (write_len != host_len) {
  357. - // bad write
  358. - return NS_ERROR_FAILURE;
  359. - }
  360. -
  361. - // There's no data left because we just sent it.
  362. - request_len = 0;
  363. -
  364. - } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
  365. -
  366. - request[3] = 0x01; // encoding of destination address (1 == IPv4)
  367. - request_len = 8; // 4 for address, 4 SOCKS headers
  368. -
  369. - char * ip = (char*)(&addr->inet.ip);
  370. - request[4] = *ip++;
  371. - request[5] = *ip++;
  372. - request[6] = *ip++;
  373. - request[7] = *ip++;
  374. -
  375. - } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
  376. -
  377. - request[3] = 0x04; // encoding of destination address (4 == IPv6)
  378. - request_len = 20; // 16 for address, 4 SOCKS headers
  379. -
  380. - char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);
  381. - request[4] = *ip++; request[5] = *ip++;
  382. - request[6] = *ip++; request[7] = *ip++;
  383. - request[8] = *ip++; request[9] = *ip++;
  384. - request[10] = *ip++; request[11] = *ip++;
  385. - request[12] = *ip++; request[13] = *ip++;
  386. - request[14] = *ip++; request[15] = *ip++;
  387. - request[16] = *ip++; request[17] = *ip++;
  388. - request[18] = *ip++; request[19] = *ip++;
  389. -
  390. - // we're going to test to see if this address can
  391. - // be mapped back into IPv4 without loss. if so,
  392. - // we'll use IPv4 instead, as reliable SOCKS server
  393. - // support for IPv6 is probably questionable.
  394. -
  395. - if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
  396. - request[3] = 0x01; // ipv4 encoding
  397. - request[4] = request[16];
  398. - request[5] = request[17];
  399. - request[6] = request[18];
  400. - request[7] = request[19];
  401. - request_len -= 12;
  402. - }
  403. - } else {
  404. - // Unknown address type
  405. - LOGERROR(("Don't know what kind of IP address this is."));
  406. - return NS_ERROR_FAILURE;
  407. - }
  408. -
  409. - // add the destination port to the request
  410. - request[request_len] = (unsigned char)(destPort >> 8);
  411. - request[request_len+1] = (unsigned char)destPort;
  412. - request_len += 2;
  413. -
  414. - write_len = pr_Send(fd, request, request_len, 0, &timeout);
  415. - if (write_len != request_len) {
  416. - // bad write
  417. - return NS_ERROR_FAILURE;
  418. - }
  419. -
  420. - desired_len = 5;
  421. - response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
  422. - if (response_len < desired_len) { // bad read
  423. - LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
  424. - return NS_ERROR_FAILURE;
  425. - }
  426. -
  427. - if (response[0] != 0x05) {
  428. - // bad response
  429. - LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
  430. - return NS_ERROR_FAILURE;
  431. - }
  432. -
  433. - switch(response[1]) {
  434. - case 0x00: break; // success
  435. - case 0x01: LOGERROR(("SOCKS 5 server rejected connect request: 01, General SOCKS server failure."));
  436. - return NS_ERROR_FAILURE;
  437. - case 0x02: LOGERROR(("SOCKS 5 server rejected connect request: 02, Connection not allowed by ruleset."));
  438. - return NS_ERROR_FAILURE;
  439. - case 0x03: LOGERROR(("SOCKS 5 server rejected connect request: 03, Network unreachable."));
  440. - return NS_ERROR_FAILURE;
  441. - case 0x04: LOGERROR(("SOCKS 5 server rejected connect request: 04, Host unreachable."));
  442. - return NS_ERROR_FAILURE;
  443. - case 0x05: LOGERROR(("SOCKS 5 server rejected connect request: 05, Connection refused."));
  444. - return NS_ERROR_FAILURE;
  445. - case 0x06: LOGERROR(("SOCKS 5 server rejected connect request: 06, TTL expired."));
  446. - return NS_ERROR_FAILURE;
  447. - case 0x07: LOGERROR(("SOCKS 5 server rejected connect request: 07, Command not supported."));
  448. - return NS_ERROR_FAILURE;
  449. - case 0x08: LOGERROR(("SOCKS 5 server rejected connect request: 08, Address type not supported."));
  450. - return NS_ERROR_FAILURE;
  451. - default: LOGERROR(("SOCKS 5 server rejected connect request: %x.", response[1]));
  452. - return NS_ERROR_FAILURE;
  453. -
  454. -
  455. - }
  456. -
  457. - switch (response[3]) {
  458. - case 0x01: // IPv4
  459. - desired_len = 4 + 2 - 1;
  460. - break;
  461. - case 0x03: // FQDN
  462. - desired_len = response[4] + 2;
  463. - break;
  464. - case 0x04: // IPv6
  465. - desired_len = 16 + 2 - 1;
  466. - break;
  467. - default: // unknown format
  468. - return NS_ERROR_FAILURE;
  469. - break;
  470. - }
  471. - response_len = pr_RecvAll(fd, response + 5, desired_len, 0, &timeout);
  472. - if (response_len < desired_len) { // bad read
  473. - LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
  474. - return NS_ERROR_FAILURE;
  475. - }
  476. - response_len += 5;
  477. -
  478. - // get external bound address (this is what
  479. - // the outside world sees as "us")
  480. - char *ip = nsnull;
  481. - PRUint16 extPort = 0;
  482. -
  483. - switch (response[3]) {
  484. - case 0x01: // IPv4
  485. -
  486. - extPort = (response[8] << 8) | response[9];
  487. -
  488. - PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, extAddr);
  489. -
  490. - ip = (char*)(&extAddr->inet.ip);
  491. - *ip++ = response[4];
  492. - *ip++ = response[5];
  493. - *ip++ = response[6];
  494. - *ip++ = response[7];
  495. -
  496. - break;
  497. - case 0x04: // IPv6
  498. -
  499. - extPort = (response[20] << 8) | response[21];
  500. -
  501. - PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);
  502. -
  503. - ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);
  504. - *ip++ = response[4]; *ip++ = response[5];
  505. - *ip++ = response[6]; *ip++ = response[7];
  506. - *ip++ = response[8]; *ip++ = response[9];
  507. - *ip++ = response[10]; *ip++ = response[11];
  508. - *ip++ = response[12]; *ip++ = response[13];
  509. - *ip++ = response[14]; *ip++ = response[15];
  510. - *ip++ = response[16]; *ip++ = response[17];
  511. - *ip++ = response[18]; *ip++ = response[19];
  512. -
  513. - break;
  514. - case 0x03: // FQDN
  515. - // if we get here, we don't know our external address.
  516. - // however, as that's possibly not critical to the user,
  517. - // we let it slide.
  518. - extPort = (response[response_len - 2] << 8) |
  519. - response[response_len - 1];
  520. - PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr);
  521. - break;
  522. - }
  523. - return NS_OK;
  524. -}
  525. -
  526. -// Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks
  527. -// server port has been established.
  528. -static nsresult
  529. -ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  530. -{
  531. - int request_len = 0;
  532. - int write_len;
  533. - int response_len = 0;
  534. - int desired_len = 0;
  535. - char *ip = nsnull;
  536. - unsigned char request[12];
  537. - unsigned char response[10];
  538. -
  539. - NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
  540. - NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
  541. -
  542. - request[0] = 0x04; // SOCKS version 4
  543. - request[1] = 0x01; // CD command code -- 1 for connect
  544. -
  545. - // destination port
  546. - PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
  547. -
  548. - // store the port
  549. - request[2] = (unsigned char)(destPort >> 8);
  550. - request[3] = (unsigned char)destPort;
  551. -
  552. - // username
  553. - request[8] = 'M';
  554. - request[9] = 'O';
  555. - request[10] = 'Z';
  556. -
  557. - request[11] = 0x00;
  558. -
  559. - request_len = 12;
  560. -
  561. - nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  562. -
  563. - if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
  564. -
  565. - LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
  566. -
  567. - // if the PROXY_RESOLVES_HOST flag is set, we assume that the
  568. - // transport wants us to pass the SOCKS server the hostname
  569. - // and port and let it do the name resolution.
  570. -
  571. - // an extension to SOCKS 4, called 4a, specifies a way
  572. - // to do this, so we'll try that and hope the
  573. - // server supports it.
  574. -
  575. - // the real destination hostname and port was stored
  576. - // in our info object earlier when this layer was created.
  577. -
  578. - const nsCString& destHost = info->DestinationHost();
  579. -
  580. - LOGDEBUG(("host:port -> %s:%li\n", destHost.get(), destPort));
  581. -
  582. - // the IP portion of the query is set to this special address.
  583. - request[4] = 0;
  584. - request[5] = 0;
  585. - request[6] = 0;
  586. - request[7] = 1;
  587. -
  588. - write_len = pr_Send(fd, request, request_len, 0, &timeout);
  589. - if (write_len != request_len) {
  590. - return NS_ERROR_FAILURE;
  591. - }
  592. -
  593. - // Remember the NULL.
  594. - int host_len = destHost.Length() + 1;
  595. -
  596. - write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
  597. - if (write_len != host_len) {
  598. - return NS_ERROR_FAILURE;
  599. - }
  600. -
  601. - // No data to send, just sent it.
  602. - request_len = 0;
  603. -
  604. - } else if (PR_NetAddrFamily(addr) == PR_AF_INET) { // IPv4
  605. -
  606. - // store the ip
  607. - ip = (char*)(&addr->inet.ip);
  608. - request[4] = *ip++;
  609. - request[5] = *ip++;
  610. - request[6] = *ip++;
  611. - request[7] = *ip++;
  612. -
  613. - } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) { // IPv6
  614. -
  615. - // IPv4 address encoded in an IPv6 address
  616. - if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
  617. - // store the ip
  618. - ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
  619. - request[4] = *ip++;
  620. - request[5] = *ip++;
  621. - request[6] = *ip++;
  622. - request[7] = *ip++;
  623. - } else {
  624. - LOGERROR(("IPv6 is not supported in SOCKS 4."));
  625. - return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
  626. - }
  627. -
  628. - } else {
  629. - LOGERROR(("Don't know what kind of IP address this is."));
  630. - return NS_ERROR_FAILURE; // don't recognize this type
  631. - }
  632. -
  633. - if (request_len > 0) {
  634. - write_len = pr_Send(fd, request, request_len, 0, &timeout);
  635. - if (write_len != request_len) {
  636. - return NS_ERROR_FAILURE;
  637. + rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec));
  638. + if (NS_FAILED(rv)) {
  639. + LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
  640. + mProxyHost.get()));
  641. + return PR_FAILURE;
  642. }
  643. }
  644.  
  645. - // get the server's response
  646. - desired_len = 8; // size of the response
  647. - response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
  648. - if (response_len < desired_len) {
  649. - LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
  650. - return NS_ERROR_FAILURE;
  651. + do {
  652. + rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
  653. + // No more addresses?
  654. + if (NS_FAILED(rv)) {
  655. + LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
  656. + mProxyHost.get()));
  657. + return PR_FAILURE;
  658. + }
  659. +
  660. +#if defined(PR_LOGGING)
  661. + char buf[64];
  662. + PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
  663. + LOGDEBUG(("socks: trying proxy server, %s:%hu",
  664. + buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
  665. +#endif
  666. + status = fd->lower->methods->connect(fd->lower,
  667. + &mInternalProxyAddr, to);
  668. + if (status != PR_SUCCESS) {
  669. + PRErrorCode c = PR_GetError();
  670. + // If EINPROGRESS, return now and check back later after polling
  671. + if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
  672. + mState = SOCKS_CONNECTING_TO_PROXY;
  673. + mPollFlags = PR_POLL_EXCEPT | PR_POLL_WRITE;
  674. + return status;
  675. + }
  676. + }
  677. + } while (status != PR_SUCCESS);
  678. +
  679. + // Connected now, send greeting
  680. + return SendGreeting(fd);
  681. +}
  682. +
  683. +PRStatus
  684. +nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags)
  685. +{
  686. + PRStatus status;
  687. +
  688. + NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
  689. + "Continuing connection in wrong state!");
  690. +
  691. + LOGDEBUG(("socks: continuing connection to proxy"));
  692. +
  693. + status = fd->lower->methods->connectcontinue(fd->lower, oflags);
  694. + if (status != PR_SUCCESS) {
  695. + PRErrorCode c = PR_GetError();
  696. + if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
  697. + // A connection failure occured, try another address
  698. + mState = SOCKS_INITIAL;
  699. + return ConnectToProxy(fd, PR_INTERVAL_NO_TIMEOUT);
  700. + }
  701. +
  702. + // We're still connecting
  703. + mPollFlags = PR_POLL_EXCEPT | PR_POLL_WRITE;
  704. + return PR_FAILURE;
  705. }
  706.  
  707. - if ((response[0] != 0x00) && (response[0] != 0x04)) {
  708. - // Novell BorderManager sends a response of type 4, should be zero
  709. - // According to the spec. Cope with this brokenness.
  710. - // it's not a SOCKS 4 reply or version 0 of the reply code
  711. - LOGERROR(("Not a SOCKS 4 reply. Expected: 0; received: %x.", response[0]));
  712. - return NS_ERROR_FAILURE;
  713. + // Connected now, send greeting
  714. + return SendGreeting(fd);
  715. +}
  716. +
  717. +PRStatus
  718. +nsSOCKSSocketInfo::HandleSocks4Connect(PRFileDesc *fd)
  719. +{
  720. + NS_ABORT_IF_FALSE(mState == SOCKS4_WANT_CONNECT_OK,
  721. + "Handling SOCKS 4 connection reply in wrong state!");
  722. + NS_ABORT_IF_FALSE(mInBuf.Length() == 8,
  723. + "SOCKS 4 connection reply must be 8 bytes!");
  724. +
  725. + LOGDEBUG(("socks4: checking connection reply"));
  726. +
  727. + // ignore version number
  728. + mPopOffset = 1;
  729. +
  730. + // see if our request was granted
  731. + if (PopUint8() == 90) {
  732. + LOGDEBUG(("socks4: connection successful!"));
  733. + mInBuf.Truncate();
  734. + mState = SOCKS_CONNECTED;
  735. + return PR_SUCCESS;
  736. }
  737.  
  738. - if (response[1] != 0x5A) { // = 90: request granted
  739. - // connect request not granted
  740. - LOGERROR(("Connection request refused. Expected: 90; received: %d.", response[1]));
  741. - return NS_ERROR_FAILURE;
  742. - }
  743. -
  744. - return NS_OK;
  745. -
  746. + LOGERROR(("socks4: unable to connect"));
  747. + PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
  748. + return PR_FAILURE;
  749. }
  750.  
  751. +PRStatus
  752. +nsSOCKSSocketInfo::HandleSocks5Auth(PRFileDesc *fd)
  753. +{
  754. + NS_ABORT_IF_FALSE(mState == SOCKS5_WANT_AUTH_NONE,
  755. + "Handling SOCKS 5 auth method reply in wrong state!");
  756. + NS_ABORT_IF_FALSE(mInBuf.Length() == 2,
  757. + "SOCKS 5 auth method reply must be 2 bytes!");
  758. +
  759. + LOGDEBUG(("socks5: checking auth method reply"));
  760. +
  761. + // ignore version number
  762. + mPopOffset = 1;
  763. +
  764. + // make sure our authentication choice was accepted
  765. + if (PopUint8() != 0x00) {
  766. + LOGERROR(("socks5: server did not accept our authentication method"));
  767. + PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
  768. + return PR_FAILURE;
  769. + }
  770. +
  771. + mInBuf.Truncate();
  772. +
  773. + // send socks 5 connect request
  774. + PRNetAddr *addr = &mDestinationAddr;
  775. + PRInt32 proxy_resolve;
  776. + proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
  777. +
  778. + LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
  779. + proxy_resolve? "yes" : "no"));
  780. +
  781. + PushUint8(0x05); // version -- 5
  782. + PushUint8(0x01); // command -- connect
  783. + PushUint8(0x00); // reserved
  784. +
  785. + if (proxy_resolve) {
  786. + // add the host name
  787. + if (mDestinationHost.Length() > 0xff) {
  788. + LOGERROR(("socks5: destination host name is too long!"));
  789. + PR_SetError(PR_BAD_ADDRESS_ERROR, 0);
  790. + return PR_FAILURE;
  791. + }
  792. + PushUint8(0x03); // addr type -- domainname
  793. + PushUint8(mDestinationHost.Length()); // name length
  794. + mOutBuf.Append(mDestinationHost); //
  795. + } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
  796. + PushUint8(0x01); // addr type -- IPv4
  797. + PushNetAddr(addr);
  798. + } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
  799. + PushUint8(0x04); // addr type -- IPv6
  800. + PushNetAddr(addr);
  801. + }
  802. +
  803. + PushNetPort(addr); // port
  804. +
  805. + mState = SOCKS5_WANT_CONNECT_OK;
  806. + WantRead(5);
  807. +
  808. + return Flush(fd);
  809. +}
  810. +
  811. +PRStatus
  812. +nsSOCKSSocketInfo::HandleSocks5Connect(PRFileDesc *fd)
  813. +{
  814. + PRUint8 res;
  815. + PRUint32 len;
  816. +
  817. + NS_ABORT_IF_FALSE(mState == SOCKS5_WANT_CONNECT_OK,
  818. + "Handling SOCKS 5 auth method reply in wrong state!");
  819. + NS_ABORT_IF_FALSE(mInBuf.Length() >= 5,
  820. + "SOCKS 5 connection reply must be at least 5 bytes!");
  821. +
  822. + LOGDEBUG(("socks5: checking connection reply"));
  823. +
  824. + // ignore version number
  825. + mPopOffset = 1;
  826. +
  827. + // check response
  828. + res = PopUint8();
  829. + if (res != 0x00) {
  830. + PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
  831. +
  832. + switch (res) {
  833. + case 0x01:
  834. + LOGERROR(("socks5: connect failed: "
  835. + "01, General SOCKS server failure."));
  836. + break;
  837. + case 0x02:
  838. + LOGERROR(("socks5: connect failed: "
  839. + "02, Connection not allowed by ruleset."));
  840. + break;
  841. + case 0x03:
  842. + LOGERROR(("socks5: connect failed: 03, Network unreachable."));
  843. + c = PR_NETWORK_UNREACHABLE_ERROR;
  844. + break;
  845. + case 0x04:
  846. + LOGERROR(("socks5: connect failed: 04, Host unreachable."));
  847. + break;
  848. + case 0x05:
  849. + LOGERROR(("socks5: connect failed: 05, Connection refused."));
  850. + break;
  851. + case 0x06:
  852. + LOGERROR(("socks5: connect failed: 06, TTL expired."));
  853. + c = PR_CONNECT_TIMEOUT_ERROR;
  854. + break;
  855. + case 0x07:
  856. + LOGERROR(("socks5: connect failed: "
  857. + "07, Command not supported."));
  858. + break;
  859. + case 0x08:
  860. + LOGERROR(("socks5: connect failed: "
  861. + "08, Address type not supported."));
  862. + c = PR_BAD_ADDRESS_ERROR;
  863. + break;
  864. + default:
  865. + LOGERROR(("socks5: connect failed."));
  866. + break;
  867. + }
  868. +
  869. + PR_SetError(c, 0);
  870. + return PR_FAILURE;
  871. + }
  872. +
  873. + // Ignore reserved field
  874. + mPopOffset++;
  875. +
  876. + // Determine address length
  877. + res = PopUint8();
  878. + switch (res) {
  879. + case 0x01: // ipv4
  880. + len = 4;
  881. + break;
  882. + case 0x04: // ipv6
  883. + len = 16;
  884. + break;
  885. + case 0x03: // fqdn
  886. + len = PopUint8() + 1;
  887. + break;
  888. + }
  889. +
  890. + // XXX check arithmatic
  891. + if (mInBuf.Length() < len + 6) {
  892. + // we've read in 5 bytes already
  893. + WantRead(len + 1);
  894. + // Attempt to read the rest immediately
  895. + if (Fill(fd) != PR_SUCCESS) {
  896. + LOGDEBUG(("socks5: need to wait to read addr and port"));
  897. + return PR_FAILURE;
  898. + }
  899. + }
  900. +
  901. + LOGDEBUG(("socks5: loading addr and port"));
  902. + // now read the address and port
  903. + switch (res) {
  904. + case 0x01: // ipv4
  905. + PopNetAddr(&mExternalProxyAddr, PR_AF_INET);
  906. + break;
  907. + case 0x04: // ipv6
  908. + PopNetAddr(&mExternalProxyAddr, PR_AF_INET6);
  909. + break;
  910. + case 0x03: // fqdn (skip)
  911. + mPopOffset += len - 1;
  912. + mExternalProxyAddr.raw.family = PR_AF_INET6;
  913. + break;
  914. + }
  915. +
  916. + PopNetPort(&mExternalProxyAddr);
  917. +
  918. + mInBuf.Truncate();
  919. + mState = SOCKS_CONNECTED;
  920. + LOGDEBUG(("socks5: connected!"));
  921. +
  922. + return PR_SUCCESS;
  923. +}
  924. +
  925. +const char *
  926. +nsSOCKSSocketInfo::StateToStr() const
  927. +{
  928. + switch (mState) {
  929. + case SOCKS_INITIAL:
  930. + return "SOCKS_INITIAL";
  931. + case SOCKS_CONNECTING_TO_PROXY:
  932. + return "SOCKS_CONNECTING_TO_PROXY";
  933. + case SOCKS4_WANT_CONNECT_OK:
  934. + return "SOCKS4_WANT_CONNECT_OK";
  935. + case SOCKS5_WANT_AUTH_NONE:
  936. + return "SOCKS5_WANT_AUTH_NONE";
  937. + case SOCKS5_WANT_CONNECT_OK:
  938. + return "SOCKS5_WANT_CONNECT_OK";
  939. + case SOCKS_CONNECTED:
  940. + return "SOCKS_CONNECTED";
  941. + }
  942. +
  943. + return "???";
  944. +}
  945. +
  946. +PRStatus
  947. +nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags,
  948. + PRIntervalTime to)
  949. +{
  950. + PRStatus ret;
  951. +
  952. + LOGDEBUG(("socks: DoHandshake(), state %s", StateToStr()));
  953. +
  954. + // Flush all pending data for a SOCKS request, then read the
  955. + // response. If we're still connecting to the SOCKS proxy and
  956. + // there's no I/O to do yet, Flush() and Fill() will simply return
  957. + // PR_SUCCESS
  958. + //
  959. + ret = Flush(fd);
  960. + if (ret != PR_SUCCESS)
  961. + return ret;
  962. +
  963. + ret = Fill(fd);
  964. + if (ret != PR_SUCCESS)
  965. + return ret;
  966. +
  967. + mPollFlags = 0;
  968. +
  969. + switch (mState) {
  970. + case SOCKS_INITIAL:
  971. + return ConnectToProxy(fd, to);
  972. + case SOCKS_CONNECTING_TO_PROXY:
  973. + return ContinueConnectingToProxy(fd, oflags);
  974. + case SOCKS4_WANT_CONNECT_OK:
  975. + return HandleSocks4Connect(fd);
  976. + case SOCKS5_WANT_AUTH_NONE:
  977. + return HandleSocks5Auth(fd);
  978. + case SOCKS5_WANT_CONNECT_OK:
  979. + return HandleSocks5Connect(fd);
  980. + case SOCKS_CONNECTED:
  981. + LOGERROR(("socks: already connected"));
  982. + PR_SetError(PR_IS_CONNECTED_ERROR, 0);
  983. + return PR_FAILURE;
  984. + }
  985. +
  986. + LOGERROR(("socks: executing handshake in invalid state, %d", mState));
  987. + PR_SetError(PR_INVALID_STATE_ERROR, 0);
  988. + return PR_FAILURE;
  989. +}
  990. +
  991. +void
  992. +nsSOCKSSocketInfo::PushUint8(PRUint8 v)
  993. +{
  994. + mOutBuf.Append((char)v);
  995. +}
  996. +
  997. +void
  998. +nsSOCKSSocketInfo::PushUint16(PRUint16 v)
  999. +{
  1000. + mOutBuf.Append((char*)&v, sizeof(v));
  1001. +}
  1002. +
  1003. +void
  1004. +nsSOCKSSocketInfo::PushUint32(PRUint32 v)
  1005. +{
  1006. + mOutBuf.Append((char*)&v, sizeof(v));
  1007. +}
  1008. +
  1009. +void
  1010. +nsSOCKSSocketInfo::PushNetAddr(const PRNetAddr *addr)
  1011. +{
  1012. + if (PR_NetAddrFamily(addr) == PR_AF_INET) {
  1013. + const char *ip = (const char*)&addr->inet.ip;
  1014. + mOutBuf.Append(ip, sizeof(addr->inet.ip));
  1015. + } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
  1016. + const char *ip = (const char*)addr->ipv6.ip.pr_s6_addr;
  1017. + mOutBuf.Append(ip, sizeof(addr->ipv6.ip.pr_s6_addr));
  1018. + }
  1019. +}
  1020. +
  1021. +void
  1022. +nsSOCKSSocketInfo::PushNetPort(const PRNetAddr *addr)
  1023. +{
  1024. + PushUint16(PR_NetAddrInetPort(addr));
  1025. +}
  1026. +
  1027. +PRUint8
  1028. +nsSOCKSSocketInfo::PopUint8()
  1029. +{
  1030. + PRUint8 rv;
  1031. + NS_ABORT_IF_FALSE(mPopOffset + sizeof(rv) <= mInBuf.Length(),
  1032. + "Not enough space to pop a uint8!");
  1033. + rv = (PRUint8)mInBuf[mPopOffset];
  1034. + mPopOffset += sizeof(rv);
  1035. + return rv;
  1036. +}
  1037. +
  1038. +PRUint16
  1039. +nsSOCKSSocketInfo::PopUint16()
  1040. +{
  1041. + PRUint16 rv;
  1042. + NS_ABORT_IF_FALSE(mPopOffset + sizeof(rv) <= mInBuf.Length(),
  1043. + "Not enough space to pop a uint16!");
  1044. + memcpy(&rv, mInBuf.Data() + mPopOffset, sizeof(rv));
  1045. + mPopOffset += sizeof(rv);
  1046. + return rv;
  1047. +}
  1048. +
  1049. +PRUint32
  1050. +nsSOCKSSocketInfo::PopUint32()
  1051. +{
  1052. + PRUint32 rv;
  1053. + NS_ABORT_IF_FALSE(mPopOffset + sizeof(rv) <= mInBuf.Length(),
  1054. + "Not enough space to pop a uint32!");
  1055. + memcpy(&rv, mInBuf.Data() + mPopOffset, sizeof(rv));
  1056. + mPopOffset += sizeof(rv);
  1057. + return rv;
  1058. +}
  1059. +
  1060. +void
  1061. +nsSOCKSSocketInfo::PopNetAddr(PRNetAddr *addr, PRUint16 fam)
  1062. +{
  1063. + PRUint32 amt;
  1064. + const char *ip = mInBuf.Data() + mPopOffset;
  1065. +
  1066. + addr->raw.family = fam;
  1067. + if (fam == PR_AF_INET) {
  1068. + amt = sizeof(addr->inet.ip);
  1069. + NS_ABORT_IF_FALSE(mPopOffset + amt <= mInBuf.Length(),
  1070. + "Not enough space to pop an ipv4 addr!");
  1071. + memcpy(&addr->inet.ip, ip, amt);
  1072. + } else if (fam == PR_AF_INET6) {
  1073. + amt = sizeof(addr->ipv6.ip.pr_s6_addr);
  1074. + NS_ABORT_IF_FALSE(mPopOffset + amt <= mInBuf.Length(),
  1075. + "Not enough space to pop an ipv6 addr!");
  1076. + memcpy(addr->ipv6.ip.pr_s6_addr, ip, amt);
  1077. + }
  1078. +
  1079. + mPopOffset += amt;
  1080. +}
  1081. +
  1082. +void
  1083. +nsSOCKSSocketInfo::PopNetPort(PRNetAddr *addr)
  1084. +{
  1085. + addr->inet.port = PopUint16();
  1086. +}
  1087. +
  1088. +void
  1089. +nsSOCKSSocketInfo::WantRead(PRInt32 sz)
  1090. +{
  1091. + NS_ABORT_IF_FALSE(mReadPtr == nsnull,
  1092. + "WantRead() called while read already in progress!");
  1093. +
  1094. + PRUint32 oldsz = mInBuf.Length();
  1095. + mInBuf.GetMutableData(&mReadPtr, oldsz + sz);
  1096. + mReadPtr += oldsz;
  1097. + mAmountToRead = sz;
  1098. +}
  1099. +
  1100. +PRStatus
  1101. +nsSOCKSSocketInfo::Fill(PRFileDesc *fd)
  1102. +{
  1103. + PRInt32 rc;
  1104. + const char *end;
  1105. +
  1106. + if (!mReadPtr) {
  1107. + LOGDEBUG(("socks: Fill(), nothing to do"));
  1108. + return PR_SUCCESS;
  1109. + }
  1110. +
  1111. + end = mInBuf.EndReading();
  1112. +
  1113. + while (mReadPtr < end) {
  1114. + rc = PR_Read(fd, mReadPtr, end - mReadPtr);
  1115. + if (rc <= 0) {
  1116. + if (rc == 0) {
  1117. + LOGERROR(("socks: proxy server closed connection"));
  1118. + PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
  1119. + } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
  1120. + LOGDEBUG(("socks: Fill(), want read"));
  1121. + mPollFlags = PR_POLL_READ;
  1122. + }
  1123. + break;
  1124. + }
  1125. +
  1126. + mReadPtr += rc;
  1127. + }
  1128. +
  1129. + LOGDEBUG(("socks: Fill(), have %d bytes total", mReadPtr - mInBuf.Data()));
  1130. + if (mReadPtr == end) {
  1131. + mReadPtr = nsnull;
  1132. + mAmountToRead = 0;
  1133. + return PR_SUCCESS;
  1134. + }
  1135. +
  1136. + return PR_FAILURE;
  1137. +}
  1138. +
  1139. +PRStatus
  1140. +nsSOCKSSocketInfo::Flush(PRFileDesc *fd)
  1141. +{
  1142. + PRInt32 len;
  1143. + PRInt32 offset;
  1144. + PRInt32 rc;
  1145. +
  1146. + offset = 0;
  1147. + len = mOutBuf.Length();
  1148. + if (len == 0) {
  1149. + LOGDEBUG(("socks: Flush(), nothing to do"));
  1150. + return PR_SUCCESS;
  1151. + }
  1152. +
  1153. + while (offset < len) {
  1154. + rc = PR_Write(fd, mOutBuf.Data() + offset, len - offset);
  1155. + if (rc < 0) {
  1156. + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
  1157. + LOGDEBUG(("socks: Flush(), want write"));
  1158. + mPollFlags = PR_POLL_WRITE;
  1159. + }
  1160. + break;
  1161. + }
  1162. +
  1163. + offset += rc;
  1164. + }
  1165. +
  1166. + LOGDEBUG(("socks: Flush(), wrote %d of %d bytes", (int)offset, (int)len));
  1167. + if (offset == len) {
  1168. + mOutBuf.Truncate();
  1169. + return PR_SUCCESS;
  1170. + }
  1171. +
  1172. + if (offset)
  1173. + mOutBuf.Cut(0, offset);
  1174. +
  1175. + return PR_FAILURE;
  1176. +}
  1177.  
  1178. static PRStatus
  1179. -nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*timeout*/)
  1180. +nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
  1181. {
  1182. + PRStatus status;
  1183. + PRNetAddr dst;
  1184.  
  1185. + nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1186. + if (info == NULL) return PR_FAILURE;
  1187. +
  1188. + if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
  1189. + PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
  1190. + const PRUint8 *srcp;
  1191. +
  1192. + LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
  1193. +
  1194. + // copied from _PR_ConvertToIpv4NetAddr()
  1195. + PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
  1196. + srcp = addr->ipv6.ip.pr_s6_addr;
  1197. + memcpy(&dst.inet.ip, srcp + 12, 4);
  1198. + dst.inet.family = PR_AF_INET;
  1199. + dst.inet.port = addr->ipv6.port;
  1200. + } else {
  1201. + memcpy(&dst, addr, sizeof(dst));
  1202. + }
  1203. +
  1204. + info->SetDestinationAddr(&dst);
  1205. + do {
  1206. + status = info->DoHandshake(fd, -1, to);
  1207. + } while (status == PR_SUCCESS && !info->IsConnected());
  1208. +
  1209. + return status;
  1210. +}
  1211. +
  1212. +static PRStatus
  1213. +nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, PRInt16 oflags)
  1214. +{
  1215. PRStatus status;
  1216.  
  1217. nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1218. if (info == NULL) return PR_FAILURE;
  1219.  
  1220. - // First, we need to look up our proxy...
  1221. - const nsCString &proxyHost = info->ProxyHost();
  1222. + do {
  1223. + status = info->DoHandshake(fd, oflags);
  1224. + } while (status == PR_SUCCESS && !info->IsConnected());
  1225.  
  1226. - if (proxyHost.IsEmpty())
  1227. - return PR_FAILURE;
  1228. + return status;
  1229. +}
  1230.  
  1231. - PRInt32 socksVersion = info->Version();
  1232. +static PRInt16
  1233. +nsSOCKSIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  1234. +{
  1235. + nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1236. + if (info == NULL) return PR_FAILURE;
  1237.  
  1238. - LOGDEBUG(("nsSOCKSIOLayerConnect SOCKS %u; proxyHost: %s.", socksVersion, proxyHost.get()));
  1239. -
  1240. - // Sync resolve the proxy hostname.
  1241. - PRNetAddr proxyAddr;
  1242. - nsCOMPtr<nsIDNSRecord> rec;
  1243. - nsresult rv;
  1244. - {
  1245. - nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
  1246. - if (!dns)
  1247. - return PR_FAILURE;
  1248. -
  1249. - rv = dns->Resolve(proxyHost, 0, getter_AddRefs(rec));
  1250. - if (NS_FAILED(rv))
  1251. - return PR_FAILURE;
  1252. + if (!info->IsConnected()) {
  1253. + *out_flags = 0;
  1254. + //LOGDEBUG(("socks: state %s, polling %hd",
  1255. + // info->StateToStr(), info->HowToPoll()));
  1256. + return info->HowToPoll();
  1257. }
  1258.  
  1259. - info->SetInternalProxyAddr(&proxyAddr);
  1260. -
  1261. - // For now, we'll do this as a blocking connect,
  1262. - // but with nspr 4.1, the necessary functions to
  1263. - // do a non-blocking connect will be available
  1264. -
  1265. - // Preserve the non-blocking state of the socket
  1266. - PRBool nonblocking;
  1267. - PRSocketOptionData sockopt;
  1268. - sockopt.option = PR_SockOpt_Nonblocking;
  1269. - status = PR_GetSocketOption(fd, &sockopt);
  1270. -
  1271. - if (PR_SUCCESS != status) {
  1272. - LOGERROR(("PR_GetSocketOption() failed. status = %x.", status));
  1273. - return status;
  1274. - }
  1275. -
  1276. - // Store blocking option
  1277. - nonblocking = sockopt.value.non_blocking;
  1278. -
  1279. - sockopt.option = PR_SockOpt_Nonblocking;
  1280. - sockopt.value.non_blocking = PR_FALSE;
  1281. - status = PR_SetSocketOption(fd, &sockopt);
  1282. -
  1283. - if (PR_SUCCESS != status) {
  1284. - LOGERROR(("PR_SetSocketOption() failed. status = %x.", status));
  1285. - return status;
  1286. - }
  1287. -
  1288. - // Now setup sockopts, so we can restore the value later.
  1289. - sockopt.option = PR_SockOpt_Nonblocking;
  1290. - sockopt.value.non_blocking = nonblocking;
  1291. -
  1292. - // This connectWait should be long enough to connect to local proxy
  1293. - // servers, but not much longer. Since this protocol negotiation
  1294. - // uses blocking network calls, the app can appear to hang for a maximum
  1295. - // of this time if the user presses the STOP button during the SOCKS
  1296. - // connection negotiation. Note that this value only applies to the
  1297. - // connecting to the SOCKS server: once the SOCKS connection has been
  1298. - // established, the value is not used anywhere else.
  1299. - PRIntervalTime connectWait = PR_SecondsToInterval(10);
  1300. -
  1301. - // Connect to the proxy server.
  1302. - PRInt32 addresses = 0;
  1303. - do {
  1304. - rv = rec->GetNextAddr(info->ProxyPort(), &proxyAddr);
  1305. - if (NS_FAILED(rv)) {
  1306. - status = PR_FAILURE;
  1307. - break;
  1308. - }
  1309. - ++addresses;
  1310. - status = fd->lower->methods->connect(fd->lower, &proxyAddr, connectWait);
  1311. - } while (PR_SUCCESS != status);
  1312. -
  1313. - if (PR_SUCCESS != status) {
  1314. - LOGERROR(("Failed to TCP connect to the proxy server (%s): timeout = %d, status = %x, tried %d addresses.", proxyHost.get(), connectWait, status, addresses));
  1315. - PR_SetSocketOption(fd, &sockopt);
  1316. - return status;
  1317. - }
  1318. -
  1319. -
  1320. - // We are now connected to the SOCKS proxy server.
  1321. - // Now we will negotiate a connection to the desired server.
  1322. -
  1323. - // External IP address returned from ConnectSOCKS5(). Not supported in SOCKS4.
  1324. - PRNetAddr extAddr;
  1325. - PR_InitializeNetAddr(PR_IpAddrNull, 0, &extAddr);
  1326. -
  1327. - NS_ASSERTION((socksVersion == 4) || (socksVersion == 5), "SOCKS Version must be selected");
  1328. -
  1329. - // Try to connect via SOCKS 5.
  1330. - if (socksVersion == 5) {
  1331. - rv = ConnectSOCKS5(fd, addr, &extAddr, connectWait);
  1332. -
  1333. - if (NS_FAILED(rv)) {
  1334. - PR_SetSocketOption(fd, &sockopt);
  1335. - return PR_FAILURE;
  1336. - }
  1337. -
  1338. - }
  1339. -
  1340. - // Try to connect via SOCKS 4.
  1341. - else {
  1342. - rv = ConnectSOCKS4(fd, addr, connectWait);
  1343. -
  1344. - if (NS_FAILED(rv)) {
  1345. - PR_SetSocketOption(fd, &sockopt);
  1346. - return PR_FAILURE;
  1347. - }
  1348. -
  1349. - }
  1350. -
  1351. -
  1352. - info->SetDestinationAddr((PRNetAddr*)addr);
  1353. - info->SetExternalProxyAddr(&extAddr);
  1354. -
  1355. - // restore non-blocking option
  1356. - PR_SetSocketOption(fd, &sockopt);
  1357. -
  1358. - // we're set-up and connected.
  1359. - // this socket can be used as normal now.
  1360. -
  1361. - return PR_SUCCESS;
  1362. + return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
  1363. }
  1364.  
  1365. static PRStatus
  1366. nsSOCKSIOLayerClose(PRFileDesc *fd)
  1367. {
  1368. nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
  1369. PRDescIdentity id = PR_GetLayersIdentity(fd);
  1370.  
  1371. @@ -880,16 +953,18 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family
  1372.  
  1373.  
  1374. if (firstTime)
  1375. {
  1376. nsSOCKSIOLayerIdentity = PR_GetUniqueIdentity("SOCKS layer");
  1377. nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods();
  1378.  
  1379. nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect;
  1380. + nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue;
  1381. + nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll;
  1382. nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind;
  1383. nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
  1384. nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
  1385. nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName;
  1386. nsSOCKSIOLayerMethods.accept = nsSOCKSIOLayerAccept;
  1387. nsSOCKSIOLayerMethods.listen = nsSOCKSIOLayerListen;
  1388. nsSOCKSIOLayerMethods.close = nsSOCKSIOLayerClose;
Add Comment
Please, Sign In to add comment