socks.c 32 KB

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