diff options
Diffstat (limited to 'indra/llmessage')
| -rw-r--r-- | indra/llmessage/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llmessage/llcurl.cpp | 140 | ||||
| -rw-r--r-- | indra/llmessage/llcurl.h | 121 | ||||
| -rw-r--r-- | indra/llmessage/llhttpassetstorage.cpp | 5 | ||||
| -rw-r--r-- | indra/llmessage/llhttpclient.cpp | 5 | ||||
| -rw-r--r-- | indra/llmessage/lliosocket.cpp | 2 | ||||
| -rw-r--r-- | indra/llmessage/lliosocket.h | 14 | ||||
| -rw-r--r-- | indra/llmessage/llpacketring.cpp | 65 | ||||
| -rw-r--r-- | indra/llmessage/llpacketring.h | 12 | ||||
| -rw-r--r-- | indra/llmessage/llproxy.cpp | 551 | ||||
| -rw-r--r-- | indra/llmessage/llproxy.h | 342 | ||||
| -rw-r--r-- | indra/llmessage/llurlrequest.cpp | 4 | ||||
| -rw-r--r-- | indra/llmessage/net.cpp | 39 | ||||
| -rw-r--r-- | indra/llmessage/net.h | 4 | 
14 files changed, 1139 insertions, 167 deletions
| diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index c5f82cf052..0f40a670fa 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -65,6 +65,7 @@ set(llmessage_SOURCE_FILES      llpacketbuffer.cpp      llpacketring.cpp      llpartdata.cpp +    llproxy.cpp      llpumpio.cpp      llregionpresenceverifier.cpp      llsdappservices.cpp @@ -161,6 +162,7 @@ set(llmessage_HEADER_FILES      llpacketring.h      llpartdata.h      llpumpio.h +    llproxy.h      llqueryflags.h      llregionflags.h      llregionhandle.h diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 1a86a69a04..bfdf49c74b 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -1,5 +1,5 @@  /** - * @file llcurl.h + * @file llcurl.cpp   * @author Zero / Donovan   * @date 2006-10-15   * @brief Implementation of wrapper around libcurl. @@ -26,7 +26,6 @@   * $/LicenseInfo$   */ -  #if LL_WINDOWS  #define SAFE_SSL 1  #elif LL_DARWIN @@ -47,8 +46,9 @@  #endif  #include "llbufferstream.h" -#include "llstl.h" +#include "llproxy.h"  #include "llsdserialize.h" +#include "llstl.h"  #include "llthread.h"  #include "lltimer.h" @@ -209,7 +209,7 @@ namespace boost  	void intrusive_ptr_release(LLCurl::Responder* p)  	{ -		if(p && 0 == --p->mReferenceCount) +		if (p && 0 == --p->mReferenceCount)  		{  			delete p;  		} @@ -219,73 +219,6 @@ namespace boost  ////////////////////////////////////////////////////////////////////////////// - -class LLCurl::Easy -{ -	LOG_CLASS(Easy); - -private: -	Easy(); -	 -public: -	static Easy* getEasy(); -	~Easy(); - -	CURL* getCurlHandle() const { return mCurlEasyHandle; } - -	void setErrorBuffer(); -	void setCA(); -	 -	void setopt(CURLoption option, S32 value); -	// These assume the setter does not free value! -	void setopt(CURLoption option, void* value); -	void setopt(CURLoption option, char* value); -	// Copies the string so that it is gauranteed to stick around -	void setoptString(CURLoption option, const std::string& value); -	 -	void slist_append(const char* str); -	void setHeaders(); -	 -	U32 report(CURLcode); -	void getTransferInfo(LLCurl::TransferInfo* info); - -	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false); -	 -	const char* getErrorBuffer(); - -	std::stringstream& getInput() { return mInput; } -	std::stringstream& getHeaderOutput() { return mHeaderOutput; } -	LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; } -	const LLChannelDescriptors& getChannels() { return mChannels; } -	 -	void resetState(); - -	static CURL* allocEasyHandle(); -	static void releaseEasyHandle(CURL* handle); - -private:	 -	friend class LLCurl; - -	CURL*				mCurlEasyHandle; -	struct curl_slist*	mHeaders; -	 -	std::stringstream	mRequest; -	LLChannelDescriptors mChannels; -	LLIOPipe::buffer_ptr_t mOutput; -	std::stringstream	mInput; -	std::stringstream	mHeaderOutput; -	char				mErrorBuffer[CURL_ERROR_SIZE]; - -	// Note: char*'s not strings since we pass pointers to curl -	std::vector<char*>	mStrings; -	 -	ResponderPtr		mResponder; - -	static std::set<CURL*> sFreeHandles; -	static std::set<CURL*> sActiveHandles; -	static LLMutex* sHandleMutex; -}; -  std::set<CURL*> LLCurl::Easy::sFreeHandles;  std::set<CURL*> LLCurl::Easy::sActiveHandles;  LLMutex* LLCurl::Easy::sHandleMutex = NULL; @@ -409,11 +342,11 @@ const char* LLCurl::Easy::getErrorBuffer()  void LLCurl::Easy::setCA()  { -	if(!sCAPath.empty()) +	if (!sCAPath.empty())  	{  		setoptString(CURLOPT_CAPATH, sCAPath);  	} -	if(!sCAFile.empty()) +	if (!sCAFile.empty())  	{  		setoptString(CURLOPT_CAINFO, sCAFile);  	} @@ -536,9 +469,12 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	if (post) setoptString(CURLOPT_ENCODING, ""); -	//setopt(CURLOPT_VERBOSE, 1); // usefull for debugging +	//setopt(CURLOPT_VERBOSE, 1); // useful for debugging  	setopt(CURLOPT_NOSIGNAL, 1); +	// Set the CURL options for either Socks or HTTP proxy +	LLProxy::getInstance()->applyProxySettings(this); +  	mOutput.reset(new LLBufferArray);  	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);  	setopt(CURLOPT_WRITEDATA, (void*)this); @@ -550,7 +486,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	setopt(CURLOPT_HEADERDATA, (void*)this);  	// Allow up to five redirects -	if(responder && responder->followRedir()) +	if (responder && responder->followRedir())  	{  		setopt(CURLOPT_FOLLOWLOCATION, 1);  		setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS); @@ -563,7 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)  	setopt(CURLOPT_SSL_VERIFYHOST, 0); -	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT)); +	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);  	setoptString(CURLOPT_URL, url); @@ -584,56 +520,6 @@ void LLCurl::Easy::prepRequest(const std::string& url,  //////////////////////////////////////////////////////////////////////////// -class LLCurl::Multi : public LLThread -{ -	LOG_CLASS(Multi); -public: - -	typedef enum -	{ -		PERFORM_STATE_READY=0, -		PERFORM_STATE_PERFORMING=1, -		PERFORM_STATE_COMPLETED=2 -	} ePerformState; - -	Multi(); -	~Multi(); - -	Easy* allocEasy(); -	bool addEasy(Easy* easy); -	 -	void removeEasy(Easy* easy); - -	S32 process(); -	void perform(); -	void doPerform(); -	 -	virtual void run(); - -	CURLMsg* info_read(S32* msgs_in_queue); - -	S32 mQueued; -	S32 mErrorCount; -	 -	S32 mPerformState; - -	LLCondition* mSignal; -	bool mQuitting; -	bool mThreaded; - -private: -	void easyFree(Easy*); -	 -	CURLM* mCurlMultiHandle; - -	typedef std::set<Easy*> easy_active_list_t; -	easy_active_list_t mEasyActiveList; -	typedef std::map<CURL*, Easy*> easy_active_map_t; -	easy_active_map_t mEasyActiveMap; -	typedef std::set<Easy*> easy_free_list_t; -	easy_free_list_t mEasyFreeList; -}; -  LLCurl::Multi::Multi()  	: LLThread("Curl Multi"),  	  mQueued(0), @@ -1071,6 +957,8 @@ LLCurlEasyRequest::LLCurlEasyRequest()  	{  		mEasy->setErrorBuffer();  		mEasy->setCA(); +		// Set proxy settings if configured to do so. +		LLProxy::getInstance()->applyProxySettings(mEasy);  	}  } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index f7518c8e5c..5ab4dc35b9 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -187,6 +187,122 @@ private:  	static const unsigned int MAX_REDIRECTS;  }; +class LLCurl::Easy +{ +	LOG_CLASS(Easy); + +private: +	Easy(); + +public: +	static Easy* getEasy(); +	~Easy(); + +	CURL* getCurlHandle() const { return mCurlEasyHandle; } + +	void setErrorBuffer(); +	void setCA(); + +	void setopt(CURLoption option, S32 value); +	// These assume the setter does not free value! +	void setopt(CURLoption option, void* value); +	void setopt(CURLoption option, char* value); +	// Copies the string so that it is guaranteed to stick around +	void setoptString(CURLoption option, const std::string& value); + +	void slist_append(const char* str); +	void setHeaders(); + +	U32 report(CURLcode); +	void getTransferInfo(LLCurl::TransferInfo* info); + +	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false); + +	const char* getErrorBuffer(); + +	std::stringstream& getInput() { return mInput; } +	std::stringstream& getHeaderOutput() { return mHeaderOutput; } +	LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; } +	const LLChannelDescriptors& getChannels() { return mChannels; } + +	void resetState(); + +	static CURL* allocEasyHandle(); +	static void releaseEasyHandle(CURL* handle); + +private: +	friend class LLCurl; + +	CURL*				mCurlEasyHandle; +	struct curl_slist*	mHeaders; + +	std::stringstream	mRequest; +	LLChannelDescriptors mChannels; +	LLIOPipe::buffer_ptr_t mOutput; +	std::stringstream	mInput; +	std::stringstream	mHeaderOutput; +	char				mErrorBuffer[CURL_ERROR_SIZE]; + +	// Note: char*'s not strings since we pass pointers to curl +	std::vector<char*>	mStrings; + +	ResponderPtr		mResponder; + +	static std::set<CURL*> sFreeHandles; +	static std::set<CURL*> sActiveHandles; +	static LLMutex* sHandleMutex; +}; + +class LLCurl::Multi : public LLThread +{ +	LOG_CLASS(Multi); +public: + +	typedef enum +	{ +		PERFORM_STATE_READY=0, +		PERFORM_STATE_PERFORMING=1, +		PERFORM_STATE_COMPLETED=2 +	} ePerformState; + +	Multi(); +	~Multi(); + +	Easy* allocEasy(); +	bool addEasy(Easy* easy); +	 +	void removeEasy(Easy* easy); + +	S32 process(); +	void perform(); +	void doPerform(); +	 +	virtual void run(); + +	CURLMsg* info_read(S32* msgs_in_queue); + +	S32 mQueued; +	S32 mErrorCount; +	 +	S32 mPerformState; + +	LLCondition* mSignal; +	bool mQuitting; +	bool mThreaded; + +private: +	void easyFree(Easy*); +	 +	CURLM* mCurlMultiHandle; + +	typedef std::set<Easy*> easy_active_list_t; +	easy_active_list_t mEasyActiveList; +	typedef std::map<CURL*, Easy*> easy_active_map_t; +	easy_active_map_t mEasyActiveMap; +	typedef std::set<Easy*> easy_free_list_t; +	easy_free_list_t mEasyFreeList; +}; +  namespace boost  {  	void intrusive_ptr_add_ref(LLCurl::Responder* p); @@ -243,6 +359,8 @@ public:  	bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);  	std::string getErrorString(); +	LLCurl::Easy* getEasy() const { return mEasy; } +  private:  	CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info); @@ -253,4 +371,7 @@ private:  	bool mResultReturned;  }; +void check_curl_code(CURLcode code); +void check_curl_multi_code(CURLMcode code); +  #endif // LL_LLCURL_H diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index 5a38b7fd9f..2bca517e97 100644 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -33,6 +33,7 @@  #include "indra_constants.h"  #include "message.h" +#include "llproxy.h"  #include "llvfile.h"  #include "llvfs.h" @@ -232,6 +233,10 @@ void LLHTTPAssetRequest::setupCurlHandle()  {  	// *NOTE: Similar code exists in mapserver/llcurlutil.cpp  JC  	mCurlHandle = curl_easy_init(); + +	// Apply proxy settings if configured to do so +	LLProxy::getInstance()->applyProxySettings(mCurlHandle); +  	curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);  	curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);  	curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer.c_str()); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 0e5206a520..dd4e3a6300 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -428,6 +428,9 @@ static LLSD blocking_request(  	std::string body_str;  	// other request method checks root cert first, we skip? + +	// Apply configured proxy settings +	LLProxy::getInstance()->applyProxySettings(curlp);  	// * Set curl handle options  	curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1);	// don't use SIGALRM for timeouts @@ -436,7 +439,7 @@ static LLSD blocking_request(  	curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);  	curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());  	curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer); -	 +  	// * Setup headers (don't forget to free them after the call!)  	curl_slist* headers_list = NULL;  	if (headers.isMap()) diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index b717e321bf..ee9379f205 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -251,10 +251,12 @@ LLSocket::~LLSocket()  	{  		ll_debug_socket("Destroying socket", mSocket);  		apr_socket_close(mSocket); +		mSocket = NULL;  	}  	if(mPool)  	{  		apr_pool_destroy(mPool); +		mPool = NULL;  	}  } diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index e0f6c1e34d..be0f7dfcc6 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -145,13 +145,6 @@ public:  	 */  	apr_socket_t* getSocket() const { return mSocket; } -protected: -	/**  -	 * @brief Protected constructor since should only make sockets -	 * with one of the two <code>create()</code> calls. -	 */ -	LLSocket(apr_socket_t* socket, apr_pool_t* pool); -  	/**   	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.  	 * @param timeout Number of microseconds to wait on this socket. Any @@ -164,6 +157,13 @@ protected:  	 */  	void setNonBlocking(); +protected: +	/** +	 * @brief Protected constructor since should only make sockets +	 * with one of the two <code>create()</code> calls. +	 */ +	LLSocket(apr_socket_t* socket, apr_pool_t* pool); +  public:  	/**   	 * @brief Do not call this directly. diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 8999dec64a..7628984de4 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -28,11 +28,20 @@  #include "llpacketring.h" +#if LL_WINDOWS +	#include <winsock2.h> +#else +	#include <sys/socket.h> +	#include <netinet/in.h> +#endif +  // linden library includes  #include "llerror.h"  #include "lltimer.h" -#include "timing.h" +#include "llproxy.h"  #include "llrand.h" +#include "message.h" +#include "timing.h"  #include "u64.h"  /////////////////////////////////////////////////////////// @@ -216,8 +225,32 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)  	else  	{  		// no delay, pull straight from net -		packet_size = receive_packet(socket, datap);		 -		mLastSender = ::get_sender(); +		if (LLProxy::isSOCKSProxyEnabled()) +		{ +			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; +			packet_size = receive_packet(socket, reinterpret_cast<char *>(buffer)); +			 +			if (packet_size > SOCKS_HEADER_SIZE) +			{ +				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) +				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE); +				proxywrap_t * header = reinterpret_cast<proxywrap_t *>(buffer); +				mLastSender.setAddress(header->addr); +				mLastSender.setPort(ntohs(header->port)); + +				packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size +			} +			else +			{ +				packet_size = 0; +			} +		} +		else +		{ +			packet_size = receive_packet(socket, datap); +			mLastSender = ::get_sender(); +		} +  		mLastReceivingIF = ::get_receiving_interface();  		if (packet_size)  // did we actually get a packet? @@ -243,7 +276,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL  	BOOL status = TRUE;  	if (!mUseOutThrottle)  	{ -		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); +		return sendPacketImpl(h_socket, send_buffer, buf_size, host );  	}  	else  	{ @@ -264,7 +297,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL  				mOutBufferLength -= packetp->getSize();  				packet_size = packetp->getSize(); -				status = send_packet(h_socket, packetp->getData(), packet_size, packetp->getHost().getAddress(), packetp->getHost().getPort()); +				status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());  				delete packetp;  				// Update the throttle @@ -273,7 +306,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL  			else  			{  				// If the queue's empty, we can just send this packet right away. -				status = send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); +				status =  sendPacketImpl(h_socket, send_buffer, buf_size, host );  				packet_size = buf_size;  				// Update the throttle @@ -311,3 +344,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL  	return status;  } + +BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) +{ +	 +	if (!LLProxy::isSOCKSProxyEnabled()) +	{ +		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort()); +	} + +	proxywrap_t *socks_header = reinterpret_cast<proxywrap_t *>(&mProxyWrappedSendBuffer); +	socks_header->rsv   = 0; +	socks_header->addr  = host.getAddress(); +	socks_header->port  = htons(host.getPort()); +	socks_header->atype = ADDRESS_IPV4; +	socks_header->frag  = 0; + +	memcpy(mProxyWrappedSendBuffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); + +	return send_packet(h_socket, (const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort()); +} diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index e6409d2048..7edcc834db 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -30,11 +30,11 @@  #include <queue> -#include "llpacketbuffer.h"  #include "llhost.h" -#include "net.h" +#include "llpacketbuffer.h" +#include "llproxy.h"  #include "llthrottle.h" - +#include "net.h"  class LLPacketRing  { @@ -82,6 +82,12 @@ protected:  	LLHost mLastSender;  	LLHost mLastReceivingIF; + + +	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; + +private: +	BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);  }; diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp new file mode 100644 index 0000000000..3f4a6accbf --- /dev/null +++ b/indra/llmessage/llproxy.cpp @@ -0,0 +1,551 @@ +/** + * @file llproxy.cpp + * @brief UDP and HTTP proxy communications + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llproxy.h" + +#include <string> +#include <curl/curl.h> + +#include "llapr.h" +#include "llcurl.h" +#include "llhost.h" + +// Static class variable instances + +// We want this to be static to avoid excessive indirection on every +// incoming packet just to do a simple bool test. The getter for this +// member is also static +bool LLProxy::sUDPProxyEnabled = false; + +// Some helpful TCP static functions. +static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake +static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host); // Open a TCP channel to a given host +static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel + +LLProxy::LLProxy(): +		mHTTPProxyEnabled(false), +		mProxyMutex(0), +		mUDPProxy(), +		mTCPProxy(), +		mPool(gAPRPoolp), +		mHTTPProxy(), +		mProxyType(LLPROXY_SOCKS), +		mAuthMethodSelected(METHOD_NOAUTH), +		mSocksUsername(), +		mSocksPassword() +{ +} + +LLProxy::~LLProxy() +{ +	stopSOCKSProxy(); +	sUDPProxyEnabled  = false; +	mHTTPProxyEnabled = false; +} + +/** + * @brief Open the SOCKS 5 TCP control channel. + * + * Perform a SOCKS 5 authentication and UDP association to the proxy server. + * + * @param proxy The SOCKS 5 server to connect to. + * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h. + */ +S32 LLProxy::proxyHandshake(LLHost proxy) +{ +	S32 result; + +	/* SOCKS 5 Auth request */ +	socks_auth_request_t  socks_auth_request; +	socks_auth_response_t socks_auth_response; + +	socks_auth_request.version     = SOCKS_VERSION;       // SOCKS version 5 +	socks_auth_request.num_methods = 1;                   // Sending 1 method. +	socks_auth_request.methods     = getSelectedAuthMethod(); // Send only the selected method. + +	result = tcp_handshake(mProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request), (char*)&socks_auth_response, sizeof(socks_auth_response)); +	if (result != APR_SUCCESS) +	{ +		LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; +		stopSOCKSProxy(); +		return SOCKS_CONNECT_ERROR; +	} + +	if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE) +	{ +		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods" << LL_ENDL; +		stopSOCKSProxy(); +		return SOCKS_NOT_ACCEPTABLE; +	} + +	// SOCKS 5 USERNAME/PASSWORD authentication +	if (socks_auth_response.method == METHOD_PASSWORD) +	{ +		// The server has requested a username/password combination +		std::string socks_username(getSocksUser()); +		std::string socks_password(getSocksPwd()); +		U32 request_size = socks_username.size() + socks_password.size() + 3; +		char * password_auth = new char[request_size]; +		password_auth[0] = 0x01; +		password_auth[1] = socks_username.size(); +		memcpy(&password_auth[2], socks_username.c_str(), socks_username.size()); +		password_auth[socks_username.size() + 2] = socks_password.size(); +		memcpy(&password_auth[socks_username.size()+3], socks_password.c_str(), socks_password.size()); + +		authmethod_password_reply_t password_reply; + +		result = tcp_handshake(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(password_reply)); +		delete[] password_auth; + +		if (result != APR_SUCCESS) +		{ +			LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL; +			stopSOCKSProxy(); +			return SOCKS_CONNECT_ERROR; +		} + +		if (password_reply.status != AUTH_SUCCESS) +		{ +			LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL; +			stopSOCKSProxy(); +			return SOCKS_AUTH_FAIL; +		} +	} + +	/* SOCKS5 connect request */ + +	socks_command_request_t  connect_request; +	socks_command_response_t connect_reply; + +	connect_request.version		= SOCKS_VERSION;         // SOCKS V5 +	connect_request.command		= COMMAND_UDP_ASSOCIATE; // Associate UDP +	connect_request.reserved	= FIELD_RESERVED; +	connect_request.atype		= ADDRESS_IPV4; +	connect_request.address		= htonl(0); // 0.0.0.0 +	connect_request.port		= htons(0); // 0 +	// "If the client is not in possession of the information at the time of the UDP ASSOCIATE, +	//  the client MUST use a port number and address of all zeros. RFC 1928" + +	result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(connect_request), (char*)&connect_reply, sizeof(connect_reply)); +	if (result != APR_SUCCESS) +	{ +		LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; +		stopSOCKSProxy(); +		return SOCKS_CONNECT_ERROR; +	} + +	if (connect_reply.reply != REPLY_REQUEST_GRANTED) +	{ +		LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL; +		stopSOCKSProxy(); +		return SOCKS_UDP_FWD_NOT_GRANTED; +	} + +	mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order +	mUDPProxy.setAddress(proxy.getAddress()); +	// The connection was successful. We now have the UDP port to send requests that need forwarding to. +	LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; +	return SOCKS_OK; +} + +/** + * @brief Initiates a SOCKS 5 proxy session. + * + * Performs basic checks on host to verify that it is a valid address. Opens the control channel + * and then negotiates the proxy connection with the server. + * + * + * @param host Socks server to connect to. + * @return SOCKS_OK if successful, otherwise a SOCKS error code defined in llproxy.h. + */ +S32 LLProxy::startSOCKSProxy(LLHost host) +{ +	S32 status = SOCKS_OK; + +	if (host.isOk()) +	{ +		mTCPProxy = host; +	} +	else +	{ +		status = SOCKS_INVALID_HOST; +	} + +	if (mProxyControlChannel && status == SOCKS_OK) +	{ +		tcp_close_channel(&mProxyControlChannel); +	} + +	if (status == SOCKS_OK) +	{ +		mProxyControlChannel = tcp_open_channel(mPool, mTCPProxy); +		if (!mProxyControlChannel) +		{ +			status = SOCKS_HOST_CONNECT_FAILED; +		} +	} + +	if (status == SOCKS_OK) +	{ +		status = proxyHandshake(mTCPProxy); +	} +	if (status == SOCKS_OK) +	{ +		sUDPProxyEnabled = true; +	} +	else +	{ +		stopSOCKSProxy(); +	} +	return status; +} + +/** + * @brief Stop using the SOCKS 5 proxy. + * + * This will stop sending UDP packets through the SOCKS 5 proxy + * and will also stop the HTTP proxy if it is configured to use SOCKS. + * The proxy control channel will also be disconnected. + */ +void LLProxy::stopSOCKSProxy() +{ +	sUDPProxyEnabled = false; + +	// If the SOCKS proxy is requested to stop and we are using that for HTTP as well +	// then we must shut down any HTTP proxy operations. But it is allowable if web +	// proxy is being used to continue proxying HTTP. + +	if (LLPROXY_SOCKS == getHTTPProxyType()) +	{ +		void disableHTTPProxy(); +	} + +	if (mProxyControlChannel) +	{ +		tcp_close_channel(&mProxyControlChannel); +	} +} + +/** + * @brief Set the proxy's SOCKS authentication method to none. + */ +void LLProxy::setAuthNone() +{ +	LLMutexLock lock(&mProxyMutex); + +	mAuthMethodSelected = METHOD_NOAUTH; +} + +/** + * @brief Set the proxy's SOCKS authentication method to password. + * + * Check whether the lengths of the supplied username + * and password conform to the lengths allowed by the + * SOCKS protocol. + * + * @param 	username The SOCKS username to send. + * @param 	password The SOCKS password to send. + * @return  Return true if applying the settings was successful. No changes are made if false. + * + */ +bool LLProxy::setAuthPassword(const std::string &username, const std::string &password) +{ +	if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN || +			username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN) +	{ +		LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL; +		return false; +	} + +	LLMutexLock lock(&mProxyMutex); + +	mAuthMethodSelected = METHOD_PASSWORD; +	mSocksUsername      = username; +	mSocksPassword      = password; + +	return true; +} + +/** + * @brief Enable the HTTP proxy for either SOCKS or HTTP. + * + * Check the supplied host to see if it is a valid IP and port. + * + * @param httpHost Proxy server to connect to. + * @param type Is the host a SOCKS or HTTP proxy. + * @return Return true if applying the setting was successful. No changes are made if false. + */ +bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) +{ +	if (!httpHost.isOk()) +	{ +		LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL; +		return false; +	} + +	LLMutexLock lock(&mProxyMutex); + +	mHTTPProxy        = httpHost; +	mProxyType        = type; + +	mHTTPProxyEnabled = true; + +	return true; +} + +/** + * @brief Enable the HTTP proxy without changing the proxy settings. + * + * This should not be called unless the proxy has already been set up. + * + * @return Return true only if the current settings are valid and the proxy was enabled. + */ +bool LLProxy::enableHTTPProxy() +{ +	bool ok; + +	LLMutexLock lock(&mProxyMutex); + +	ok = (mHTTPProxy.isOk()); +	if (ok) +	{ +		mHTTPProxyEnabled = true; +	} + +	return ok; +} + +/** + * @brief Disable the HTTP proxy. + */ +void LLProxy::disableHTTPProxy() +{ +	LLMutexLock lock(&mProxyMutex); + +	mHTTPProxyEnabled = false; +} + +/** + * @brief Get the HTTP proxy address and port + */ +// +LLHost LLProxy::getHTTPProxy() const +{ +	LLMutexLock lock(&mProxyMutex); +	return mHTTPProxy; +} + +/** + * @brief Get the currently selected HTTP proxy type + */ +LLHttpProxyType LLProxy::getHTTPProxyType() const +{ +	LLMutexLock lock(&mProxyMutex); +	return mProxyType; +} + +/** + * @brief Get the SOCKS 5 password. + */ +std::string LLProxy::getSocksPwd() const +{ +	LLMutexLock lock(&mProxyMutex); +	return mSocksPassword; +} + +/** + * @brief Get the SOCKS 5 username. + */ +std::string LLProxy::getSocksUser() const +{ +	LLMutexLock lock(&mProxyMutex); +	return mSocksUsername; +} + +/** + * @brief Get the currently selected SOCKS 5 authentication method. + * + * @return Returns either none or password. + */ +LLSocks5AuthType LLProxy::getSelectedAuthMethod() const +{ +	LLMutexLock lock(&mProxyMutex); +	return mAuthMethodSelected; +} + +/** + * @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR. + * + * Deletes the LLProxy singleton, destroying the APR pool used by the control channel as well as . + */ +//static +void LLProxy::cleanupClass() +{ +	getInstance()->stopSOCKSProxy(); +	deleteSingleton(); +} + +void LLProxy::applyProxySettings(LLCurlEasyRequest* handle) +{ +	applyProxySettings(handle->getEasy()); +} + +void LLProxy::applyProxySettings(LLCurl::Easy* handle) +{ +	applyProxySettings(handle->getCurlHandle()); +} + +/** + * @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled. + * + * This method has been designed to be safe to call from + * any thread in the viewer.  This allows requests in the + * texture fetch thread to be aware of the proxy settings. + * When the HTTP proxy is enabled, the proxy mutex will + * be locked every time this method is called. + * + * @param handle A pointer to a valid CURL request, before it has been performed. + */ +void LLProxy::applyProxySettings(CURL* handle) +{ +	// Do a faster unlocked check to see if we are supposed to proxy. +	if (mHTTPProxyEnabled) +	{ +		// We think we should proxy, lock the proxy mutex. +		LLMutexLock lock(&mProxyMutex); +		// Now test again to verify that the proxy wasn't disabled between the first check and the lock. +		if (mHTTPProxyEnabled) +		{ +			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); +			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort())); + +			if (mProxyType == LLPROXY_SOCKS) +			{ +				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5)); +				if (mAuthMethodSelected == METHOD_PASSWORD) +				{ +					std::string auth_string = mSocksUsername + ":" + mSocksPassword; +					check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str())); +				} +			} +			else +			{ +				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)); +			} +		} +	} +} + +/** + * @brief Send one TCP packet and receive one in return. + * + * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking + * operation would impact the operation of the viewer. + * + * @param handle_ptr 	Pointer to a connected LLSocket of type STREAM_TCP. + * @param dataout		Data to send. + * @param outlen		Length of dataout. + * @param datain		Buffer for received data. Undefined if return value is not APR_SUCCESS. + * @param maxinlen		Maximum possible length of received data.  Short reads are allowed. + * @return 				Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received. + */ +static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) +{ +	apr_socket_t* apr_socket = handle->getSocket(); +	apr_status_t rv = APR_SUCCESS; + +	apr_size_t expected_len = outlen; + +	handle->setBlocking(1000); + +  	rv = apr_socket_send(apr_socket, dataout, &outlen); +	if (APR_SUCCESS != rv) +	{ +		LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL; +		ll_apr_warn_status(rv); +	} +	else if (expected_len != outlen) +	{ +		LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len << +				" Sent: " << outlen << LL_ENDL; +		rv = -1; +	} + +	if (APR_SUCCESS == rv) +	{ +		expected_len = maxinlen; +		rv = apr_socket_recv(apr_socket, datain, &maxinlen); +		if (rv != APR_SUCCESS) +		{ +			LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL; +			ll_apr_warn_status(rv); +		} +		else if (expected_len < maxinlen) +		{ +			LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len << +					" Received: " << maxinlen << LL_ENDL; +			rv = -1; +		} +	} + +	handle->setNonBlocking(); + +	return rv; +} + +/** + * @brief Open a LLSocket and do a blocking connect to the chosen host. + * + * Checks for a successful connection, and makes sure the connection is closed if it fails. + * + * @param pool		APR pool to pass into the LLSocket. + * @param host		The host to open the connection to. + * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful. + */ +static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host) +{ +	LLSocket::ptr_t socket = LLSocket::create(pool, LLSocket::STREAM_TCP); +	bool connected = socket->blockingConnect(host); +	if (!connected) +	{ +		tcp_close_channel(&socket); +	} + +	return socket; +} + +/** + * @brief Close the socket. + * + * @param handle_ptr A pointer-to-pointer to avoid increasing the use count. + */ +static void tcp_close_channel(LLSocket::ptr_t* handle_ptr) +{ +	LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL; +	handle_ptr->reset(); +} diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h new file mode 100644 index 0000000000..29e7e28567 --- /dev/null +++ b/indra/llmessage/llproxy.h @@ -0,0 +1,342 @@ +/** + * @file llproxy.h + * @brief UDP and HTTP proxy communications + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_PROXY_H +#define LL_PROXY_H + +#include "llcurl.h" +#include "llhost.h" +#include "lliosocket.h" +#include "llmemory.h" +#include "llsingleton.h" +#include "llthread.h" +#include <string> + +// SOCKS error codes returned from the StartProxy method + +#define SOCKS_OK 0 +#define SOCKS_CONNECT_ERROR (-1) +#define SOCKS_NOT_PERMITTED (-2) +#define SOCKS_NOT_ACCEPTABLE (-3) +#define SOCKS_AUTH_FAIL (-4) +#define SOCKS_UDP_FWD_NOT_GRANTED (-5) +#define SOCKS_HOST_CONNECT_FAILED (-6) +#define SOCKS_INVALID_HOST (-7) + + +#ifndef MAXHOSTNAMELEN +#define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */ +#endif + +#define SOCKSMAXUSERNAMELEN 255 +#define SOCKSMAXPASSWORDLEN 255 + +#define SOCKSMINUSERNAMELEN 1 +#define SOCKSMINPASSWORDLEN 1 + +#define SOCKS_VERSION 0x05 // we are using SOCKS 5 + +#define SOCKS_HEADER_SIZE 10 + +// SOCKS 5 address/hostname types +#define ADDRESS_IPV4     0x01 +#define ADDRESS_HOSTNAME 0x03 +#define ADDRESS_IPV6     0x04 + +// Lets just use our own ipv4 struct rather than dragging in system +// specific headers +union ipv4_address_t { +	U8		octets[4]; +	U32		addr32; +}; + +// SOCKS 5 control channel commands +#define COMMAND_TCP_STREAM    0x01 +#define COMMAND_TCP_BIND      0x02 +#define COMMAND_UDP_ASSOCIATE 0x03 + +// SOCKS 5 command replies +#define REPLY_REQUEST_GRANTED     0x00 +#define REPLY_GENERAL_FAIL        0x01 +#define REPLY_RULESET_FAIL        0x02 +#define REPLY_NETWORK_UNREACHABLE 0x03 +#define REPLY_HOST_UNREACHABLE    0x04 +#define REPLY_CONNECTION_REFUSED  0x05 +#define REPLY_TTL_EXPIRED         0x06 +#define REPLY_PROTOCOL_ERROR      0x07 +#define REPLY_TYPE_NOT_SUPPORTED  0x08 + +#define FIELD_RESERVED 0x00 + +// The standard SOCKS 5 request packet +// Push current alignment to stack and set alignment to 1 byte boundary +// This enabled us to use structs directly to set up and receive network packets +// into the correct fields, without fear of boundary alignment causing issues +#pragma pack(push,1) + +// SOCKS 5 command packet +struct socks_command_request_t { +	U8		version; +	U8		command; +	U8		reserved; +	U8		atype; +	U32		address; +	U16		port; +}; + +// Standard SOCKS 5 reply packet +struct socks_command_response_t { +	U8		version; +	U8		reply; +	U8		reserved; +	U8		atype; +	U8		add_bytes[4]; +	U16		port; +}; + +#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available +#define AUTH_SUCCESS        0x00 // reply if authentication successful + +// SOCKS 5 authentication request, stating which methods the client supports +struct socks_auth_request_t { +	U8		version; +	U8		num_methods; +	U8		methods; // We are only using a single method currently +}; + +// SOCKS 5 authentication response packet, stating server preferred method +struct socks_auth_response_t { +	U8		version; +	U8		method; +}; + +// SOCKS 5 password reply packet +struct authmethod_password_reply_t { +	U8		version; +	U8		status; +}; + +// SOCKS 5 UDP packet header +struct proxywrap_t { +	U16		rsv; +	U8		frag; +	U8		atype; +	U32		addr; +	U16		port; +}; + +#pragma pack(pop) /* restore original alignment from stack */ + + +// Currently selected HTTP proxy type +enum LLHttpProxyType +{ +	LLPROXY_SOCKS = 0, +	LLPROXY_HTTP  = 1 +}; + +// Auth types +enum LLSocks5AuthType +{ +	METHOD_NOAUTH   = 0x00,	// Client supports no auth +	METHOD_GSSAPI   = 0x01,	// Client supports GSSAPI (Not currently supported) +	METHOD_PASSWORD = 0x02 	// Client supports username/password +}; + +/** + * @brief Manage SOCKS 5 UDP proxy and HTTP proxy. + * + * This class is responsible for managing two interconnected tasks, + * connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP + * packets and managing proxy settings for HTTP requests. + * + * <h1>Threading:</h1> + * Because HTTP requests can be generated in threads outside the + * main thread, it is necessary for some of the information stored + * by this class to be available to other threads. The members that + * need to be read across threads are in a labeled section below. + * To protect those members, a mutex, mProxyMutex should be locked + * before reading or writing those members.  Methods that can lock + * mProxyMutex are in a labeled section below. Those methods should + * not be called while the mutex is already locked. + * + * There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used + * to track whether the HTTP proxy is currently enabled. This allows + * for faster unlocked checks to see if the proxy is enabled.  This + * allows us to cut down on the performance hit when the proxy is + * disabled compared to before this class was introduced. + * + * <h1>UDP Proxying:</h1> + * UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate + * command.  To initiate the proxy, a TCP socket connection is opened + * to the SOCKS 5 host, and after a handshake exchange, the server + * returns a port and address to send the UDP traffic that is to be + * proxied to. The LLProxy class tracks this address and port after the + * exchange and provides it to LLPacketRing when required to. All UDP + * proxy management occurs in the main thread. + * + * <h1>HTTP Proxying:</h1> + * This class allows all viewer HTTP packets to be sent through a proxy. + * The user can select whether to send HTTP packets through a standard + * "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP + * communication. This class does not manage the integrated web browser + * proxy, which is handled in llviewermedia.cpp. + * + * The implementation of HTTP proxying is handled by libcurl. LLProxy + * is responsible for managing the HTTP proxy options and provides a + * thread-safe method to apply those options to a curl request + * (LLProxy::applyProxySettings()). This method is overloaded + * to accommodate the various abstraction libcurl layers that exist + * throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL). + * + * If you are working with LLCurl or LLCurlEasyRequest objects, + * the configured proxy settings will be applied in the constructors + * of those request handles.  If you are working with CURL objects + * directly, you will need to pass the handle of the request to + * applyProxySettings() before issuing the request. + * + * To ensure thread safety, all LLProxy members that relate to the HTTP + * proxy require the LLProxyMutex to be locked before accessing. + */ +class LLProxy: public LLSingleton<LLProxy> +{ +	LOG_CLASS(LLProxy); +public: +	// METHODS THAT DO NOT LOCK mProxyMutex! + +	LLProxy(); + +	// static check for enabled status for UDP packets +	static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } + +	// check for enabled status for HTTP packets +	// mHTTPProxyEnabled is atomic, so no locking is required for thread safety. +	bool isHTTPProxyEnabled() const { return mHTTPProxyEnabled; } + +	// Get the UDP proxy address and port +	LLHost getUDPProxy() const { return mUDPProxy; } + +	// Get the SOCKS 5 TCP control channel address and port +	LLHost getTCPProxy() const { return mTCPProxy; } + +	// END OF NON-LOCKING METHODS + +	// METHODS THAT DO LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! + +	~LLProxy(); + +	// Start a connection to the SOCKS 5 proxy +	S32 startSOCKSProxy(LLHost host); + +	// Disconnect and clean up any connection to the SOCKS 5 proxy +	void stopSOCKSProxy(); + +	// Delete LLProxy singleton, destroying the APR pool used by the control channel. +	static void cleanupClass(); + +	// Set up to use Password auth when connecting to the SOCKS proxy +	bool setAuthPassword(const std::string &username, const std::string &password); + +	// Set up to use No Auth when connecting to the SOCKS proxy +	void setAuthNone(); + +	// Get the currently selected auth method. +	LLSocks5AuthType getSelectedAuthMethod() const; + +	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy +	// as specified in type +	bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type); +	bool enableHTTPProxy(); + +	// Stop proxying HTTP packets +	void disableHTTPProxy(); + +	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. +	void applyProxySettings(CURL* handle); +	void applyProxySettings(LLCurl::Easy* handle); +	void applyProxySettings(LLCurlEasyRequest* handle); + +	// Get the HTTP proxy address and port +	LLHost getHTTPProxy() const; + +	// Get the currently selected HTTP proxy type +	LLHttpProxyType getHTTPProxyType() const; + +	std::string getSocksPwd() const; +	std::string getSocksUser() const; + +	// END OF LOCKING METHODS +private: +	// Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort +	S32 proxyHandshake(LLHost proxy); + +private: +	// Is the HTTP proxy enabled? +	// Safe to read in any thread, do not write directly, +	// use enableHTTPProxy() and disableHTTPProxy() instead. +	mutable LLAtomic32<bool> mHTTPProxyEnabled; + +	// Mutex to protect shared members in non-main thread calls to applyProxySettings() +	mutable LLMutex mProxyMutex; + +	// MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! + +	// Is the UDP proxy enabled? +	static bool sUDPProxyEnabled; + +	// UDP proxy address and port +	LLHost mUDPProxy; +	// TCP proxy control channel address and port +	LLHost mTCPProxy; + +	// socket handle to proxy TCP control channel +	LLSocket::ptr_t mProxyControlChannel; + +	// APR pool for the socket +	apr_pool_t* mPool; + +	// END OF UNSHARED MEMBERS + +	// MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! + +	// HTTP proxy address and port +	LLHost mHTTPProxy; + +	// Currently selected HTTP proxy type. Can be web or socks. +	LLHttpProxyType mProxyType; + +	// SOCKS 5 auth method selected +	LLSocks5AuthType mAuthMethodSelected; + +	// SOCKS 5 username +	std::string mSocksUsername; +	// SOCKS 5 password +	std::string mSocksPassword; + +	// END OF SHARED MEMBERS +}; + +#endif diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index e8e35d00a2..d5400e4169 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -35,6 +35,7 @@  #include "llcurl.h"  #include "llioutil.h"  #include "llmemtype.h" +#include "llproxy.h"  #include "llpumpio.h"  #include "llsd.h"  #include "llstring.h" @@ -227,8 +228,7 @@ void LLURLRequest::useProxy(bool use_proxy)          }      } - -    lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl; +    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL;      if (env_proxy && use_proxy)      { diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 97611c3b51..85aef5da00 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -50,7 +50,6 @@  #include "lltimer.h"  #include "indra_constants.h" -  // Globals  #if LL_WINDOWS @@ -174,7 +173,7 @@ U32 ip_string_to_u32(const char* ip_string)  	// use wildcard addresses. -Ambroff  	U32 ip = inet_addr(ip_string);  	if (ip == INADDR_NONE  -	    && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0) +			&& strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0)  	{  		llwarns << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << llendl;  		return INVALID_HOST_IP_ADDRESS; @@ -188,11 +187,11 @@ U32 ip_string_to_u32(const char* ip_string)  //////////////////////////////////////////////////////////////////////////////////////////  #if LL_WINDOWS -  +  S32 start_net(S32& socket_out, int& nPort)   {			  	// Create socket, make non-blocking -    // Init WinSock  +	// Init WinSock  	int nRet;  	int hSocket; @@ -201,7 +200,7 @@ S32 start_net(S32& socket_out, int& nPort)  	int buff_size = 4;  	// Initialize windows specific stuff -	if(WSAStartup(0x0202, &stWSAData)) +	if (WSAStartup(0x0202, &stWSAData))  	{  		S32 err = WSAGetLastError();  		WSACleanup(); @@ -210,8 +209,8 @@ S32 start_net(S32& socket_out, int& nPort)  	}  	// Get a datagram socket -    hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); -    if (hSocket == INVALID_SOCKET) +	hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); +	if (hSocket == INVALID_SOCKET)  	{  		S32 err = WSAGetLastError();  		WSACleanup(); @@ -304,7 +303,7 @@ S32 start_net(S32& socket_out, int& nPort)  	//  Setup a destination address  	stDstAddr.sin_family =      AF_INET;  	stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS; -    stDstAddr.sin_port =        htons(nPort); +	stDstAddr.sin_port =        htons(nPort);  	socket_out = hSocket;  	return 0; @@ -393,10 +392,10 @@ S32 start_net(S32& socket_out, int& nPort)  	int rec_size = RECEIVE_BUFFER_SIZE;  	socklen_t buff_size = 4; -     +  	//  Create socket -    hSocket = socket(AF_INET, SOCK_DGRAM, 0); -    if (hSocket < 0) +	hSocket = socket(AF_INET, SOCK_DGRAM, 0); +	if (hSocket < 0)  	{  		llwarns << "socket() failed" << llendl;  		return 1; @@ -429,7 +428,7 @@ S32 start_net(S32& socket_out, int& nPort)  	}  	else  	{ -	    // Name the socket (assign the local port number to receive on) +		// Name the socket (assign the local port number to receive on)  		stLclAddr.sin_family      = AF_INET;  		stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);  		stLclAddr.sin_port        = htons(nPort); @@ -474,7 +473,7 @@ S32 start_net(S32& socket_out, int& nPort)  		nPort = attempt_port;  	}  	// Set socket to be non-blocking - 	fcntl(hSocket, F_SETFL, O_NONBLOCK); +	fcntl(hSocket, F_SETFL, O_NONBLOCK);  	// set a large receive buffer  	nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);  	if (nRet) @@ -510,8 +509,8 @@ S32 start_net(S32& socket_out, int& nPort)  	//  Setup a destination address  	char achMCAddr[MAXADDRSTR] = "127.0.0.1";	/* Flawfinder: ignore */   	stDstAddr.sin_family =      AF_INET; -        stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr); -        stDstAddr.sin_port =        htons(nPort); +	stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr); +	stDstAddr.sin_port =        htons(nPort);  	socket_out = hSocket;  	return 0; @@ -537,7 +536,7 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro  	iov[0].iov_base = buf;  	iov[0].iov_len = len; -	memset( &msg, 0, sizeof msg ); +	memset(&msg, 0, sizeof msg);  	msg.msg_name = from;  	msg.msg_namelen = *fromlen;  	msg.msg_iov = iov; @@ -545,14 +544,14 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro  	msg.msg_control = &cmsg;  	msg.msg_controllen = sizeof(cmsg); -	size = recvmsg( socket, &msg, 0 ); +	size = recvmsg(socket, &msg, 0); -	if( size == -1 ) +	if (size == -1)  	{  		return -1;  	} -	for( cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr ) ) +	for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr))  	{  		if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO )  		{ @@ -650,7 +649,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient,  			}  		}  	} -	while ( resend && send_attempts < 3); +	while (resend && send_attempts < 3);  	if (send_attempts >= 3)  	{ diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index 9f4f5c5821..0f2437479d 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -46,10 +46,10 @@ S32		receive_packet(int hSocket, char * receiveBuffer);  BOOL	send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort);	// Returns TRUE on success.  //void	get_sender(char * tmp); -LLHost  get_sender(); +LLHost	get_sender();  U32		get_sender_port();  U32		get_sender_ip(void); -LLHost  get_receiving_interface(); +LLHost	get_receiving_interface();  U32		get_receiving_interface_ip(void);  const char*	u32_to_ip_string(U32 ip);					// Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls  | 
