llproxy.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /**
  2. * @file llsocks5.cpp
  3. * @brief Socks 5 implementation
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewergpl$
  6. *
  7. * Copyright (c) 2000-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llproxy.h"
  34. #include "llapr.h"
  35. #include "llcorehttpcommon.h"
  36. #include "llhost.h"
  37. #include "lltimer.h" // For ms_sleep()
  38. // Static class variable instances
  39. // We want this to be static to avoid excessive indirection on every incoming
  40. // packet just to do a simple bool test. The getter for this member is also
  41. // static.
  42. bool LLProxy::sUDPProxyEnabled = false;
  43. // Some helpful TCP static functions.
  44. // Do a TCP data handshake
  45. static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle,
  46. char* dataout, apr_size_t outlen,
  47. char* datain, apr_size_t maxinlen);
  48. // Open a TCP channel to a given host
  49. static LLSocket::ptr_t tcp_open_channel(LLHost host);
  50. // Close an open TCP channel
  51. static void tcp_close_channel(LLSocket::ptr_t* handle_ptr);
  52. LLProxy::LLProxy()
  53. : mHTTPProxyEnabled(false),
  54. mProxyType(LLPROXY_SOCKS),
  55. mAuthMethodSelected(METHOD_NOAUTH)
  56. {
  57. }
  58. LLProxy::~LLProxy()
  59. {
  60. if (gAPRInitialized)
  61. {
  62. stopSOCKSProxy();
  63. disableHTTPProxy();
  64. }
  65. }
  66. /**
  67. * @brief Open the SOCKS 5 TCP control channel.
  68. *
  69. * Perform a SOCKS 5 authentication and UDP association with the proxy server.
  70. *
  71. * @param proxy The SOCKS 5 server to connect to.
  72. * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h.
  73. */
  74. S32 LLProxy::proxyHandshake(LLHost proxy)
  75. {
  76. S32 result;
  77. /* SOCKS 5 Auth request */
  78. socks_auth_request_t socks_auth_request;
  79. socks_auth_response_t socks_auth_response;
  80. socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5
  81. socks_auth_request.num_methods = 1; // Sending 1 method.
  82. socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method.
  83. result = tcp_blocking_handshake(mProxyControlChannel,
  84. static_cast<char*>(static_cast<void*>(&socks_auth_request)),
  85. sizeof(socks_auth_request),
  86. static_cast<char*>(static_cast<void*>(&socks_auth_response)),
  87. sizeof(socks_auth_response));
  88. if (result != APR_SUCCESS)
  89. {
  90. llwarns << "SOCKS authentication request failed, error on TCP control channel : "
  91. << result << llendl;
  92. stopSOCKSProxy();
  93. return SOCKS_CONNECT_ERROR;
  94. }
  95. if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
  96. {
  97. llwarns << "SOCKS 5 server refused all our authentication methods."
  98. << llendl;
  99. stopSOCKSProxy();
  100. return SOCKS_NOT_ACCEPTABLE;
  101. }
  102. /* SOCKS 5 USERNAME/PASSWORD authentication */
  103. if (socks_auth_response.method == METHOD_PASSWORD)
  104. {
  105. // The server has requested a username/password combination
  106. std::string socks_username(getSocksUser());
  107. std::string socks_password(getSocksPwd());
  108. U32 request_size = socks_username.size() + socks_password.size() + 3;
  109. char* password_auth = new char[request_size];
  110. password_auth[0] = 0x01;
  111. password_auth[1] = (char)socks_username.size();
  112. memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());
  113. password_auth[socks_username.size() + 2] = (char)socks_password.size();
  114. memcpy(&password_auth[socks_username.size() + 3],
  115. socks_password.c_str(), socks_password.size());
  116. authmethod_password_reply_t password_reply;
  117. result = tcp_blocking_handshake(mProxyControlChannel,
  118. password_auth,
  119. request_size,
  120. static_cast<char*>(static_cast<void*>(&password_reply)),
  121. sizeof(password_reply));
  122. delete[] password_auth;
  123. if (result != APR_SUCCESS)
  124. {
  125. llwarns << "SOCKS authentication failed, error on TCP control channel : "
  126. << result << llendl;
  127. stopSOCKSProxy();
  128. return SOCKS_CONNECT_ERROR;
  129. }
  130. if (password_reply.status != AUTH_SUCCESS)
  131. {
  132. llwarns << "SOCKS authentication failed" << llendl;
  133. stopSOCKSProxy();
  134. return SOCKS_AUTH_FAIL;
  135. }
  136. }
  137. /* SOCKS5 connect request */
  138. socks_command_request_t connect_request;
  139. socks_command_response_t connect_reply;
  140. connect_request.version = SOCKS_VERSION; // SOCKS V5
  141. connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
  142. connect_request.reserved = FIELD_RESERVED;
  143. connect_request.atype = ADDRESS_IPV4;
  144. connect_request.address = htonl(0); // 0.0.0.0
  145. connect_request.port = htons(0); // 0
  146. // "If the client is not in possession of the information at the time of
  147. // the UDP ASSOCIATE, the client MUST use a port number and address of all
  148. // zeros. RFC 1928"
  149. result = tcp_blocking_handshake(mProxyControlChannel,
  150. static_cast<char*>(static_cast<void*>(&connect_request)),
  151. sizeof(connect_request),
  152. static_cast<char*>(static_cast<void*>(&connect_reply)),
  153. sizeof(connect_reply));
  154. if (result != APR_SUCCESS)
  155. {
  156. llwarns << "SOCKS connect request failed, error on TCP control channel : "
  157. << result << llendl;
  158. stopSOCKSProxy();
  159. return SOCKS_CONNECT_ERROR;
  160. }
  161. if (connect_reply.reply != REPLY_REQUEST_GRANTED)
  162. {
  163. llwarns << "Connection to SOCKS 5 server failed, UDP forward request not granted"
  164. << llendl;
  165. stopSOCKSProxy();
  166. return SOCKS_UDP_FWD_NOT_GRANTED;
  167. }
  168. // reply port is in network byte order
  169. mUDPProxy.setPort(ntohs(connect_reply.port));
  170. mUDPProxy.setAddress(proxy.getAddress());
  171. // The connection was successful. We now have the UDP port to send requests
  172. // that need forwarding to.
  173. llinfos << "SOCKS 5 UDP proxy connected on " << mUDPProxy << llendl;
  174. return SOCKS_OK;
  175. }
  176. /**
  177. * @brief Initiates a SOCKS 5 proxy session.
  178. *
  179. * Performs basic checks on host to verify that it is a valid address. Opens
  180. * the control channel and then negotiates the proxy connection with the
  181. * server. Closes any existing SOCKS connection before proceeding. Also
  182. * disables an HTTP proxy if it is using SOCKS as the proxy.
  183. *
  184. *
  185. * @param host Socks server to connect to.
  186. * @return SOCKS_OK if successful, otherwise a SOCKS error code defined in
  187. * llproxy.h.
  188. */
  189. S32 LLProxy::startSOCKSProxy(LLHost host)
  190. {
  191. if (host.isOk())
  192. {
  193. mTCPProxy = host;
  194. }
  195. else
  196. {
  197. return SOCKS_INVALID_HOST;
  198. }
  199. // Close any running SOCKS connection.
  200. stopSOCKSProxy();
  201. mProxyControlChannel = tcp_open_channel(mTCPProxy);
  202. if (!mProxyControlChannel)
  203. {
  204. return SOCKS_HOST_CONNECT_FAILED;
  205. }
  206. S32 status = proxyHandshake(mTCPProxy);
  207. if (status != SOCKS_OK)
  208. {
  209. // Shut down the proxy if any of the above steps failed.
  210. stopSOCKSProxy();
  211. }
  212. else
  213. {
  214. // Connection was successful.
  215. sUDPProxyEnabled = true;
  216. }
  217. return status;
  218. }
  219. /**
  220. * @brief Stop using the SOCKS 5 proxy.
  221. *
  222. * This will stop sending UDP packets through the SOCKS 5 proxy and will also
  223. * stop the HTTP proxy if it is configured to use SOCKS. The proxy control
  224. * channel will also be disconnected.
  225. */
  226. void LLProxy::stopSOCKSProxy()
  227. {
  228. sUDPProxyEnabled = false;
  229. // If the SOCKS proxy is requested to stop and we are using that for HTTP
  230. // as well then we must shut down any HTTP proxy operations. But it is
  231. // allowable if web proxy is being used to continue proxying HTTP.
  232. if (LLPROXY_SOCKS == getHTTPProxyType())
  233. {
  234. disableHTTPProxy();
  235. }
  236. if (mProxyControlChannel)
  237. {
  238. tcp_close_channel(&mProxyControlChannel);
  239. }
  240. }
  241. /**
  242. * @brief Set the proxy's SOCKS authentication method to none.
  243. */
  244. void LLProxy::setAuthNone()
  245. {
  246. mProxyMutex.lock();
  247. mAuthMethodSelected = METHOD_NOAUTH;
  248. mProxyMutex.unlock();
  249. }
  250. /**
  251. * @brief Set the proxy's SOCKS authentication method to password.
  252. *
  253. * Check whether the lengths of the supplied username
  254. * and password conform to the lengths allowed by the
  255. * SOCKS protocol.
  256. *
  257. * @param username The SOCKS username to send.
  258. * @param password The SOCKS password to send.
  259. * @return Return true if applying the settings was successful. No changes are
  260. * made if false.
  261. *
  262. */
  263. bool LLProxy::setAuthPassword(const std::string& username,
  264. const std::string& password)
  265. {
  266. if (username.length() > SOCKSMAXUSERNAMELEN ||
  267. password.length() > SOCKSMAXPASSWORDLEN ||
  268. username.length() < SOCKSMINUSERNAMELEN ||
  269. password.length() < SOCKSMINPASSWORDLEN)
  270. {
  271. llwarns << "Invalid SOCKS 5 password or username length." << llendl;
  272. return false;
  273. }
  274. mProxyMutex.lock();
  275. mAuthMethodSelected = METHOD_PASSWORD;
  276. mSocksUsername = username;
  277. mSocksPassword = password;
  278. mProxyMutex.unlock();
  279. return true;
  280. }
  281. /**
  282. * @brief Enable the HTTP proxy for either SOCKS or HTTP.
  283. *
  284. * Check the supplied host to see if it is a valid IP and port.
  285. *
  286. * @param httpHost Proxy server to connect to.
  287. * @param type Is the host a SOCKS or HTTP proxy.
  288. * @return Return true if applying the setting was successful. No changes are
  289. * made if false.
  290. */
  291. bool LLProxy::enableHTTPProxy(LLHost http_host, LLHttpProxyType type)
  292. {
  293. if (!http_host.isOk())
  294. {
  295. llwarns << "Invalid SOCKS 5 Server" << llendl;
  296. return false;
  297. }
  298. mProxyMutex.lock();
  299. mHTTPProxy = http_host;
  300. mProxyType = type;
  301. mHTTPProxyEnabled = true;
  302. mProxyMutex.unlock();
  303. return true;
  304. }
  305. /**
  306. * @brief Enable the HTTP proxy without changing the proxy settings.
  307. *
  308. * This should not be called unless the proxy has already been set up.
  309. *
  310. * @return Return true only if the current settings are valid and the proxy was
  311. * enabled.
  312. */
  313. bool LLProxy::enableHTTPProxy()
  314. {
  315. mProxyMutex.lock();
  316. bool ok = mHTTPProxy.isOk();
  317. if (ok)
  318. {
  319. mHTTPProxyEnabled = true;
  320. }
  321. mProxyMutex.unlock();
  322. return ok;
  323. }
  324. /**
  325. * @brief Disable the HTTP proxy.
  326. */
  327. void LLProxy::disableHTTPProxy()
  328. {
  329. mProxyMutex.lock();
  330. mHTTPProxyEnabled = false;
  331. mProxyMutex.unlock();
  332. }
  333. /**
  334. * @brief Get the currently selected HTTP proxy type
  335. */
  336. LLHttpProxyType LLProxy::getHTTPProxyType() const
  337. {
  338. mProxyMutex.lock();
  339. LLHttpProxyType type = mProxyType;
  340. mProxyMutex.unlock();
  341. return type;
  342. }
  343. /**
  344. * @brief Get the SOCKS 5 password.
  345. */
  346. std::string LLProxy::getSocksPwd() const
  347. {
  348. mProxyMutex.lock();
  349. std::string password = mSocksPassword;
  350. mProxyMutex.unlock();
  351. return password;
  352. }
  353. /**
  354. * @brief Get the SOCKS 5 username.
  355. */
  356. std::string LLProxy::getSocksUser() const
  357. {
  358. mProxyMutex.lock();
  359. std::string username = mSocksUsername;
  360. mProxyMutex.unlock();
  361. return username;
  362. }
  363. /**
  364. * @brief Get the currently selected SOCKS 5 authentication method.
  365. *
  366. * @return Returns either none or password.
  367. */
  368. LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
  369. {
  370. mProxyMutex.lock();
  371. LLSocks5AuthType type = mAuthMethodSelected;
  372. mProxyMutex.unlock();
  373. return type;
  374. }
  375. /**
  376. * @brief Stop the LLProxy and make certain that any APR pools and classes
  377. * are deleted before terminating APR.
  378. *
  379. * Deletes the LLProxy singleton, destroying the APR pool used by the control
  380. * channel as well as .
  381. */
  382. //static
  383. void LLProxy::cleanupClass()
  384. {
  385. getInstance()->stopSOCKSProxy();
  386. deleteSingleton();
  387. }
  388. /**
  389. * @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
  390. *
  391. * This method has been designed to be safe to call from
  392. * any thread in the viewer. This allows requests in the
  393. * texture fetch thread to be aware of the proxy settings.
  394. * When the HTTP proxy is enabled, the proxy mutex will
  395. * be locked every time this method is called.
  396. *
  397. * @param handle A pointer to a valid CURL request, before it has been
  398. * performed.
  399. */
  400. void LLProxy::applyProxySettings(CURL* handle)
  401. {
  402. // Do a faster unlocked check to see if we are supposed to proxy.
  403. if (mHTTPProxyEnabled)
  404. {
  405. // We think we should proxy, lock the proxy mutex.
  406. mProxyMutex.lock();
  407. // Now test again to verify that the proxy wasn't disabled between the
  408. // first check and the lock.
  409. if (mHTTPProxyEnabled)
  410. {
  411. LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle,
  412. CURLOPT_PROXY,
  413. mHTTPProxy.getIPString().c_str()),
  414. CURLOPT_PROXY);
  415. LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle,
  416. CURLOPT_PROXYPORT,
  417. mHTTPProxy.getPort()),
  418. CURLOPT_PROXYPORT);
  419. if (mProxyType == LLPROXY_SOCKS)
  420. {
  421. LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle,
  422. CURLOPT_PROXYTYPE,
  423. CURLPROXY_SOCKS5),
  424. CURLOPT_PROXYTYPE);
  425. if (mAuthMethodSelected == METHOD_PASSWORD)
  426. {
  427. std::string auth_string = mSocksUsername + ":" +
  428. mSocksPassword;
  429. LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle,
  430. CURLOPT_PROXYUSERPWD,
  431. auth_string.c_str()),
  432. CURLOPT_PROXYUSERPWD);
  433. }
  434. }
  435. else
  436. {
  437. LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle,
  438. CURLOPT_PROXYTYPE,
  439. CURLPROXY_HTTP),
  440. CURLOPT_PROXYTYPE);
  441. }
  442. }
  443. mProxyMutex.unlock();
  444. }
  445. }
  446. /**
  447. * @brief Send one TCP packet and receive one in return.
  448. *
  449. * This operation is done synchronously with a 1000ms timeout. Therefore, it
  450. * should not be used when a blocking operation would impact the operation of
  451. * the viewer.
  452. *
  453. * @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
  454. * @param dataout Data to send.
  455. * @param outlen Length of dataout.
  456. * @param datain Buffer for received data. Undefined if return value is
  457. * not APR_SUCCESS.
  458. * @param maxinlen Maximum possible length of received data. Short reads
  459. * are allowed.
  460. * @return Indicates APR status code of exchange. APR_SUCCESS if
  461. * exchange was successful, -1 if invalid data length was
  462. * received.
  463. */
  464. static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle,
  465. char* dataout, apr_size_t outlen,
  466. char* datain, apr_size_t maxinlen)
  467. {
  468. apr_socket_t* apr_socket = handle->getSocket();
  469. apr_status_t rv = APR_SUCCESS;
  470. apr_size_t expected_len = outlen;
  471. handle->setBlocking(1000);
  472. rv = apr_socket_send(apr_socket, dataout, &outlen);
  473. if (rv != APR_SUCCESS)
  474. {
  475. char buf[MAX_STRING];
  476. llwarns << "Error sending data to proxy control channel, status: "
  477. << rv << " - " << apr_strerror(rv, buf, MAX_STRING) << llendl;
  478. ll_apr_warn_status(rv);
  479. }
  480. else if (expected_len != outlen)
  481. {
  482. llwarns << "Incorrect data length sent. Expected: " << expected_len
  483. << " Sent: " << outlen << llendl;
  484. rv = -1;
  485. }
  486. ms_sleep(1);
  487. if (rv == APR_SUCCESS)
  488. {
  489. expected_len = maxinlen;
  490. rv = apr_socket_recv(apr_socket, datain, &maxinlen);
  491. if (rv != APR_SUCCESS)
  492. {
  493. char buf[MAX_STRING];
  494. llwarns << "Error receiving data from proxy control channel, status: "
  495. << rv << " - " << apr_strerror(rv, buf, MAX_STRING)
  496. << llendl;
  497. ll_apr_warn_status(rv);
  498. }
  499. else if (expected_len < maxinlen)
  500. {
  501. llwarns << "Incorrect data length received. Expected: "
  502. << expected_len << " Received: " << maxinlen << llendl;
  503. rv = -1;
  504. }
  505. }
  506. handle->setNonBlocking();
  507. return rv;
  508. }
  509. /**
  510. * @brief Open a LLSocket and do a blocking connect to the chosen host.
  511. *
  512. * Checks for a successful connection, and makes sure the connection is closed
  513. * if it fails.
  514. *
  515. * @param host The host to open the connection to.
  516. * @return The created socket. Will evaluate as NULL if the connection
  517. * is unsuccessful.
  518. */
  519. static LLSocket::ptr_t tcp_open_channel(LLHost host)
  520. {
  521. LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP);
  522. bool connected = socket->blockingConnect(host);
  523. if (!connected)
  524. {
  525. tcp_close_channel(&socket);
  526. }
  527. return socket;
  528. }
  529. /**
  530. * @brief Close the socket.
  531. *
  532. * @param handle_ptr The handle of the socket being closed.
  533. * A pointer-to-pointer to avoid increasing the use count.
  534. */
  535. static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)
  536. {
  537. LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == "
  538. << handle_ptr->use_count() << LL_ENDL;
  539. handle_ptr->reset();
  540. }