socks.c 32 KB

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