socks.c 30 KB

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