socks.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #if !defined(CURL_DISABLE_PROXY)
  24. #ifdef HAVE_NETINET_IN_H
  25. #include <netinet/in.h>
  26. #endif
  27. #ifdef HAVE_ARPA_INET_H
  28. #include <arpa/inet.h>
  29. #endif
  30. #include "urldata.h"
  31. #include "sendf.h"
  32. #include "select.h"
  33. #include "connect.h"
  34. #include "timeval.h"
  35. #include "socks.h"
  36. #include "multiif.h" /* for getsock macros */
  37. /* The last 3 #include files should be in this order */
  38. #include "curl_printf.h"
  39. #include "curl_memory.h"
  40. #include "memdebug.h"
  41. #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  42. /*
  43. * Helper read-from-socket functions. Does the same as Curl_read() but it
  44. * blocks until all bytes amount of buffersize will be read. No more, no less.
  45. *
  46. * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
  47. */
  48. int Curl_blockread_all(struct connectdata *conn, /* connection data */
  49. curl_socket_t sockfd, /* read from this socket */
  50. char *buf, /* store read data here */
  51. ssize_t buffersize, /* max amount to read */
  52. ssize_t *n) /* amount bytes read */
  53. {
  54. ssize_t nread = 0;
  55. ssize_t allread = 0;
  56. int result;
  57. *n = 0;
  58. for(;;) {
  59. timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE);
  60. if(timeout_ms < 0) {
  61. /* we already got the timeout */
  62. result = CURLE_OPERATION_TIMEDOUT;
  63. break;
  64. }
  65. if(!timeout_ms)
  66. timeout_ms = 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 connectdata *conn,
  100. enum connect_t state
  101. #ifdef DEBUGBUILD
  102. , int lineno
  103. #endif
  104. )
  105. {
  106. enum connect_t oldstate = conn->cnnct.state;
  107. #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  108. /* synced with the state list in urldata.h */
  109. static const char * const statename[] = {
  110. "INIT",
  111. "SOCKS_INIT",
  112. "SOCKS_SEND",
  113. "SOCKS_READ_INIT",
  114. "SOCKS_READ",
  115. "GSSAPI_INIT",
  116. "AUTH_INIT",
  117. "AUTH_SEND",
  118. "AUTH_READ",
  119. "REQ_INIT",
  120. "RESOLVING",
  121. "RESOLVED",
  122. "RESOLVE_REMOTE",
  123. "REQ_SEND",
  124. "REQ_SENDING",
  125. "REQ_READ",
  126. "REQ_READ_MORE",
  127. "DONE"
  128. };
  129. #endif
  130. if(oldstate == state)
  131. /* don't bother when the new state is the same as the old state */
  132. return;
  133. conn->cnnct.state = state;
  134. #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  135. infof(conn->data,
  136. "SXSTATE: %s => %s conn %p; line %d\n",
  137. statename[oldstate], statename[conn->cnnct.state], conn,
  138. lineno);
  139. #endif
  140. }
  141. int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
  142. int sockindex)
  143. {
  144. int rc = 0;
  145. sock[0] = conn->sock[sockindex];
  146. switch(conn->cnnct.state) {
  147. case CONNECT_RESOLVING:
  148. case CONNECT_SOCKS_READ:
  149. case CONNECT_AUTH_READ:
  150. case CONNECT_REQ_READ:
  151. case CONNECT_REQ_READ_MORE:
  152. rc = GETSOCK_READSOCK(0);
  153. break;
  154. default:
  155. rc = GETSOCK_WRITESOCK(0);
  156. break;
  157. }
  158. return rc;
  159. }
  160. /*
  161. * This function logs in to a SOCKS4 proxy and sends the specifics to the final
  162. * destination server.
  163. *
  164. * Reference :
  165. * https://www.openssh.com/txt/socks4.protocol
  166. *
  167. * Note :
  168. * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
  169. * Nonsupport "Identification Protocol (RFC1413)"
  170. */
  171. CURLproxycode Curl_SOCKS4(const char *proxy_user,
  172. const char *hostname,
  173. int remote_port,
  174. int sockindex,
  175. struct connectdata *conn,
  176. bool *done)
  177. {
  178. const bool protocol4a =
  179. (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
  180. unsigned char *socksreq = &conn->cnnct.socksreq[0];
  181. CURLcode result;
  182. curl_socket_t sockfd = conn->sock[sockindex];
  183. struct Curl_easy *data = conn->data;
  184. struct connstate *sx = &conn->cnnct;
  185. struct Curl_dns_entry *dns = NULL;
  186. ssize_t actualread;
  187. ssize_t written;
  188. if(!SOCKS_STATE(sx->state) && !*done)
  189. sxstate(conn, CONNECT_SOCKS_INIT);
  190. switch(sx->state) {
  191. case CONNECT_SOCKS_INIT:
  192. /* SOCKS4 can only do IPv4, insist! */
  193. conn->ip_version = CURL_IPRESOLVE_V4;
  194. if(conn->bits.httpproxy)
  195. infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
  196. protocol4a ? "a" : "", hostname, remote_port);
  197. infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
  198. /*
  199. * Compose socks4 request
  200. *
  201. * Request format
  202. *
  203. * +----+----+----+----+----+----+----+----+----+----+....+----+
  204. * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
  205. * +----+----+----+----+----+----+----+----+----+----+....+----+
  206. * # of bytes: 1 1 2 4 variable 1
  207. */
  208. socksreq[0] = 4; /* version (SOCKS4) */
  209. socksreq[1] = 1; /* connect */
  210. socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
  211. socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
  212. /* DNS resolve only for SOCKS4, not SOCKS4a */
  213. if(!protocol4a) {
  214. enum resolve_t rc =
  215. Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
  216. if(rc == CURLRESOLV_ERROR)
  217. return CURLPX_RESOLVE_HOST;
  218. else if(rc == CURLRESOLV_PENDING) {
  219. sxstate(conn, CONNECT_RESOLVING);
  220. infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
  221. return CURLPX_OK;
  222. }
  223. sxstate(conn, CONNECT_RESOLVED);
  224. goto CONNECT_RESOLVED;
  225. }
  226. /* socks4a doesn't resolve anything locally */
  227. sxstate(conn, CONNECT_REQ_INIT);
  228. goto CONNECT_REQ_INIT;
  229. case CONNECT_RESOLVING:
  230. /* check if we have the name resolved by now */
  231. dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
  232. if(dns) {
  233. #ifdef CURLRES_ASYNCH
  234. conn->async.dns = dns;
  235. conn->async.done = TRUE;
  236. #endif
  237. infof(data, "Hostname '%s' was found\n", hostname);
  238. sxstate(conn, CONNECT_RESOLVED);
  239. }
  240. else {
  241. result = Curl_resolv_check(data->conn, &dns);
  242. if(!dns) {
  243. if(result)
  244. return CURLPX_RESOLVE_HOST;
  245. return CURLPX_OK;
  246. }
  247. }
  248. /* FALLTHROUGH */
  249. CONNECT_RESOLVED:
  250. case CONNECT_RESOLVED: {
  251. struct Curl_addrinfo *hp = NULL;
  252. char buf[64];
  253. /*
  254. * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
  255. * returns a Curl_addrinfo pointer that may not always look the same.
  256. */
  257. if(dns)
  258. hp = dns->addr;
  259. if(hp) {
  260. Curl_printable_address(hp, buf, sizeof(buf));
  261. if(hp->ai_family == AF_INET) {
  262. struct sockaddr_in *saddr_in;
  263. saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
  264. socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
  265. socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
  266. socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
  267. socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
  268. infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
  269. }
  270. else {
  271. hp = NULL; /* fail! */
  272. failf(data, "SOCKS4 connection to %s not supported", buf);
  273. }
  274. Curl_resolv_unlock(data, dns); /* not used anymore from now on */
  275. }
  276. if(!hp) {
  277. failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
  278. hostname);
  279. return CURLPX_RESOLVE_HOST;
  280. }
  281. }
  282. /* FALLTHROUGH */
  283. CONNECT_REQ_INIT:
  284. case CONNECT_REQ_INIT:
  285. /*
  286. * This is currently not supporting "Identification Protocol (RFC1413)".
  287. */
  288. socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
  289. if(proxy_user) {
  290. size_t plen = strlen(proxy_user);
  291. if(plen >= sizeof(sx->socksreq) - 8) {
  292. failf(data, "Too long SOCKS proxy user name, can't use!");
  293. return CURLPX_LONG_USER;
  294. }
  295. /* copy the proxy name WITH trailing zero */
  296. memcpy(socksreq + 8, proxy_user, plen + 1);
  297. }
  298. /*
  299. * Make connection
  300. */
  301. {
  302. size_t packetsize = 9 +
  303. strlen((char *)socksreq + 8); /* size including NUL */
  304. /* If SOCKS4a, set special invalid IP address 0.0.0.x */
  305. if(protocol4a) {
  306. size_t hostnamelen = 0;
  307. socksreq[4] = 0;
  308. socksreq[5] = 0;
  309. socksreq[6] = 0;
  310. socksreq[7] = 1;
  311. /* append hostname */
  312. hostnamelen = strlen(hostname) + 1; /* length including NUL */
  313. if(hostnamelen <= 255)
  314. strcpy((char *)socksreq + packetsize, hostname);
  315. else {
  316. failf(data, "SOCKS4: too long host name");
  317. return CURLPX_LONG_HOSTNAME;
  318. }
  319. packetsize += hostnamelen;
  320. }
  321. sx->outp = socksreq;
  322. sx->outstanding = packetsize;
  323. sxstate(conn, CONNECT_REQ_SENDING);
  324. }
  325. /* FALLTHROUGH */
  326. case CONNECT_REQ_SENDING:
  327. /* Send request */
  328. result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
  329. sx->outstanding, &written);
  330. if(result && (CURLE_AGAIN != result)) {
  331. failf(data, "Failed to send SOCKS4 connect request.");
  332. return CURLPX_SEND_CONNECT;
  333. }
  334. if(written != sx->outstanding) {
  335. /* not done, remain in state */
  336. sx->outstanding -= written;
  337. sx->outp += written;
  338. return CURLPX_OK;
  339. }
  340. /* done sending! */
  341. sx->outstanding = 8; /* receive data size */
  342. sx->outp = socksreq;
  343. sxstate(conn, CONNECT_SOCKS_READ);
  344. /* FALLTHROUGH */
  345. case CONNECT_SOCKS_READ:
  346. /* Receive response */
  347. result = Curl_read_plain(sockfd, (char *)sx->outp,
  348. sx->outstanding, &actualread);
  349. if(result && (CURLE_AGAIN != result)) {
  350. failf(data, "SOCKS4: Failed receiving connect request ack: %s",
  351. curl_easy_strerror(result));
  352. return CURLPX_RECV_CONNECT;
  353. }
  354. else if(!result && !actualread) {
  355. /* connection closed */
  356. failf(data, "connection to proxy closed");
  357. return CURLPX_CLOSED;
  358. }
  359. else if(actualread != sx->outstanding) {
  360. /* remain in reading state */
  361. sx->outstanding -= actualread;
  362. sx->outp += actualread;
  363. return CURLPX_OK;
  364. }
  365. sxstate(conn, CONNECT_DONE);
  366. break;
  367. default: /* lots of unused states in SOCKS4 */
  368. break;
  369. }
  370. /*
  371. * Response format
  372. *
  373. * +----+----+----+----+----+----+----+----+
  374. * | VN | CD | DSTPORT | DSTIP |
  375. * +----+----+----+----+----+----+----+----+
  376. * # of bytes: 1 1 2 4
  377. *
  378. * VN is the version of the reply code and should be 0. CD is the result
  379. * code with one of the following values:
  380. *
  381. * 90: request granted
  382. * 91: request rejected or failed
  383. * 92: request rejected because SOCKS server cannot connect to
  384. * identd on the client
  385. * 93: request rejected because the client program and identd
  386. * report different user-ids
  387. */
  388. /* wrong version ? */
  389. if(socksreq[0] != 0) {
  390. failf(data,
  391. "SOCKS4 reply has wrong version, version should be 0.");
  392. return CURLPX_BAD_VERSION;
  393. }
  394. /* Result */
  395. switch(socksreq[1]) {
  396. case 90:
  397. infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
  398. break;
  399. case 91:
  400. failf(data,
  401. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  402. ", request rejected or failed.",
  403. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  404. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  405. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  406. (unsigned char)socksreq[1]);
  407. return CURLPX_REQUEST_FAILED;
  408. case 92:
  409. failf(data,
  410. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  411. ", request rejected because SOCKS server cannot connect to "
  412. "identd on the client.",
  413. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  414. (unsigned char)socksreq[6], (unsigned char)socksreq[7],
  415. (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
  416. (unsigned char)socksreq[1]);
  417. return CURLPX_IDENTD;
  418. case 93:
  419. failf(data,
  420. "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
  421. ", request rejected because the client program and identd "
  422. "report different user-ids.",
  423. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  424. (unsigned char)socksreq[6], (unsigned char)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. (unsigned char)socksreq[4], (unsigned char)socksreq[5],
  433. (unsigned char)socksreq[6], (unsigned char)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 connectdata *conn,
  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. unsigned char *socksreq = &conn->cnnct.socksreq[0];
  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. struct Curl_easy *data = conn->data;
  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(conn, CONNECT_SOCKS_INIT);
  484. switch(sx->state) {
  485. case CONNECT_SOCKS_INIT:
  486. if(conn->bits.httpproxy)
  487. infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
  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(conn->data, "SOCKS5: server resolving disabled for hostnames of "
  492. "length > 255 [actual len=%zu]\n", hostname_len);
  493. socks5_resolve_local = TRUE;
  494. }
  495. if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
  496. infof(conn->data,
  497. "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
  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(conn, 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(conn, CONNECT_SOCKS_SEND);
  523. sx->outstanding = idx - written;
  524. sx->outp = &socksreq[written];
  525. return CURLPX_OK;
  526. }
  527. sxstate(conn, CONNECT_SOCKS_READ);
  528. goto CONNECT_SOCKS_READ_INIT;
  529. case CONNECT_SOCKS_SEND:
  530. result = Curl_write_plain(conn, 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(conn, CONNECT_REQ_INIT);
  573. goto CONNECT_REQ_INIT;
  574. }
  575. else if(socksreq[1] == 2) {
  576. /* regular name + password authentication */
  577. sxstate(conn, 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(conn, CONNECT_GSSAPI_INIT);
  583. result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
  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(conn, CONNECT_AUTH_SEND);
  654. sx->outstanding = len;
  655. sx->outp = socksreq;
  656. }
  657. /* FALLTHROUGH */
  658. case CONNECT_AUTH_SEND:
  659. result = Curl_write_plain(conn, 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(conn, 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] != 0) { /* 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(conn, 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(conn, hostname, remote_port,
  706. FALSE, &dns);
  707. if(rc == CURLRESOLV_ERROR)
  708. return CURLPX_RESOLVE_HOST;
  709. if(rc == CURLRESOLV_PENDING) {
  710. sxstate(conn, CONNECT_RESOLVING);
  711. return CURLPX_OK;
  712. }
  713. sxstate(conn, 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(conn, hostname, remote_port);
  720. if(dns) {
  721. #ifdef CURLRES_ASYNCH
  722. conn->async.dns = dns;
  723. conn->async.done = TRUE;
  724. #endif
  725. infof(data, "SOCKS5: hostname '%s' found\n", hostname);
  726. }
  727. if(!dns) {
  728. result = Curl_resolv_check(data->conn, &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)\n", 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)\n", 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)\n",
  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(conn, CONNECT_REQ_SENDING);
  815. /* FALLTHROUGH */
  816. case CONNECT_REQ_SENDING:
  817. result = Curl_write_plain(conn, 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(conn, 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] != 0) { /* 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(conn, CONNECT_REQ_READ_MORE);
  923. }
  924. else {
  925. sxstate(conn, 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(conn, CONNECT_DONE);
  951. }
  952. infof(data, "SOCKS5 request granted.\n");
  953. *done = TRUE;
  954. return CURLPX_OK; /* Proxy was successful! */
  955. }
  956. #endif /* CURL_DISABLE_PROXY */