socks.c 32 KB

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