socks.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, 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 https://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. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #if !defined(CURL_DISABLE_PROXY)
  24. #ifdef HAVE_NETINET_IN_H
  25. #include <netinet/in.h>
  26. #endif
  27. #ifdef HAVE_ARPA_INET_H
  28. #include <arpa/inet.h>
  29. #endif
  30. #include "urldata.h"
  31. #include "sendf.h"
  32. #include "select.h"
  33. #include "connect.h"
  34. #include "timeval.h"
  35. #include "socks.h"
  36. #include "multiif.h" /* for getsock macros */
  37. /* The last 3 #include files should be in this order */
  38. #include "curl_printf.h"
  39. #include "curl_memory.h"
  40. #include "memdebug.h"
  41. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  42. /*
  43. * Helper read-from-socket functions. Does the same as Curl_read() but it
  44. * blocks until all bytes amount of buffersize will be read. No more, no less.
  45. *
  46. * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
  47. */
  48. int Curl_blockread_all(struct connectdata *conn, /* connection data */
  49. curl_socket_t sockfd, /* read from this socket */
  50. char *buf, /* store read data here */
  51. ssize_t buffersize, /* max amount to read */
  52. ssize_t *n) /* amount bytes read */
  53. {
  54. ssize_t nread = 0;
  55. ssize_t allread = 0;
  56. int result;
  57. *n = 0;
  58. for(;;) {
  59. timediff_t timeleft = Curl_timeleft(conn->data, NULL, TRUE);
  60. if(timeleft < 0) {
  61. /* we already got the timeout */
  62. result = CURLE_OPERATION_TIMEDOUT;
  63. break;
  64. }
  65. if(SOCKET_READABLE(sockfd, timeleft) <= 0) {
  66. result = ~CURLE_OK;
  67. break;
  68. }
  69. result = Curl_read_plain(sockfd, buf, buffersize, &nread);
  70. if(CURLE_AGAIN == result)
  71. continue;
  72. if(result)
  73. break;
  74. if(buffersize == nread) {
  75. allread += nread;
  76. *n = allread;
  77. result = CURLE_OK;
  78. break;
  79. }
  80. if(!nread) {
  81. result = ~CURLE_OK;
  82. break;
  83. }
  84. buffersize -= nread;
  85. buf += nread;
  86. allread += nread;
  87. }
  88. return result;
  89. }
  90. #endif
  91. #ifndef DEBUGBUILD
  92. #define sxstate(x,y) socksstate(x,y)
  93. #else
  94. #define sxstate(x,y) socksstate(x,y, __LINE__)
  95. #endif
  96. /* always use this function to change state, to make debugging easier */
  97. static void socksstate(struct connectdata *conn,
  98. enum connect_t state
  99. #ifdef DEBUGBUILD
  100. , int lineno
  101. #endif
  102. )
  103. {
  104. enum connect_t oldstate = conn->cnnct.state;
  105. #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  106. /* synced with the state list in urldata.h */
  107. static const char * const statename[] = {
  108. "INIT",
  109. "SOCKS_INIT",
  110. "SOCKS_SEND",
  111. "SOCKS_READ_INIT",
  112. "SOCKS_READ",
  113. "GSSAPI_INIT",
  114. "AUTH_INIT",
  115. "AUTH_SEND",
  116. "AUTH_READ",
  117. "REQ_INIT",
  118. "RESOLVING",
  119. "RESOLVED",
  120. "RESOLVE_REMOTE",
  121. "REQ_SEND",
  122. "REQ_SENDING",
  123. "REQ_READ",
  124. "REQ_READ_MORE",
  125. "DONE"
  126. };
  127. #endif
  128. if(oldstate == state)
  129. /* don't bother when the new state is the same as the old state */
  130. return;
  131. conn->cnnct.state = state;
  132. #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  133. infof(conn->data,
  134. "SXSTATE: %s => %s conn %p; line %d\n",
  135. statename[oldstate], statename[conn->cnnct.state], conn,
  136. lineno);
  137. #endif
  138. }
  139. int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
  140. int sockindex)
  141. {
  142. int rc = 0;
  143. sock[0] = conn->sock[sockindex];
  144. switch(conn->cnnct.state) {
  145. case CONNECT_RESOLVING:
  146. case CONNECT_SOCKS_READ:
  147. case CONNECT_AUTH_READ:
  148. case CONNECT_REQ_READ:
  149. case CONNECT_REQ_READ_MORE:
  150. rc = GETSOCK_READSOCK(0);
  151. break;
  152. default:
  153. rc = GETSOCK_WRITESOCK(0);
  154. break;
  155. }
  156. return rc;
  157. }
  158. /*
  159. * This function logs in to a SOCKS4 proxy and sends the specifics to the final
  160. * destination server.
  161. *
  162. * Reference :
  163. * https://www.openssh.com/txt/socks4.protocol
  164. *
  165. * Note :
  166. * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
  167. * Nonsupport "Identification Protocol (RFC1413)"
  168. */
  169. CURLcode Curl_SOCKS4(const char *proxy_user,
  170. const char *hostname,
  171. int remote_port,
  172. int sockindex,
  173. struct connectdata *conn,
  174. bool *done)
  175. {
  176. const bool protocol4a =
  177. (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
  178. unsigned char *socksreq = &conn->cnnct.socksreq[0];
  179. CURLcode result;
  180. curl_socket_t sockfd = conn->sock[sockindex];
  181. struct Curl_easy *data = conn->data;
  182. struct connstate *sx = &conn->cnnct;
  183. struct Curl_dns_entry *dns = NULL;
  184. ssize_t actualread;
  185. ssize_t written;
  186. if(!SOCKS_STATE(sx->state) && !*done)
  187. sxstate(conn, CONNECT_SOCKS_INIT);
  188. switch(sx->state) {
  189. case CONNECT_SOCKS_INIT:
  190. if(conn->bits.httpproxy)
  191. infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
  192. protocol4a ? "a" : "", hostname, remote_port);
  193. infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
  194. /*
  195. * Compose socks4 request
  196. *
  197. * Request format
  198. *
  199. * +----+----+----+----+----+----+----+----+----+----+....+----+
  200. * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
  201. * +----+----+----+----+----+----+----+----+----+----+....+----+
  202. * # of bytes: 1 1 2 4 variable 1
  203. */
  204. socksreq[0] = 4; /* version (SOCKS4) */
  205. socksreq[1] = 1; /* connect */
  206. socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
  207. socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
  208. /* DNS resolve only for SOCKS4, not SOCKS4a */
  209. if(!protocol4a) {
  210. enum resolve_t rc =
  211. Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
  212. if(rc == CURLRESOLV_ERROR)
  213. return CURLE_COULDNT_RESOLVE_PROXY;
  214. else if(rc == CURLRESOLV_PENDING) {
  215. sxstate(conn, CONNECT_RESOLVING);
  216. infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
  217. return CURLE_OK;
  218. }
  219. sxstate(conn, CONNECT_RESOLVED);
  220. goto CONNECT_RESOLVED;
  221. }
  222. /* socks4a doesn't resolve anything locally */
  223. sxstate(conn, CONNECT_REQ_INIT);
  224. goto CONNECT_REQ_INIT;
  225. case CONNECT_RESOLVING:
  226. /* check if we have the name resolved by now */
  227. dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
  228. if(dns) {
  229. #ifdef CURLRES_ASYNCH
  230. conn->async.dns = dns;
  231. conn->async.done = TRUE;
  232. #endif
  233. infof(data, "Hostname '%s' was found\n", hostname);
  234. sxstate(conn, CONNECT_RESOLVED);
  235. }
  236. else {
  237. result = Curl_resolv_check(data->conn, &dns);
  238. /* stay in the state or error out */
  239. return result;
  240. }
  241. /* FALLTHROUGH */
  242. CONNECT_RESOLVED:
  243. case CONNECT_RESOLVED: {
  244. Curl_addrinfo *hp = NULL;
  245. char buf[64];
  246. /*
  247. * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
  248. * returns a Curl_addrinfo pointer that may not always look the same.
  249. */
  250. if(dns)
  251. hp = dns->addr;
  252. if(hp) {
  253. Curl_printable_address(hp, buf, sizeof(buf));
  254. if(hp->ai_family == AF_INET) {
  255. struct sockaddr_in *saddr_in;
  256. saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
  257. socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
  258. socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
  259. socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
  260. socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
  261. infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
  262. }
  263. else {
  264. hp = NULL; /* fail! */
  265. failf(data, "SOCKS4 connection to %s not supported\n", buf);
  266. }
  267. Curl_resolv_unlock(data, dns); /* not used anymore from now on */
  268. }
  269. if(!hp) {
  270. failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
  271. hostname);
  272. return CURLE_COULDNT_RESOLVE_HOST;
  273. }
  274. }
  275. /* FALLTHROUGH */
  276. CONNECT_REQ_INIT:
  277. case CONNECT_REQ_INIT:
  278. /*
  279. * This is currently not supporting "Identification Protocol (RFC1413)".
  280. */
  281. socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
  282. if(proxy_user) {
  283. size_t plen = strlen(proxy_user);
  284. if(plen >= sizeof(sx->socksreq) - 8) {
  285. failf(data, "Too long SOCKS proxy name, can't use!\n");
  286. return CURLE_COULDNT_CONNECT;
  287. }
  288. /* copy the proxy name WITH trailing zero */
  289. memcpy(socksreq + 8, proxy_user, plen + 1);
  290. }
  291. /*
  292. * Make connection
  293. */
  294. {
  295. ssize_t packetsize = 9 +
  296. strlen((char *)socksreq + 8); /* size including NUL */
  297. /* If SOCKS4a, set special invalid IP address 0.0.0.x */
  298. if(protocol4a) {
  299. ssize_t hostnamelen = 0;
  300. socksreq[4] = 0;
  301. socksreq[5] = 0;
  302. socksreq[6] = 0;
  303. socksreq[7] = 1;
  304. /* append hostname */
  305. hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
  306. if(hostnamelen <= 255)
  307. strcpy((char *)socksreq + packetsize, hostname);
  308. else {
  309. failf(data, "SOCKS4: too long host name");
  310. return CURLE_COULDNT_CONNECT;
  311. }
  312. packetsize += hostnamelen;
  313. }
  314. sx->outp = socksreq;
  315. sx->outstanding = packetsize;
  316. sxstate(conn, CONNECT_REQ_SENDING);
  317. }
  318. /* FALLTHROUGH */
  319. case CONNECT_REQ_SENDING:
  320. /* Send request */
  321. result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
  322. sx->outstanding, &written);
  323. if(result && (CURLE_AGAIN != result)) {
  324. failf(data, "Failed to send SOCKS4 connect request.");
  325. return CURLE_COULDNT_CONNECT;
  326. }
  327. if(written != sx->outstanding) {
  328. /* not done, remain in state */
  329. sx->outstanding -= written;
  330. sx->outp += written;
  331. return CURLE_OK;
  332. }
  333. /* done sending! */
  334. sx->outstanding = 8; /* receive data size */
  335. sx->outp = socksreq;
  336. sxstate(conn, CONNECT_SOCKS_READ);
  337. /* FALLTHROUGH */
  338. case CONNECT_SOCKS_READ:
  339. /* Receive response */
  340. result = Curl_read_plain(sockfd, (char *)sx->outp,
  341. sx->outstanding, &actualread);
  342. if(result && (CURLE_AGAIN != result)) {
  343. failf(data, "SOCKS4: Failed receiving connect request ack: %s",
  344. curl_easy_strerror(result));
  345. return CURLE_COULDNT_CONNECT;
  346. }
  347. else if(actualread != sx->outstanding) {
  348. /* remain in reading state */
  349. sx->outstanding -= actualread;
  350. sx->outp += actualread;
  351. return CURLE_OK;
  352. }
  353. sxstate(conn, CONNECT_DONE);
  354. break;
  355. default: /* lots of unused states in SOCKS4 */
  356. break;
  357. }
  358. /*
  359. * Response format
  360. *
  361. * +----+----+----+----+----+----+----+----+
  362. * | VN | CD | DSTPORT | DSTIP |
  363. * +----+----+----+----+----+----+----+----+
  364. * # of bytes: 1 1 2 4
  365. *
  366. * VN is the version of the reply code and should be 0. CD is the result
  367. * code with one of the following values:
  368. *
  369. * 90: request granted
  370. * 91: request rejected or failed
  371. * 92: request rejected because SOCKS server cannot connect to
  372. * identd on the client
  373. * 93: request rejected because the client program and identd
  374. * report different user-ids
  375. */
  376. /* wrong version ? */
  377. if(socksreq[0] != 0) {
  378. failf(data,
  379. "SOCKS4 reply has wrong version, version should be 0.");
  380. return CURLE_COULDNT_CONNECT;
  381. }
  382. /* Result */
  383. switch(socksreq[1]) {
  384. case 90:
  385. infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
  386. break;
  387. case 91:
  388. failf(data,
  389. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  390. ", request rejected or failed.",
  391. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  392. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  393. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  394. (unsigned char)socksreq[1]);
  395. return CURLE_COULDNT_CONNECT;
  396. case 92:
  397. failf(data,
  398. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  399. ", request rejected because SOCKS server cannot connect to "
  400. "identd on the client.",
  401. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  402. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  403. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  404. (unsigned char)socksreq[1]);
  405. return CURLE_COULDNT_CONNECT;
  406. case 93:
  407. failf(data,
  408. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  409. ", request rejected because the client program and identd "
  410. "report different user-ids.",
  411. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  412. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  413. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  414. (unsigned char)socksreq[1]);
  415. return CURLE_COULDNT_CONNECT;
  416. default:
  417. failf(data,
  418. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  419. ", Unknown.",
  420. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  421. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  422. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  423. (unsigned char)socksreq[1]);
  424. return CURLE_COULDNT_CONNECT;
  425. }
  426. *done = TRUE;
  427. return CURLE_OK; /* Proxy was successful! */
  428. }
  429. /*
  430. * This function logs in to a SOCKS5 proxy and sends the specifics to the final
  431. * destination server.
  432. */
  433. CURLcode Curl_SOCKS5(const char *proxy_user,
  434. const char *proxy_password,
  435. const char *hostname,
  436. int remote_port,
  437. int sockindex,
  438. struct connectdata *conn,
  439. bool *done)
  440. {
  441. /*
  442. According to the RFC1928, section "6. Replies". This is what a SOCK5
  443. replies:
  444. +----+-----+-------+------+----------+----------+
  445. |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  446. +----+-----+-------+------+----------+----------+
  447. | 1 | 1 | X'00' | 1 | Variable | 2 |
  448. +----+-----+-------+------+----------+----------+
  449. Where:
  450. o VER protocol version: X'05'
  451. o REP Reply field:
  452. o X'00' succeeded
  453. */
  454. unsigned char *socksreq = &conn->cnnct.socksreq[0];
  455. char dest[256] = "unknown"; /* printable hostname:port */
  456. int idx;
  457. ssize_t actualread;
  458. ssize_t written;
  459. CURLcode result;
  460. curl_socket_t sockfd = conn->sock[sockindex];
  461. struct Curl_easy *data = conn->data;
  462. bool socks5_resolve_local =
  463. (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
  464. const size_t hostname_len = strlen(hostname);
  465. ssize_t len = 0;
  466. const unsigned long auth = data->set.socks5auth;
  467. bool allow_gssapi = FALSE;
  468. struct connstate *sx = &conn->cnnct;
  469. struct Curl_dns_entry *dns = NULL;
  470. if(!SOCKS_STATE(sx->state) && !*done)
  471. sxstate(conn, CONNECT_SOCKS_INIT);
  472. switch(sx->state) {
  473. case CONNECT_SOCKS_INIT:
  474. if(conn->bits.httpproxy)
  475. infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
  476. hostname, remote_port);
  477. /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
  478. if(!socks5_resolve_local && hostname_len > 255) {
  479. infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
  480. "length > 255 [actual len=%zu]\n", hostname_len);
  481. socks5_resolve_local = TRUE;
  482. }
  483. if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
  484. infof(conn->data,
  485. "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
  486. auth);
  487. if(!(auth & CURLAUTH_BASIC))
  488. /* disable username/password auth */
  489. proxy_user = NULL;
  490. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  491. if(auth & CURLAUTH_GSSAPI)
  492. allow_gssapi = TRUE;
  493. #endif
  494. idx = 0;
  495. socksreq[idx++] = 5; /* version */
  496. idx++; /* number of authentication methods */
  497. socksreq[idx++] = 0; /* no authentication */
  498. if(allow_gssapi)
  499. socksreq[idx++] = 1; /* GSS-API */
  500. if(proxy_user)
  501. socksreq[idx++] = 2; /* username/password */
  502. /* write the number of authentication methods */
  503. socksreq[1] = (unsigned char) (idx - 2);
  504. result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written);
  505. if(result && (CURLE_AGAIN != result)) {
  506. failf(data, "Unable to send initial SOCKS5 request.");
  507. return CURLE_COULDNT_CONNECT;
  508. }
  509. if(written != idx) {
  510. sxstate(conn, CONNECT_SOCKS_SEND);
  511. sx->outstanding = idx - written;
  512. sx->outp = &socksreq[written];
  513. return CURLE_OK;
  514. }
  515. sxstate(conn, CONNECT_SOCKS_READ);
  516. goto CONNECT_SOCKS_READ_INIT;
  517. case CONNECT_SOCKS_SEND:
  518. result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
  519. sx->outstanding, &written);
  520. if(result && (CURLE_AGAIN != result)) {
  521. failf(data, "Unable to send initial SOCKS5 request.");
  522. return CURLE_COULDNT_CONNECT;
  523. }
  524. if(written != sx->outstanding) {
  525. /* not done, remain in state */
  526. sx->outstanding -= written;
  527. sx->outp += written;
  528. return CURLE_OK;
  529. }
  530. /* FALLTHROUGH */
  531. CONNECT_SOCKS_READ_INIT:
  532. case CONNECT_SOCKS_READ_INIT:
  533. sx->outstanding = 2; /* expect two bytes */
  534. sx->outp = socksreq; /* store it here */
  535. /* FALLTHROUGH */
  536. case CONNECT_SOCKS_READ:
  537. result = Curl_read_plain(sockfd, (char *)sx->outp,
  538. sx->outstanding, &actualread);
  539. if(result && (CURLE_AGAIN != result)) {
  540. failf(data, "Unable to receive initial SOCKS5 response.");
  541. return CURLE_COULDNT_CONNECT;
  542. }
  543. else if(actualread != sx->outstanding) {
  544. /* remain in reading state */
  545. sx->outstanding -= actualread;
  546. sx->outp += actualread;
  547. return CURLE_OK;
  548. }
  549. else if(socksreq[0] != 5) {
  550. failf(data, "Received invalid version in initial SOCKS5 response.");
  551. return CURLE_COULDNT_CONNECT;
  552. }
  553. else if(socksreq[1] == 0) {
  554. /* DONE! No authentication needed. Send request. */
  555. sxstate(conn, CONNECT_REQ_INIT);
  556. goto CONNECT_REQ_INIT;
  557. }
  558. else if(socksreq[1] == 2) {
  559. /* regular name + password authentication */
  560. sxstate(conn, CONNECT_AUTH_INIT);
  561. goto CONNECT_AUTH_INIT;
  562. }
  563. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  564. else if(allow_gssapi && (socksreq[1] == 1)) {
  565. sxstate(conn, CONNECT_GSSAPI_INIT);
  566. result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
  567. if(result) {
  568. failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
  569. return CURLE_COULDNT_CONNECT;
  570. }
  571. }
  572. #endif
  573. else {
  574. /* error */
  575. if(!allow_gssapi && (socksreq[1] == 1)) {
  576. failf(data,
  577. "SOCKS5 GSSAPI per-message authentication is not supported.");
  578. return CURLE_COULDNT_CONNECT;
  579. }
  580. else if(socksreq[1] == 255) {
  581. failf(data, "No authentication method was acceptable.");
  582. return CURLE_COULDNT_CONNECT;
  583. }
  584. failf(data,
  585. "Undocumented SOCKS5 mode attempted to be used by server.");
  586. return CURLE_COULDNT_CONNECT;
  587. }
  588. break;
  589. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  590. case CONNECT_GSSAPI_INIT:
  591. /* GSSAPI stuff done non-blocking */
  592. break;
  593. #endif
  594. default: /* do nothing! */
  595. break;
  596. CONNECT_AUTH_INIT:
  597. case CONNECT_AUTH_INIT: {
  598. /* Needs user name and password */
  599. size_t proxy_user_len, proxy_password_len;
  600. if(proxy_user && proxy_password) {
  601. proxy_user_len = strlen(proxy_user);
  602. proxy_password_len = strlen(proxy_password);
  603. }
  604. else {
  605. proxy_user_len = 0;
  606. proxy_password_len = 0;
  607. }
  608. /* username/password request looks like
  609. * +----+------+----------+------+----------+
  610. * |VER | ULEN | UNAME | PLEN | PASSWD |
  611. * +----+------+----------+------+----------+
  612. * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
  613. * +----+------+----------+------+----------+
  614. */
  615. len = 0;
  616. socksreq[len++] = 1; /* username/pw subnegotiation version */
  617. socksreq[len++] = (unsigned char) proxy_user_len;
  618. if(proxy_user && proxy_user_len) {
  619. /* the length must fit in a single byte */
  620. if(proxy_user_len >= 255) {
  621. failf(data, "Excessive user name length for proxy auth");
  622. return CURLE_BAD_FUNCTION_ARGUMENT;
  623. }
  624. memcpy(socksreq + len, proxy_user, proxy_user_len);
  625. }
  626. len += proxy_user_len;
  627. socksreq[len++] = (unsigned char) proxy_password_len;
  628. if(proxy_password && proxy_password_len) {
  629. /* the length must fit in a single byte */
  630. if(proxy_password_len > 255) {
  631. failf(data, "Excessive password length for proxy auth");
  632. return CURLE_BAD_FUNCTION_ARGUMENT;
  633. }
  634. memcpy(socksreq + len, proxy_password, proxy_password_len);
  635. }
  636. len += proxy_password_len;
  637. sxstate(conn, CONNECT_AUTH_SEND);
  638. sx->outstanding = len;
  639. sx->outp = socksreq;
  640. }
  641. /* FALLTHROUGH */
  642. case CONNECT_AUTH_SEND:
  643. result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
  644. sx->outstanding, &written);
  645. if(result && (CURLE_AGAIN != result)) {
  646. failf(data, "Failed to send SOCKS5 sub-negotiation request.");
  647. return CURLE_COULDNT_CONNECT;
  648. }
  649. if(sx->outstanding != written) {
  650. /* remain in state */
  651. sx->outstanding -= written;
  652. sx->outp += written;
  653. return CURLE_OK;
  654. }
  655. sx->outp = socksreq;
  656. sx->outstanding = 2;
  657. sxstate(conn, CONNECT_AUTH_READ);
  658. /* FALLTHROUGH */
  659. case CONNECT_AUTH_READ:
  660. result = Curl_read_plain(sockfd, (char *)sx->outp,
  661. sx->outstanding, &actualread);
  662. if(result && (CURLE_AGAIN != result)) {
  663. failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
  664. return CURLE_COULDNT_CONNECT;
  665. }
  666. if(actualread != sx->outstanding) {
  667. /* remain in state */
  668. sx->outstanding -= actualread;
  669. sx->outp += actualread;
  670. return CURLE_OK;
  671. }
  672. /* ignore the first (VER) byte */
  673. if(socksreq[1] != 0) { /* status */
  674. failf(data, "User was rejected by the SOCKS5 server (%d %d).",
  675. socksreq[0], socksreq[1]);
  676. return CURLE_COULDNT_CONNECT;
  677. }
  678. /* Everything is good so far, user was authenticated! */
  679. sxstate(conn, CONNECT_REQ_INIT);
  680. /* FALLTHROUGH */
  681. CONNECT_REQ_INIT:
  682. case CONNECT_REQ_INIT:
  683. if(socks5_resolve_local) {
  684. enum resolve_t rc = Curl_resolv(conn, hostname, remote_port,
  685. FALSE, &dns);
  686. if(rc == CURLRESOLV_ERROR)
  687. return CURLE_COULDNT_RESOLVE_HOST;
  688. if(rc == CURLRESOLV_PENDING) {
  689. sxstate(conn, CONNECT_RESOLVING);
  690. return CURLE_OK;
  691. }
  692. sxstate(conn, CONNECT_RESOLVED);
  693. goto CONNECT_RESOLVED;
  694. }
  695. goto CONNECT_RESOLVE_REMOTE;
  696. case CONNECT_RESOLVING:
  697. /* check if we have the name resolved by now */
  698. dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
  699. if(dns) {
  700. #ifdef CURLRES_ASYNCH
  701. conn->async.dns = dns;
  702. conn->async.done = TRUE;
  703. #endif
  704. infof(data, "SOCKS5: hostname '%s' found\n", hostname);
  705. }
  706. if(!dns) {
  707. result = Curl_resolv_check(data->conn, &dns);
  708. /* stay in the state or error out */
  709. return result;
  710. }
  711. /* FALLTHROUGH */
  712. CONNECT_RESOLVED:
  713. case CONNECT_RESOLVED: {
  714. Curl_addrinfo *hp = NULL;
  715. if(dns)
  716. hp = dns->addr;
  717. if(!hp) {
  718. failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
  719. hostname);
  720. return CURLE_COULDNT_RESOLVE_HOST;
  721. }
  722. if(Curl_printable_address(hp, dest, sizeof(dest))) {
  723. size_t destlen = strlen(dest);
  724. msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port);
  725. }
  726. else {
  727. strcpy(dest, "unknown");
  728. }
  729. len = 0;
  730. socksreq[len++] = 5; /* version (SOCKS5) */
  731. socksreq[len++] = 1; /* connect */
  732. socksreq[len++] = 0; /* must be zero */
  733. if(hp->ai_family == AF_INET) {
  734. int i;
  735. struct sockaddr_in *saddr_in;
  736. socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
  737. saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
  738. for(i = 0; i < 4; i++) {
  739. socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
  740. }
  741. infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest);
  742. }
  743. #ifdef ENABLE_IPV6
  744. else if(hp->ai_family == AF_INET6) {
  745. int i;
  746. struct sockaddr_in6 *saddr_in6;
  747. socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
  748. saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
  749. for(i = 0; i < 16; i++) {
  750. socksreq[len++] =
  751. ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
  752. }
  753. infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest);
  754. }
  755. #endif
  756. else {
  757. hp = NULL; /* fail! */
  758. failf(data, "SOCKS5 connection to %s not supported\n", dest);
  759. }
  760. Curl_resolv_unlock(data, dns); /* not used anymore from now on */
  761. goto CONNECT_REQ_SEND;
  762. }
  763. CONNECT_RESOLVE_REMOTE:
  764. case CONNECT_RESOLVE_REMOTE:
  765. /* Authentication is complete, now specify destination to the proxy */
  766. len = 0;
  767. socksreq[len++] = 5; /* version (SOCKS5) */
  768. socksreq[len++] = 1; /* connect */
  769. socksreq[len++] = 0; /* must be zero */
  770. if(!socks5_resolve_local) {
  771. socksreq[len++] = 3; /* ATYP: domain name = 3 */
  772. socksreq[len++] = (char) hostname_len; /* one byte address length */
  773. memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
  774. len += hostname_len;
  775. infof(data, "SOCKS5 connect to %s:%d (remotely resolved)\n",
  776. hostname, remote_port);
  777. }
  778. /* FALLTHROUGH */
  779. CONNECT_REQ_SEND:
  780. case CONNECT_REQ_SEND:
  781. /* PORT MSB */
  782. socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff);
  783. /* PORT LSB */
  784. socksreq[len++] = (unsigned char)(remote_port & 0xff);
  785. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  786. if(conn->socks5_gssapi_enctype) {
  787. failf(data, "SOCKS5 GSS-API protection not yet implemented.");
  788. return CURLE_COULDNT_CONNECT;
  789. }
  790. #endif
  791. sx->outp = socksreq;
  792. sx->outstanding = len;
  793. sxstate(conn, CONNECT_REQ_SENDING);
  794. /* FALLTHROUGH */
  795. case CONNECT_REQ_SENDING:
  796. result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
  797. sx->outstanding, &written);
  798. if(result && (CURLE_AGAIN != result)) {
  799. failf(data, "Failed to send SOCKS5 connect request.");
  800. return CURLE_COULDNT_CONNECT;
  801. }
  802. if(sx->outstanding != written) {
  803. /* remain in state */
  804. sx->outstanding -= written;
  805. sx->outp += written;
  806. return CURLE_OK;
  807. }
  808. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  809. if(conn->socks5_gssapi_enctype) {
  810. failf(data, "SOCKS5 GSS-API protection not yet implemented.");
  811. return CURLE_COULDNT_CONNECT;
  812. }
  813. #endif
  814. sx->outstanding = 10; /* minimum packet size is 10 */
  815. sx->outp = socksreq;
  816. sxstate(conn, CONNECT_REQ_READ);
  817. /* FALLTHROUGH */
  818. case CONNECT_REQ_READ:
  819. result = Curl_read_plain(sockfd, (char *)sx->outp,
  820. sx->outstanding, &actualread);
  821. if(result && (CURLE_AGAIN != result)) {
  822. failf(data, "Failed to receive SOCKS5 connect request ack.");
  823. return CURLE_COULDNT_CONNECT;
  824. }
  825. else if(actualread != sx->outstanding) {
  826. /* remain in state */
  827. sx->outstanding -= actualread;
  828. sx->outp += actualread;
  829. return CURLE_OK;
  830. }
  831. if(socksreq[0] != 5) { /* version */
  832. failf(data,
  833. "SOCKS5 reply has wrong version, version should be 5.");
  834. return CURLE_COULDNT_CONNECT;
  835. }
  836. else if(socksreq[1] != 0) { /* Anything besides 0 is an error */
  837. failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
  838. hostname, (unsigned char)socksreq[1]);
  839. return CURLE_COULDNT_CONNECT;
  840. }
  841. /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
  842. 1928, so the reply packet should be read until the end to avoid errors
  843. at subsequent protocol level.
  844. +----+-----+-------+------+----------+----------+
  845. |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  846. +----+-----+-------+------+----------+----------+
  847. | 1 | 1 | X'00' | 1 | Variable | 2 |
  848. +----+-----+-------+------+----------+----------+
  849. ATYP:
  850. o IP v4 address: X'01', BND.ADDR = 4 byte
  851. o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
  852. o IP v6 address: X'04', BND.ADDR = 16 byte
  853. */
  854. /* Calculate real packet size */
  855. if(socksreq[3] == 3) {
  856. /* domain name */
  857. int addrlen = (int) socksreq[4];
  858. len = 5 + addrlen + 2;
  859. }
  860. else if(socksreq[3] == 4) {
  861. /* IPv6 */
  862. len = 4 + 16 + 2;
  863. }
  864. /* At this point we already read first 10 bytes */
  865. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  866. if(!conn->socks5_gssapi_enctype) {
  867. /* decrypt_gssapi_blockread already read the whole packet */
  868. #endif
  869. if(len > 10) {
  870. sx->outstanding = len - 10; /* get the rest */
  871. sx->outp = &socksreq[10];
  872. sxstate(conn, CONNECT_REQ_READ_MORE);
  873. }
  874. else {
  875. sxstate(conn, CONNECT_DONE);
  876. break;
  877. }
  878. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  879. }
  880. #endif
  881. /* FALLTHROUGH */
  882. case CONNECT_REQ_READ_MORE:
  883. result = Curl_read_plain(sockfd, (char *)sx->outp,
  884. sx->outstanding, &actualread);
  885. if(result && (CURLE_AGAIN != result)) {
  886. failf(data, "Failed to receive SOCKS5 connect request ack.");
  887. return CURLE_COULDNT_CONNECT;
  888. }
  889. if(actualread != sx->outstanding) {
  890. /* remain in state */
  891. sx->outstanding -= actualread;
  892. sx->outp += actualread;
  893. return CURLE_OK;
  894. }
  895. sxstate(conn, CONNECT_DONE);
  896. }
  897. infof(data, "SOCKS5 request granted.\n");
  898. *done = TRUE;
  899. return CURLE_OK; /* Proxy was successful! */
  900. }
  901. #endif /* CURL_DISABLE_PROXY */