socks.c 32 KB

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