socks.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. ***************************************************************************/
  23. #include "setup.h"
  24. #if !defined(CURL_DISABLE_PROXY) || defined(USE_WINDOWS_SSPI)
  25. #include <string.h>
  26. #ifdef HAVE_STDLIB_H
  27. #include <stdlib.h>
  28. #endif
  29. #ifdef HAVE_SYS_SOCKET_H
  30. #include <sys/socket.h>
  31. #endif
  32. #ifdef HAVE_NETINET_IN_H
  33. #include <netinet/in.h>
  34. #endif
  35. #ifdef HAVE_ARPA_INET_H
  36. #include <arpa/inet.h>
  37. #endif
  38. #include "urldata.h"
  39. #include "sendf.h"
  40. #include "strequal.h"
  41. #include "select.h"
  42. #include "connect.h"
  43. #include "timeval.h"
  44. #include "socks.h"
  45. /* The last #include file should be: */
  46. #include "memdebug.h"
  47. /*
  48. * Helper read-from-socket functions. Does the same as Curl_read() but it
  49. * blocks until all bytes amount of buffersize will be read. No more, no less.
  50. *
  51. * This is STUPID BLOCKING behaviour which we frown upon, but right now this
  52. * is what we have...
  53. */
  54. int Curl_blockread_all(struct connectdata *conn, /* connection data */
  55. curl_socket_t sockfd, /* read from this socket */
  56. char *buf, /* store read data here */
  57. ssize_t buffersize, /* max amount to read */
  58. ssize_t *n, /* amount bytes read */
  59. long conn_timeout) /* timeout for data wait
  60. relative to
  61. conn->created */
  62. {
  63. ssize_t nread;
  64. ssize_t allread = 0;
  65. int result;
  66. struct timeval tvnow;
  67. long conntime;
  68. *n = 0;
  69. do {
  70. tvnow = Curl_tvnow();
  71. /* calculating how long connection is establishing */
  72. conntime = Curl_tvdiff(tvnow, conn->created);
  73. if(conntime > conn_timeout) {
  74. /* we already got the timeout */
  75. result = ~CURLE_OK;
  76. break;
  77. }
  78. if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD,
  79. (int)(conn_timeout - conntime)) <= 0) {
  80. result = ~CURLE_OK;
  81. break;
  82. }
  83. result = Curl_read_plain(sockfd, buf, buffersize, &nread);
  84. if(result)
  85. break;
  86. if(buffersize == nread) {
  87. allread += nread;
  88. *n = allread;
  89. result = CURLE_OK;
  90. break;
  91. }
  92. if(!nread) {
  93. result = ~CURLE_OK;
  94. break;
  95. }
  96. buffersize -= nread;
  97. buf += nread;
  98. allread += nread;
  99. } while(1);
  100. return result;
  101. }
  102. /*
  103. * This function logs in to a SOCKS4 proxy and sends the specifics to the final
  104. * destination server.
  105. *
  106. * Reference :
  107. * http://socks.permeo.com/protocol/socks4.protocol
  108. *
  109. * Note :
  110. * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
  111. * Nonsupport "Identification Protocol (RFC1413)"
  112. */
  113. CURLcode Curl_SOCKS4(const char *proxy_name,
  114. const char *hostname,
  115. int remote_port,
  116. int sockindex,
  117. struct connectdata *conn,
  118. bool protocol4a)
  119. {
  120. #define SOCKS4REQLEN 262
  121. unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
  122. id */
  123. int result;
  124. CURLcode code;
  125. curl_socket_t sock = conn->sock[sockindex];
  126. long timeout;
  127. struct SessionHandle *data = conn->data;
  128. /* get timeout */
  129. timeout = Curl_timeleft(conn, NULL, TRUE);
  130. if(timeout < 0) {
  131. /* time-out, bail out, go home */
  132. failf(data, "Connection time-out");
  133. return CURLE_OPERATION_TIMEDOUT;
  134. }
  135. curlx_nonblock(sock, FALSE);
  136. /*
  137. * Compose socks4 request
  138. *
  139. * Request format
  140. *
  141. * +----+----+----+----+----+----+----+----+----+----+....+----+
  142. * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
  143. * +----+----+----+----+----+----+----+----+----+----+....+----+
  144. * # of bytes: 1 1 2 4 variable 1
  145. */
  146. socksreq[0] = 4; /* version (SOCKS4) */
  147. socksreq[1] = 1; /* connect */
  148. *((unsigned short*)&socksreq[2]) = htons((unsigned short)remote_port);
  149. /* DNS resolve only for SOCKS4, not SOCKS4a */
  150. if (!protocol4a) {
  151. struct Curl_dns_entry *dns;
  152. Curl_addrinfo *hp=NULL;
  153. int rc;
  154. rc = Curl_resolv(conn, hostname, remote_port, &dns);
  155. if(rc == CURLRESOLV_ERROR)
  156. return CURLE_COULDNT_RESOLVE_PROXY;
  157. if(rc == CURLRESOLV_PENDING)
  158. /* this requires that we're in "wait for resolve" state */
  159. rc = Curl_wait_for_resolv(conn, &dns);
  160. /*
  161. * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
  162. * returns a Curl_addrinfo pointer that may not always look the same.
  163. */
  164. if(dns)
  165. hp=dns->addr;
  166. if(hp) {
  167. char buf[64];
  168. unsigned short ip[4];
  169. Curl_printable_address(hp, buf, sizeof(buf));
  170. if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
  171. &ip[0], &ip[1], &ip[2], &ip[3])) {
  172. /* Set DSTIP */
  173. socksreq[4] = (unsigned char)ip[0];
  174. socksreq[5] = (unsigned char)ip[1];
  175. socksreq[6] = (unsigned char)ip[2];
  176. socksreq[7] = (unsigned char)ip[3];
  177. }
  178. else
  179. hp = NULL; /* fail! */
  180. Curl_resolv_unlock(data, dns); /* not used anymore from now on */
  181. }
  182. if(!hp) {
  183. failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
  184. hostname);
  185. return CURLE_COULDNT_RESOLVE_HOST;
  186. }
  187. }
  188. /*
  189. * This is currently not supporting "Identification Protocol (RFC1413)".
  190. */
  191. socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
  192. if(proxy_name)
  193. strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8);
  194. /*
  195. * Make connection
  196. */
  197. {
  198. ssize_t actualread;
  199. ssize_t written;
  200. ssize_t hostnamelen = 0;
  201. int packetsize = 9 +
  202. (int)strlen((char*)socksreq + 8); /* size including NUL */
  203. /* If SOCKS4a, set special invalid IP address 0.0.0.x */
  204. if (protocol4a) {
  205. socksreq[4] = 0;
  206. socksreq[5] = 0;
  207. socksreq[6] = 0;
  208. socksreq[7] = 1;
  209. /* If still enough room in buffer, also append hostname */
  210. hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
  211. if (packetsize + hostnamelen <= SOCKS4REQLEN)
  212. strcpy((char*)socksreq + packetsize, hostname);
  213. else
  214. hostnamelen = 0; /* Flag: hostname did not fit in buffer */
  215. }
  216. /* Send request */
  217. code = Curl_write_plain(conn, sock, (char *)socksreq,
  218. packetsize + hostnamelen,
  219. &written);
  220. if((code != CURLE_OK) || (written != packetsize + hostnamelen)) {
  221. failf(data, "Failed to send SOCKS4 connect request.");
  222. return CURLE_COULDNT_CONNECT;
  223. }
  224. if (protocol4a && hostnamelen == 0) {
  225. /* SOCKS4a with very long hostname - send that name separately */
  226. hostnamelen = (ssize_t)strlen(hostname) + 1;
  227. code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
  228. &written);
  229. if((code != CURLE_OK) || (written != hostnamelen)) {
  230. failf(data, "Failed to send SOCKS4 connect request.");
  231. return CURLE_COULDNT_CONNECT;
  232. }
  233. }
  234. packetsize = 8; /* receive data size */
  235. /* Receive response */
  236. result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
  237. &actualread, timeout);
  238. if((result != CURLE_OK) || (actualread != packetsize)) {
  239. failf(data, "Failed to receive SOCKS4 connect request ack.");
  240. return CURLE_COULDNT_CONNECT;
  241. }
  242. /*
  243. * Response format
  244. *
  245. * +----+----+----+----+----+----+----+----+
  246. * | VN | CD | DSTPORT | DSTIP |
  247. * +----+----+----+----+----+----+----+----+
  248. * # of bytes: 1 1 2 4
  249. *
  250. * VN is the version of the reply code and should be 0. CD is the result
  251. * code with one of the following values:
  252. *
  253. * 90: request granted
  254. * 91: request rejected or failed
  255. * 92: request rejected because SOCKS server cannot connect to
  256. * identd on the client
  257. * 93: request rejected because the client program and identd
  258. * report different user-ids
  259. */
  260. /* wrong version ? */
  261. if(socksreq[0] != 0) {
  262. failf(data,
  263. "SOCKS4 reply has wrong version, version should be 4.");
  264. return CURLE_COULDNT_CONNECT;
  265. }
  266. /* Result */
  267. switch(socksreq[1])
  268. {
  269. case 90:
  270. if (protocol4a)
  271. infof(data, "SOCKS4a request granted.\n");
  272. else
  273. infof(data, "SOCKS4 request granted.\n");
  274. break;
  275. case 91:
  276. failf(data,
  277. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  278. ", request rejected or failed.",
  279. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  280. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  281. (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
  282. socksreq[1]);
  283. return CURLE_COULDNT_CONNECT;
  284. case 92:
  285. failf(data,
  286. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  287. ", request rejected because SOCKS server cannot connect to "
  288. "identd on the client.",
  289. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  290. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  291. (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
  292. socksreq[1]);
  293. return CURLE_COULDNT_CONNECT;
  294. case 93:
  295. failf(data,
  296. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  297. ", request rejected because the client program and identd "
  298. "report different user-ids.",
  299. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  300. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  301. (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
  302. socksreq[1]);
  303. return CURLE_COULDNT_CONNECT;
  304. default:
  305. failf(data,
  306. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  307. ", Unknown.",
  308. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  309. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  310. (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
  311. socksreq[1]);
  312. return CURLE_COULDNT_CONNECT;
  313. }
  314. }
  315. curlx_nonblock(sock, TRUE);
  316. return CURLE_OK; /* Proxy was successful! */
  317. }
  318. /*
  319. * This function logs in to a SOCKS5 proxy and sends the specifics to the final
  320. * destination server.
  321. */
  322. CURLcode Curl_SOCKS5(const char *proxy_name,
  323. const char *proxy_password,
  324. const char *hostname,
  325. int remote_port,
  326. int sockindex,
  327. struct connectdata *conn)
  328. {
  329. /*
  330. According to the RFC1928, section "6. Replies". This is what a SOCK5
  331. replies:
  332. +----+-----+-------+------+----------+----------+
  333. |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  334. +----+-----+-------+------+----------+----------+
  335. | 1 | 1 | X'00' | 1 | Variable | 2 |
  336. +----+-----+-------+------+----------+----------+
  337. Where:
  338. o VER protocol version: X'05'
  339. o REP Reply field:
  340. o X'00' succeeded
  341. */
  342. unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
  343. ssize_t actualread;
  344. ssize_t written;
  345. int result;
  346. CURLcode code;
  347. curl_socket_t sock = conn->sock[sockindex];
  348. struct SessionHandle *data = conn->data;
  349. long timeout;
  350. bool socks5_resolve_local = (bool)(data->set.proxytype == CURLPROXY_SOCKS5);
  351. const size_t hostname_len = strlen(hostname);
  352. ssize_t packetsize = 0;
  353. /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
  354. if(!socks5_resolve_local && hostname_len > 255)
  355. {
  356. infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
  357. "length > 255 [actual len=%d]\n", hostname_len);
  358. socks5_resolve_local = TRUE;
  359. }
  360. /* get timeout */
  361. timeout = Curl_timeleft(conn, NULL, TRUE);
  362. if(timeout < 0) {
  363. /* time-out, bail out, go home */
  364. failf(data, "Connection time-out");
  365. return CURLE_OPERATION_TIMEDOUT;
  366. }
  367. curlx_nonblock(sock, TRUE);
  368. /* wait until socket gets connected */
  369. result = Curl_socket_ready(CURL_SOCKET_BAD, sock, (int)timeout);
  370. if(-1 == result) {
  371. failf(conn->data, "SOCKS5: no connection here");
  372. return CURLE_COULDNT_CONNECT;
  373. }
  374. else if(0 == result) {
  375. failf(conn->data, "SOCKS5: connection timeout");
  376. return CURLE_OPERATION_TIMEDOUT;
  377. }
  378. if(result & CURL_CSELECT_ERR) {
  379. failf(conn->data, "SOCKS5: error occured during connection");
  380. return CURLE_COULDNT_CONNECT;
  381. }
  382. socksreq[0] = 5; /* version */
  383. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  384. socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
  385. socksreq[2] = 0; /* no authentication */
  386. socksreq[3] = 1; /* gssapi */
  387. socksreq[4] = 2; /* username/password */
  388. #else
  389. socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
  390. socksreq[2] = 0; /* no authentication */
  391. socksreq[3] = 2; /* username/password */
  392. #endif
  393. curlx_nonblock(sock, FALSE);
  394. code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
  395. &written);
  396. if((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
  397. failf(data, "Unable to send initial SOCKS5 request.");
  398. return CURLE_COULDNT_CONNECT;
  399. }
  400. curlx_nonblock(sock, TRUE);
  401. result = Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout);
  402. if(-1 == result) {
  403. failf(conn->data, "SOCKS5 nothing to read");
  404. return CURLE_COULDNT_CONNECT;
  405. }
  406. else if(0 == result) {
  407. failf(conn->data, "SOCKS5 read timeout");
  408. return CURLE_OPERATION_TIMEDOUT;
  409. }
  410. if(result & CURL_CSELECT_ERR) {
  411. failf(conn->data, "SOCKS5 read error occured");
  412. return CURLE_RECV_ERROR;
  413. }
  414. curlx_nonblock(sock, FALSE);
  415. result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
  416. timeout);
  417. if((result != CURLE_OK) || (actualread != 2)) {
  418. failf(data, "Unable to receive initial SOCKS5 response.");
  419. return CURLE_COULDNT_CONNECT;
  420. }
  421. if(socksreq[0] != 5) {
  422. failf(data, "Received invalid version in initial SOCKS5 response.");
  423. return CURLE_COULDNT_CONNECT;
  424. }
  425. if(socksreq[1] == 0) {
  426. /* Nothing to do, no authentication needed */
  427. ;
  428. }
  429. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  430. else if(socksreq[1] == 1) {
  431. code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
  432. if(code != CURLE_OK) {
  433. failf(data, "Unable to negotiate SOCKS5 gssapi context.");
  434. return CURLE_COULDNT_CONNECT;
  435. }
  436. }
  437. #endif
  438. else if(socksreq[1] == 2) {
  439. /* Needs user name and password */
  440. size_t userlen, pwlen;
  441. int len;
  442. if(proxy_name && proxy_password) {
  443. userlen = strlen(proxy_name);
  444. pwlen = strlen(proxy_password);
  445. }
  446. else {
  447. userlen = 0;
  448. pwlen = 0;
  449. }
  450. /* username/password request looks like
  451. * +----+------+----------+------+----------+
  452. * |VER | ULEN | UNAME | PLEN | PASSWD |
  453. * +----+------+----------+------+----------+
  454. * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
  455. * +----+------+----------+------+----------+
  456. */
  457. len = 0;
  458. socksreq[len++] = 1; /* username/pw subnegotiation version */
  459. socksreq[len++] = (char) userlen;
  460. memcpy(socksreq + len, proxy_name, userlen);
  461. len += (int)userlen;
  462. socksreq[len++] = (char) pwlen;
  463. memcpy(socksreq + len, proxy_password, pwlen);
  464. len += (int)pwlen;
  465. code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
  466. if((code != CURLE_OK) || (len != written)) {
  467. failf(data, "Failed to send SOCKS5 sub-negotiation request.");
  468. return CURLE_COULDNT_CONNECT;
  469. }
  470. result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
  471. timeout);
  472. if((result != CURLE_OK) || (actualread != 2)) {
  473. failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
  474. return CURLE_COULDNT_CONNECT;
  475. }
  476. /* ignore the first (VER) byte */
  477. if(socksreq[1] != 0) { /* status */
  478. failf(data, "User was rejected by the SOCKS5 server (%d %d).",
  479. socksreq[0], socksreq[1]);
  480. return CURLE_COULDNT_CONNECT;
  481. }
  482. /* Everything is good so far, user was authenticated! */
  483. }
  484. else {
  485. /* error */
  486. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  487. if(socksreq[1] == 255) {
  488. #else
  489. if(socksreq[1] == 1) {
  490. failf(data,
  491. "SOCKS5 GSSAPI per-message authentication is not supported.");
  492. return CURLE_COULDNT_CONNECT;
  493. }
  494. else if(socksreq[1] == 255) {
  495. #endif
  496. if(!proxy_name || !*proxy_name) {
  497. failf(data,
  498. "No authentication method was acceptable. (It is quite likely"
  499. " that the SOCKS5 server wanted a username/password, since none"
  500. " was supplied to the server on this connection.)");
  501. }
  502. else {
  503. failf(data, "No authentication method was acceptable.");
  504. }
  505. return CURLE_COULDNT_CONNECT;
  506. }
  507. else {
  508. failf(data,
  509. "Undocumented SOCKS5 mode attempted to be used by server.");
  510. return CURLE_COULDNT_CONNECT;
  511. }
  512. }
  513. /* Authentication is complete, now specify destination to the proxy */
  514. socksreq[0] = 5; /* version (SOCKS5) */
  515. socksreq[1] = 1; /* connect */
  516. socksreq[2] = 0; /* must be zero */
  517. if(!socks5_resolve_local) {
  518. packetsize = (ssize_t)(5 + hostname_len + 2);
  519. socksreq[3] = 3; /* ATYP: domain name = 3 */
  520. socksreq[4] = (char) hostname_len; /* address length */
  521. memcpy(&socksreq[5], hostname, hostname_len); /* address bytes w/o NULL */
  522. *((unsigned short*)&socksreq[hostname_len+5]) =
  523. htons((unsigned short)remote_port);
  524. }
  525. else {
  526. struct Curl_dns_entry *dns;
  527. Curl_addrinfo *hp=NULL;
  528. int rc = Curl_resolv(conn, hostname, remote_port, &dns);
  529. packetsize = 10;
  530. socksreq[3] = 1; /* IPv4 = 1 */
  531. if(rc == CURLRESOLV_ERROR)
  532. return CURLE_COULDNT_RESOLVE_HOST;
  533. if(rc == CURLRESOLV_PENDING)
  534. /* this requires that we're in "wait for resolve" state */
  535. rc = Curl_wait_for_resolv(conn, &dns);
  536. /*
  537. * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
  538. * returns a Curl_addrinfo pointer that may not always look the same.
  539. */
  540. if(dns)
  541. hp=dns->addr;
  542. if(hp) {
  543. char buf[64];
  544. unsigned short ip[4];
  545. Curl_printable_address(hp, buf, sizeof(buf));
  546. if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
  547. &ip[0], &ip[1], &ip[2], &ip[3])) {
  548. socksreq[4] = (unsigned char)ip[0];
  549. socksreq[5] = (unsigned char)ip[1];
  550. socksreq[6] = (unsigned char)ip[2];
  551. socksreq[7] = (unsigned char)ip[3];
  552. }
  553. else
  554. hp = NULL; /* fail! */
  555. Curl_resolv_unlock(data, dns); /* not used anymore from now on */
  556. }
  557. if(!hp) {
  558. failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
  559. hostname);
  560. return CURLE_COULDNT_RESOLVE_HOST;
  561. }
  562. *((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port);
  563. }
  564. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  565. if(conn->socks5_gssapi_enctype) {
  566. failf(data, "SOCKS5 gssapi protection not yet implemented.");
  567. } else
  568. #endif
  569. code = Curl_write_plain(conn, sock, (char *)socksreq, packetsize, &written);
  570. if((code != CURLE_OK) || (written != packetsize)) {
  571. failf(data, "Failed to send SOCKS5 connect request.");
  572. return CURLE_COULDNT_CONNECT;
  573. }
  574. packetsize = 10; /* minimum packet size is 10 */
  575. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  576. if(conn->socks5_gssapi_enctype) {
  577. failf(data, "SOCKS5 gssapi protection not yet implemented.");
  578. } else
  579. #endif
  580. result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
  581. &actualread, timeout);
  582. if((result != CURLE_OK) || (actualread != packetsize)) {
  583. failf(data, "Failed to receive SOCKS5 connect request ack.");
  584. return CURLE_COULDNT_CONNECT;
  585. }
  586. if(socksreq[0] != 5) { /* version */
  587. failf(data,
  588. "SOCKS5 reply has wrong version, version should be 5.");
  589. return CURLE_COULDNT_CONNECT;
  590. }
  591. if(socksreq[1] != 0) { /* Anything besides 0 is an error */
  592. failf(data,
  593. "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
  594. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  595. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  596. (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
  597. socksreq[1]);
  598. return CURLE_COULDNT_CONNECT;
  599. }
  600. /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
  601. 1928, so the reply packet should be read until the end to avoid errors at
  602. subsequent protocol level.
  603. +----+-----+-------+------+----------+----------+
  604. |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  605. +----+-----+-------+------+----------+----------+
  606. | 1 | 1 | X'00' | 1 | Variable | 2 |
  607. +----+-----+-------+------+----------+----------+
  608. ATYP:
  609. o IP v4 address: X'01', BND.ADDR = 4 byte
  610. o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
  611. o IP v6 address: X'04', BND.ADDR = 16 byte
  612. */
  613. /* Calculate real packet size */
  614. if(socksreq[3] == 3) {
  615. /* domain name */
  616. int addrlen = (int) socksreq[4];
  617. packetsize = 5 + addrlen + 2;
  618. }
  619. else if(socksreq[3] == 4) {
  620. /* IPv6 */
  621. packetsize = 4 + 16 + 2;
  622. }
  623. /* At this point we already read first 10 bytes */
  624. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  625. if(!conn->socks5_gssapi_enctype) {
  626. /* decrypt_gssapi_blockread already read the whole packet */
  627. #endif
  628. if(packetsize > 10) {
  629. packetsize -= 10;
  630. result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
  631. packetsize, &actualread, timeout);
  632. if((result != CURLE_OK) || (actualread != packetsize)) {
  633. failf(data, "Failed to receive SOCKS5 connect request ack.");
  634. return CURLE_COULDNT_CONNECT;
  635. }
  636. }
  637. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  638. }
  639. #endif
  640. curlx_nonblock(sock, TRUE);
  641. return CURLE_OK; /* Proxy was successful! */
  642. }
  643. #endif /* CURL_DISABLE_PROXY */