diff options
| -rw-r--r-- | indra/llmessage/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llmessage/llcurl.cpp | 43 | ||||
| -rw-r--r-- | indra/llmessage/llpacketring.cpp | 60 | ||||
| -rw-r--r-- | indra/llmessage/llpacketring.h | 3 | ||||
| -rw-r--r-- | indra/llmessage/llsocks5.cpp | 218 | ||||
| -rw-r--r-- | indra/llmessage/llsocks5.h | 237 | ||||
| -rw-r--r-- | indra/llmessage/net.cpp | 156 | ||||
| -rw-r--r-- | indra/llmessage/net.h | 5 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 77 | ||||
| -rwxr-xr-x | indra/newview/llfloaterpreference.cpp | 171 | ||||
| -rw-r--r-- | indra/newview/llfloaterpreference.h | 30 | ||||
| -rw-r--r-- | indra/newview/llstartup.cpp | 123 | ||||
| -rw-r--r-- | indra/newview/llstartup.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llxmlrpctransaction.cpp | 21 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_preferences_proxy.xml | 274 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 70 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_setup.xml | 83 | 
18 files changed, 1511 insertions, 65 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index c5f82cf052..4b679ef6a5 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -76,6 +76,7 @@ set(llmessage_SOURCE_FILES      llsdrpcserver.cpp      llservicebuilder.cpp      llservice.cpp +    llsocks5.cpp      llstoredmessage.cpp      lltemplatemessagebuilder.cpp      lltemplatemessagedispatcher.cpp @@ -174,6 +175,7 @@ set(llmessage_HEADER_FILES      llsdrpcserver.h      llservice.h      llservicebuilder.h +    llsocks5.h      llstoredmessage.h      lltaskname.h      llteleportflags.h diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 7c8b7e3584..9c507517c7 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -51,6 +51,8 @@  #include "llthread.h"  #include "lltimer.h" +#include "llsocks5.h" +  //////////////////////////////////////////////////////////////////////////////  /*  	The trick to getting curl to do keep-alives is to reuse the @@ -355,6 +357,27 @@ LLCurl::Easy* LLCurl::Easy::getEasy()  	// multi handles cache if they are added to one.  	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);  	check_curl_code(result); + +	//Set the CURL options for either Socks or HTTP proxy +	if (LLSocks::getInstance()->isHttpProxyEnabled()) +	{ +		std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); +		U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); +		curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXY,address.c_str()); +		curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYPORT,port); +		if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) +		{ +			curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); +			if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) +			{ +				curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd().c_str()); +			} +		} +		else +		{ +			curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); +		} +	}  	++gCurlEasyCount;  	return easy; @@ -534,6 +557,26 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	//setopt(CURLOPT_VERBOSE, 1); // usefull for debugging  	setopt(CURLOPT_NOSIGNAL, 1); +	if (LLSocks::getInstance()->isHttpProxyEnabled()) +	{ +		std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); +		U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); +		setoptString(CURLOPT_PROXY, address.c_str()); +		setopt(CURLOPT_PROXYPORT, port); +		if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) +		{ +			setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); +			if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) +			{ +				setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); +			} +		} +		else +		{ +			setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); +		} +	} +  	mOutput.reset(new LLBufferArray);  	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);  	setopt(CURLOPT_WRITEDATA, (void*)this); diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 8999dec64a..0c8c5f763c 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -35,6 +35,17 @@  #include "llrand.h"  #include "u64.h" +#include "llsocks5.h" +#include "message.h" + +#if LL_WINDOWS +	#include <winsock2.h> +#else +	#include <sys/socket.h> +	#include <netinet/in.h> +#endif + +  ///////////////////////////////////////////////////////////  LLPacketRing::LLPacketRing () :  	mUseInThrottle(FALSE), @@ -216,8 +227,31 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)  	else  	{  		// no delay, pull straight from net +		if (LLSocks::isEnabled()) +		{ +			U8 buffer[MAX_BUFFER_SIZE]; +			packet_size = receive_packet(socket, (char*)buffer); +			 +			if (packet_size > 10) +			{ +				memcpy(datap,buffer+10,packet_size-10); +			} +			else +			{ +				packet_size=0; +			} + +			proxywrap_t * header; +			header = (proxywrap_t *)buffer; +			mLastSender.setAddress(header->addr); +			mLastSender.setPort(ntohs(header->port)); +		} +		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 +277,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 doSendPacket(h_socket, send_buffer, buf_size, host );  	}  	else  	{ @@ -264,7 +298,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 = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost());  				delete packetp;  				// Update the throttle @@ -273,7 +307,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 =  doSendPacket(h_socket, send_buffer, buf_size, host );  				packet_size = buf_size;  				// Update the throttle @@ -311,3 +345,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL  	return status;  } + +BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) +{ +	 +	if (!LLSocks::isEnabled()) +	{ +		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort()); +	} + +	proxywrap_t *socks_header = (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+10, send_buffer, buf_size); + +	return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size+10, LLSocks::getInstance()->getUDPProxy().getAddress(), LLSocks::getInstance()->getUDPProxy().getPort()); +} diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index e6409d2048..2fe2f8e1e9 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -82,6 +82,9 @@ protected:  	LLHost mLastSender;  	LLHost mLastReceivingIF; + +	BOOL doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); +	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE];  }; diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp new file mode 100644 index 0000000000..8a63287f22 --- /dev/null +++ b/indra/llmessage/llsocks5.cpp @@ -0,0 +1,218 @@ +/** + * @file llsocks5.cpp + * @brief Socks 5 implementation + * + * $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 <string> + +#include "linden_common.h" +#include "net.h" +#include "llhost.h" +#include "message.h" +#include "llsocks5.h" + +// Static class variable instances + +// We want this to be static to avoid excessive indirection on every +// incomming packet just to do a simple bool test. The getter for this +// member is also static +bool LLSocks::sUdpProxyEnabled; +bool LLSocks::sHttpProxyEnabled; + +LLSocks::LLSocks() +{ +    sUdpProxyEnabled  = false; +    sHttpProxyEnabled = false; +    hProxyControlChannel = 0; +    mProxyType = LLPROXY_SOCKS; +} + +// Perform a Socks5 authentication and UDP assioacation to the proxy +// specified by proxy, and assiocate UDP port message_port +int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) +{ +    int 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     = mAuthMethodSelected; // send only the selected metho + +    result = tcp_handshake(hProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request_t), (char*)&socks_auth_response, sizeof(socks_auth_response_t)); +    if (result != 0) +    { +        llwarns << "Socks authentication request failed, error on TCP control channel : " << result << llendl; +        stopProxy(); +        return SOCKS_CONNECT_ERROR; +    } +     +    if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE) +    { +        llwarns << "Socks5 server refused all our authentication methods" << llendl; +        stopProxy(); +        return SOCKS_NOT_ACCEPTABLE; +    } + +    // SOCKS5 USERNAME/PASSWORD authentication +    if (socks_auth_response.method == METHOD_PASSWORD) +    { +        // The server has requested a username/password combination +        U32 request_size = mSocksUsername.size() + mSocksPassword.size() + 3; +        char * password_auth = (char *)malloc(request_size); +        password_auth[0] = 0x01; +        password_auth[1] = mSocksUsername.size(); +        memcpy(&password_auth[2],mSocksUsername.c_str(), mSocksUsername.size()); +        password_auth[mSocksUsername.size()+2] = mSocksPassword.size(); +        memcpy(&password_auth[mSocksUsername.size()+3], mSocksPassword.c_str(), mSocksPassword.size()); + +        authmethod_password_reply_t password_reply; + +        result = tcp_handshake(hProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t)); +        free (password_auth); + +        if (result != 0) +        { +        llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl; +            stopProxy(); +            return SOCKS_CONNECT_ERROR; +        } + +        if (password_reply.status != AUTH_SUCCESS) +        { +            llwarns << "Socks authentication failed" << llendl; +            stopProxy(); +            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.flag    = FIELD_RESERVED; +    connect_request.atype   = ADDRESS_IPV4; +    connect_request.address = 0; // 0.0.0.0 We are not fussy about address +                                 // UDP is promiscious receive for our protocol +    connect_request.port    = 0; // Port must be 0 if you ever want to connect via NAT and your router does port rewrite for you + +    result = tcp_handshake(hProxyControlChannel, (char*)&connect_request, sizeof(socks_command_request_t), (char*)&connect_reply, sizeof(socks_command_response_t)); +    if (result != 0) +    { +        llwarns << "Socks connect request failed, error on TCP control channel : " << result << llendl; +        stopProxy(); +        return SOCKS_CONNECT_ERROR; +    } + +    if (connect_reply.reply != REPLY_REQUEST_GRANTED) +    { +        //Something went wrong +        llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl; +        stopProxy(); +        return SOCKS_UDP_FWD_NOT_GRANTED; +    } + +    mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order +    mUDPProxy.setAddress(proxy.getAddress()); +    // All good now we have been given the UDP port to send requests that need forwarding. +    llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl; +    return SOCKS_OK; +} + +int LLSocks::startProxy(LLHost proxy, U32 message_port) +{ +    int status; + +    mTCPProxy   = proxy; + +    if (hProxyControlChannel) +    { +        tcp_close_channel(hProxyControlChannel); +        hProxyControlChannel=0; +    } + +    hProxyControlChannel = tcp_open_channel(proxy);	 +    if (hProxyControlChannel == -1) +    { +        return SOCKS_HOST_CONNECT_FAILED; +    } + +    status = proxyHandshake(proxy, message_port);	 +    if (status == SOCKS_OK) +    { +        sUdpProxyEnabled=true; +    } +    return status; +} + +int LLSocks::startProxy(std::string host, U32 port) +{ +        mTCPProxy.setHostByName(host); +        mTCPProxy.setPort(port); +        return startProxy(mTCPProxy, (U32)gMessageSystem->mPort); +} + +void LLSocks::stopProxy() +{ +    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 == mProxyType) +    { +        sHttpProxyEnabled = false; +    } + +    if (hProxyControlChannel) +    { +        tcp_close_channel(hProxyControlChannel); +        hProxyControlChannel=0; +    } +} + +void LLSocks::setAuthNone() +{ +    mAuthMethodSelected = METHOD_NOAUTH; +} + +void LLSocks::setAuthPassword(std::string username, std::string password) +{ +    mAuthMethodSelected = METHOD_PASSWORD; +    mSocksUsername      = username; +    mSocksPassword      = password; +} + +void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type) +{  +    sHttpProxyEnabled = true;  +    mHTTPProxy        = httpHost;  +    mProxyType        = type; +} diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h new file mode 100644 index 0000000000..a78acb8b23 --- /dev/null +++ b/indra/llmessage/llsocks5.h @@ -0,0 +1,237 @@ +/** + * @file llsocks5.h + * @brief Socks 5 implementation + * + * $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_SOCKS5_H +#define LL_SOCKS5_H + +#include "llhost.h" +#include "llmemory.h" +#include "llsingleton.h" +#include <string> + +// 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 + +#ifndef MAXHOSTNAMELEN +#define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */ +#endif + +#define SOCKS_VERSION 0x05 // we are using socks 5 + +// 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 { +    unsigned char octects[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 replys +#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 socks5 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) + +// Socks5 command packet +struct socks_command_request_t { +    unsigned char version; +    unsigned char command; +    unsigned char flag; +    unsigned char atype; +    U32           address; +    U16           port; +}; + +// Standard socks5 reply packet +struct socks_command_response_t { +    unsigned char version; +    unsigned char reply; +    unsigned char flag; +    unsigned char atype; +    unsigned char add_bytes[4]; +    U16           port; +}; + +#define AUTH_NOT_ACCEPTABLE 0xFF // reply if prefered methods are not avaiable +#define AUTH_SUCCESS        0x00 // reply if authentication successfull + +// socks 5 authentication request, stating which methods the client supports +struct socks_auth_request_t { +    unsigned char version; +    unsigned char num_methods; +    unsigned char methods; // We are only using a single method currently +}; + +// socks 5 authentication response packet, stating server prefered method +struct socks_auth_response_t { +    unsigned char version; +    unsigned char method; +}; + +// socks 5 password reply packet +struct authmethod_password_reply_t { +    unsigned char version; +    unsigned char 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 +}; + +class LLSocks: public LLSingleton<LLSocks> +{ +public: +    LLSocks(); + +    // Start a connection to the socks 5 proxy +    int startProxy(std::string host,U32 port); +    int startProxy(LLHost proxy,U32 messagePort); + +    // Disconnect and clean up any connection to the socks 5 proxy +    void stopProxy(); + +    // Set up to use Password auth when connecting to the socks proxy +    void setAuthPassword(std::string username,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() { return mAuthMethodSelected; }; + +    // static check for enabled status for UDP packets +    static bool isEnabled(){return sUdpProxyEnabled;}; + +    // static check for enabled status for http packets +    static bool isHttpProxyEnabled(){return sHttpProxyEnabled;}; + +    // Proxy http packets via httpHost, which can be a Socks5 or a http proxy +    // as specified in type +    void EnableHttpProxy(LLHost httpHost,LLHttpProxyType type); + +    // Stop proxying http packets +    void DisableHttpProxy() {sHttpProxyEnabled = false;}; + +    // get the UDP proxy address and port +    LLHost getUDPProxy(){return mUDPProxy;}; + +    // get the socks 5 TCP control channel address and port +    LLHost getTCPProxy(){return mTCPProxy;}; + +    //get the http proxy address and port +    LLHost getHTTPProxy(){return mHTTPProxy;}; + +    // get the currently selected http proxy type +    LLHttpProxyType getHttpProxyType(){return mProxyType;}; + +    //Get the username password in a curl compatible format +    std::string getProxyUserPwd(){ return (mSocksUsername + ":" + mSocksPassword);}; + +private: + +    // Open a communication channel to the socks5 proxy proxy, at port messagePort +    int proxyHandshake(LLHost proxy,U32 messagePort); + +    // socket handle to proxy tcp control channel +    S32 hProxyControlChannel; + +    // is the UDP proxy enabled +    static bool sUdpProxyEnabled; +    // is the http proxy enabled +    static bool sHttpProxyEnabled; + +    // currently selected http proxy type +    LLHttpProxyType mProxyType; + +    // UDP proxy address and port +    LLHost mUDPProxy; +    // TCP Proxy control channel address and port +    LLHost mTCPProxy; +    // HTTP proxy address and port +    LLHost mHTTPProxy; + +    // socks 5 auth method selected +    LLSocks5AuthType mAuthMethodSelected; + +    // socks 5 username +    std::string mSocksUsername; +    // socks 5 password +    std::string mSocksPassword; +}; + +#endif diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 97611c3b51..ab5c1950c6 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -50,6 +50,7 @@  #include "lltimer.h"  #include "indra_constants.h" +#include "llsocks5.h"  // Globals  #if LL_WINDOWS @@ -189,6 +190,90 @@ U32 ip_string_to_u32(const char* ip_string)  #if LL_WINDOWS +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen) +{ +	int result; +	result = send(handle, dataout, outlen, 0); +	if (result != outlen) +	{ +		S32 err = WSAGetLastError(); +		llwarns << "Error sending data to proxy control channel, number of bytes sent were " << result << " error code was " << err << llendl; +		return -1; +	} + +	result = recv(handle, datain, maxinlen, 0); +	if (result != maxinlen) +	{ +		S32 err = WSAGetLastError(); +		llwarns << "Error receiving data from proxy control channel, number of bytes received were " << result << " error code was " << err << llendl; +		return -1; +	} + +	return 0; +} + +S32 tcp_open_channel(LLHost host) +{ +	// Open a TCP channel +	// Jump through some hoops to ensure that if the request hosts is down +	// or not reachable connect() does not block + +	S32 handle; +	handle = socket(AF_INET, SOCK_STREAM, 0); +	if (!handle) +	{ +		llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; +		return -1; +	} + +	struct sockaddr_in address; +	address.sin_port        = htons(host.getPort()); +	address.sin_family      = AF_INET; +	address.sin_addr.s_addr = host.getAddress(); + +	// Non blocking  +	WSAEVENT hEvent=WSACreateEvent(); +	WSAEventSelect(handle, hEvent, FD_CONNECT) ; +	connect(handle, (struct sockaddr*)&address, sizeof(address)) ; +	// Wait fot 5 seconds, if we can't get a TCP channel open in this +	// time frame then there is something badly wrong. +	WaitForSingleObject(hEvent, 1000*5); // 5 seconds time out + +	WSANETWORKEVENTS netevents; +	WSAEnumNetworkEvents(handle,hEvent,&netevents); + +	// Check the async event status to see if we connected +	if ((netevents.lNetworkEvents & FD_CONNECT) == FD_CONNECT) +	{ +		if (netevents.iErrorCode[FD_CONNECT_BIT] != 0) +		{ +			llwarns << "Unable to open TCP channel, WSA returned an error code of " << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; +			WSACloseEvent(hEvent); +			return -1; +		} + +		// Now we are connected disable non blocking +		// we don't need support an async interface as +		// currently our only consumer (socks5) will make one round +		// of packets then just hold the connection open +		WSAEventSelect(handle, hEvent, NULL) ; +		unsigned long NonBlock = 0; +		ioctlsocket(handle, FIONBIO, &NonBlock); + +		return handle; +	} + +	llwarns << "Unable to open TCP channel, Timeout is the host up?" << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; +	return -1; +} + +void tcp_close_channel(S32 handle) +{ +	llinfos << "Closing TCP channel" << llendl; +	shutdown(handle, SD_BOTH); +	closesocket(handle); +} +  S32 start_net(S32& socket_out, int& nPort)   {			  	// Create socket, make non-blocking @@ -385,6 +470,77 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i  #else + +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen) +{ +	if (send(handle, dataout, outlen, 0) != outlen) +	{ +		llwarns << "Error sending data to proxy control channel" << llendl; +		return -1; +	} + +	if (recv(handle, datain, maxinlen, 0) != maxinlen) +	{ +		llwarns << "Error receiving data to proxy control channel" << llendl;		 +		return -1; +	} + +	return 0; +} + +S32 tcp_open_channel(LLHost host) +{ +	S32 handle; +	handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +	if (!handle) +	{ +		llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; +		return -1; +	} + +	struct sockaddr_in address; +	address.sin_port        = htons(host.getPort()); +	address.sin_family      = AF_INET; +	address.sin_addr.s_addr = host.getAddress(); + +	// Set the socket to non blocking for the connect() +	int flags = fcntl(handle, F_GETFL, 0); +	fcntl(handle, F_SETFL, flags | O_NONBLOCK); + +	S32 error = connect(handle, (sockaddr*)&address, sizeof(address)); +	if (error && (errno != EINPROGRESS)) +	{ +			llwarns << "Unable to open TCP channel, error code: " << errno << llendl; +			return -1; +	} + +	struct timeval timeout; +	timeout.tv_sec  = 5; // Maximum time to wait for the connect() to complete +	timeout.tv_usec = 0; +	fd_set fds; +	FD_ZERO(&fds); +	FD_SET(handle, &fds); + +	// See if we have connectde or time out after 5 seconds +	U32 rc = select(sizeof(fds)*8, NULL, &fds, NULL, &timeout);	 +	 +	if (rc != 1) // we require exactly one descriptor to be set +	{ +			llwarns << "Unable to open TCP channel" << llendl; +			return -1; +	} + +	// Return the socket to blocking operations +	fcntl(handle, F_SETFL, flags); + +	return handle; +} + +void tcp_close_channel(S32 handle) +{ +	close(handle); +} +  //  Create socket, make non-blocking  S32 start_net(S32& socket_out, int& nPort)  { diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index 9f4f5c5821..d93ed20c98 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -52,6 +52,11 @@ U32		get_sender_ip(void);  LLHost  get_receiving_interface();  U32		get_receiving_interface_ip(void); +// Some helpful tcp functions added for the socks 5 proxy support +S32 tcp_open_channel(LLHost host); // Open a tcp channel to a given host +void tcp_close_channel(S32 handle); // Close an open tcp channel +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen); // Do a TCP data handshake +  const char*	u32_to_ip_string(U32 ip);					// Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls   char*		u32_to_ip_string(U32 ip, char *ip_string);	// NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars  U32			ip_string_to_u32(const char* ip_string);	// Wrapper for inet_addr() diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index fc7fd2dd8a..871fd7eb97 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -796,6 +796,83 @@        <key>Value</key>        <integer>5</integer>      </map> +    <key>Socks5ProxyEnabled</key> +    <map> +      <key>Comment</key> +      <string>Use Socks5 Proxy</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>Socks5HttpProxyType</key> +    <map> +      <key>Comment</key> +      <string>Proxy type to use for HTTP operations</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>Socks</string> +    </map> +    <key>Socks5ProxyHost</key> +    <map> +      <key>Comment</key> +      <string>Socks 5 Proxy Host</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>64.79.219.97</string> +    </map> +    <key>Socks5ProxyPort</key> +    <map> +      <key>Comment</key> +      <string>Socks 5 Proxy Port</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>U32</string> +      <key>Value</key> +      <integer>1080</integer> +    </map> +     <key>Socks5Username</key> +    <map> +      <key>Comment</key> +      <string>Socks 5 Username</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map> +    <key>Socks5Password</key> +    <map> +      <key>Comment</key> +      <string>Socks 5 Password</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map> +    <key>Socks5AuthType</key> +    <map> +      <key>Comment</key> +      <string>Selected Auth mechanism for Socks5</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>None</string> +    </map>      <key>BuildAxisDeadZone0</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 60a2f813aa..b49026de38 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -105,6 +105,7 @@  #include "llviewermedia.h"  #include "llpluginclassmedia.h"  #include "llteleporthistorystorage.h" +#include "llsocks5.h"  #include "lllogininstance.h"        // to check if logged in yet  #include "llsdserialize.h" @@ -342,6 +343,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)  	mCommitCallbackRegistrar.add("Pref.getUIColor",				boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2));  	mCommitCallbackRegistrar.add("Pref.MaturitySettings",		boost::bind(&LLFloaterPreference::onChangeMaturity, this));  	mCommitCallbackRegistrar.add("Pref.BlockList",				boost::bind(&LLFloaterPreference::onClickBlockList, this)); +    mCommitCallbackRegistrar.add("Pref.Proxy",                    boost::bind(&LLFloaterPreference::onClickProxySettings, this));  	sSkin = gSavedSettings.getString("SkinCurrent"); @@ -615,6 +617,12 @@ void LLFloaterPreference::cancel()  		updateDoubleClickControls();  		mDoubleClickActionDirty = false;  	} +    LLFloaterPreferenceProxy * advanced_socks_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_socks5_advanced"); +    if(advanced_socks_settings) +    { +        advanced_socks_settings->cancel(); +    } +      }  void LLFloaterPreference::onOpen(const LLSD& key) @@ -1535,6 +1543,11 @@ void LLFloaterPreference::updateDoubleClickSettings()  	}  } +void LLFloaterPreference::onClickProxySettings() +{ +    LLFloaterReg::showInstance("prefs_proxy"); +} +  void LLFloaterPreference::updateDoubleClickControls()  {  	// check is one of double-click actions settings enabled @@ -1902,3 +1915,161 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()  	resetDirtyChilds();  	LLPanelPreference::setHardwareDefaults();  } + + +/* ------------------------------------------------------------ */ + +LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) +    : LLFloater(key), +    mSocksSettingsDirty(false) +{ +    mCommitCallbackRegistrar.add("Proxy.OK",                boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); +    mCommitCallbackRegistrar.add("Proxy.Cancel",            boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); +    mCommitCallbackRegistrar.add("Proxy.Change",            boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); +} + +LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() +{ +} + +BOOL LLFloaterPreferenceProxy::postBuild() +{ +    LLLineEditor* edit = getChild<LLLineEditor>("socks_password_editor"); +    if (edit) edit->setDrawAsterixes(TRUE); + +    LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); +    if(socksAuth->getSelectedValue().asString() == "None") +    { +        getChild<LLLineEditor>("socks5_username")->setEnabled(false); +        getChild<LLLineEditor>("socks5_password")->setEnabled(false); +    } + +    center(); +    return TRUE; +} + +void LLFloaterPreferenceProxy::onOpen(const LLSD& key) +{ +    saveSettings(); +} + +void LLFloaterPreferenceProxy::onClose(bool app_quitting) +{ +    if(mSocksSettingsDirty) +    { + +        // If the user plays with the Socks proxy settings after login, its only fair we let them know +        // it will not be updated untill next restart. +        if(LLStartUp::getStartupState()>STATE_LOGIN_WAIT) +        {         +            if(this->mSocksSettingsDirty == true ) +            { +                LLNotifications::instance().add("ChangeSocks5Settings",LLSD(),LLSD()); +                mSocksSettingsDirty = false; // we have notified the user now be quiet again +            } +        } +    } +} + +void LLFloaterPreferenceProxy::saveSettings() +{ +    // Save the value of all controls in the hierarchy +    mSavedValues.clear(); +    std::list<LLView*> view_stack; +    view_stack.push_back(this); +    while(!view_stack.empty()) +    { +        // Process view on top of the stack +        LLView* curview = view_stack.front(); +        view_stack.pop_front(); + +        LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); +        if (ctrl) +        { +            LLControlVariable* control = ctrl->getControlVariable(); +            if (control) +            { +                mSavedValues[control] = control->getValue(); +            } +        } +                     +        // Push children onto the end of the work stack +        for (child_list_t::const_iterator iter = curview->getChildList()->begin(); +             iter != curview->getChildList()->end(); ++iter) +        { +            view_stack.push_back(*iter); +        } +    }     + +} + +void LLFloaterPreferenceProxy::onBtnOk() +{ +    // commit any outstanding text entry +    if (hasFocus()) +    { +        LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); +        if (cur_focus && cur_focus->acceptsTextInput()) +        { +            cur_focus->onCommit(); +        } +    } +    closeFloater(false); +} + +void LLFloaterPreferenceProxy::onBtnCancel() +{ +    if (hasFocus()) +    { +        LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); +        if (cur_focus && cur_focus->acceptsTextInput()) +        { +            cur_focus->onCommit(); +        } +        refresh(); +    } +     +    cancel(); +     +} +void LLFloaterPreferenceProxy::cancel() +{ + +    for (control_values_map_t::iterator iter =  mSavedValues.begin(); +         iter !=  mSavedValues.end(); ++iter) +    { +        LLControlVariable* control = iter->first; +        LLSD ctrl_value = iter->second; +        control->set(ctrl_value); +    } +     +    closeFloater(); +} + +void LLFloaterPreferenceProxy::onChangeSocksSettings()  +{ +    mSocksSettingsDirty = true;  + +    LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); +    if(socksAuth->getSelectedValue().asString() == "None") +    { +        getChild<LLLineEditor>("socks5_username")->setEnabled(false); +        getChild<LLLineEditor>("socks5_password")->setEnabled(false); +    } +    else +    { +        getChild<LLLineEditor>("socks5_username")->setEnabled(true); +        getChild<LLLineEditor>("socks5_password")->setEnabled(true); +    } + +    //Check for invalid states for the other http proxy radio +    LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_selection"); +    if( (otherHttpProxy->getSelectedValue().asString() == "Socks" &&  +        getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == FALSE )||( +        otherHttpProxy->getSelectedValue().asString() == "Web" &&  +        getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == FALSE ) ) +    {     +        otherHttpProxy->selectFirstItem(); +    } + +};
\ No newline at end of file diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index ef92575347..4a180ce0f7 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -155,6 +155,7 @@ public:  	void applyResolution();  	void onChangeMaturity();  	void onClickBlockList(); +	void onClickProxySettings();  	void applyUIColor(LLUICtrl* ctrl, const LLSD& param);  	void getUIColor(LLUICtrl* ctrl, const LLSD& param); @@ -228,4 +229,33 @@ protected:  }; +class LLFloaterPreferenceProxy : public LLFloater +{ +public:  +	LLFloaterPreferenceProxy(const LLSD& key); +	~LLFloaterPreferenceProxy(); + +	/// show off our menu +	static void show(); +	void cancel(); +	 +protected: +	BOOL postBuild(); +	void onOpen(const LLSD& key); +	void onClose(bool app_quitting); +	void saveSettings(); +	void onBtnOk(); +	void onBtnCancel(); + +	void onChangeSocksSettings(); + +private: +	 +	bool mSocksSettingsDirty; +	typedef std::map<LLControlVariable*, LLSD> control_values_map_t; +	control_values_map_t mSavedValues; + +}; + +  #endif  // LL_LLPREFERENCEFLOATER_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 86b09473ab..d54c5b177a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -191,6 +191,8 @@  #include "llevents.h"  #include "llstartuplistener.h" +#include "llsocks5.h" +  #if LL_WINDOWS  #include "lldxhardware.h"  #endif @@ -390,7 +392,7 @@ bool idle_startup()  		gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());  		// load dynamic GPU/feature tables from website (S3) -		LLFeatureManager::getInstance()->fetchHTTPTables(); +		//LLFeatureManager::getInstance()->fetchHTTPTables();  		std::string xml_file = LLUI::locateSkin("xui_version.xml");  		LLXMLNodePtr root; @@ -593,6 +595,15 @@ bool idle_startup()  		LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;  		//------------------------------------------------- +		// Init the socks 5 proxy and open the control TCP  +		// connection if the user is using SOCKS5 +		// We need to do this early incase the user is using +		// socks for http so we get the login screen via socks +		//------------------------------------------------- + +		LLStartUp::handleSocksProxy(false); + +		//-------------------------------------------------  		// Init audio, which may be needed for prefs dialog  		// or audio cues in connection UI.  		//------------------------------------------------- @@ -807,6 +818,27 @@ bool idle_startup()  	if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())  	{ +		// Post login screen, we should see if any settings have changed that may +		// require us to either start/stop or change the socks proxy. As various communications +		// past this point may require the proxy to be up. +		if ( gSavedSettings.getBOOL("Socks5ProxyEnabled") ) +		{ +			if (!LLStartUp::handleSocksProxy(true)) +			{ +				// Proxy start up failed, we should now bail the state machine +				// HandleSocksProxy() will have reported an error to the user  +				// already, so we just go back to the login screen. The user +				// could then change the preferences to fix the issue.  +				LLStartUp::setStartupState(STATE_LOGIN_SHOW); +				return FALSE; +			} +		} +		else +		{ +			LLSocks::getInstance()->stopProxy(); +		} +		 +  		//reset the values that could have come in from a slurl  		// DEV-42215: Make sure they're not empty -- gUserCredential  		// might already have been set from gSavedSettings, and it's too bad @@ -2728,6 +2760,95 @@ void LLStartUp::setStartSLURL(const LLSLURL& slurl)      }  } +bool LLStartUp::handleSocksProxy(bool reportOK) +{ +	std::string httpProxyType = gSavedSettings.getString("Socks5HttpProxyType"); + +	// Determine the http proxy type (if any) +	if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) +	{ +		LLHost httpHost; +		httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); +		httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort")); +		LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_HTTP); +	} +	else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) +	{ +		LLHost httpHost; +		httpHost.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); +		httpHost.setPort(gSavedSettings.getU32("Socks5ProxyPort")); +		LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_SOCKS); +	} +	else +	{ +		LLSocks::getInstance()->DisableHttpProxy(); +	} +	 +	bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled"); +	if (use_socks_proxy) +	{	 + +		// Determine and update LLSocks with the saved authentication system +		std::string auth_type = gSavedSettings.getString("Socks5AuthType"); +			 +		if (auth_type.compare("None") == 0) +		{ +			LLSocks::getInstance()->setAuthNone(); +		} + +		if (auth_type.compare("UserPass") == 0) +		{ +			LLSocks::getInstance()->setAuthPassword(gSavedSettings.getString("Socks5Username"),gSavedSettings.getString("Socks5Password")); +		} + +		// Start the proxy and check for errors +		int status = LLSocks::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort")); +		LLSD subs; +		LLSD payload; +		subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); +		subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + +		switch(status) +		{ +			case SOCKS_OK: +				return true; +				break; + +			case SOCKS_CONNECT_ERROR: // TCP Fail +				LLNotifications::instance().add("SOCKS_CONNECT_ERROR", subs,payload); +				break; + +			case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection +				LLNotifications::instance().add("SOCKS_NOT_PERMITTED", subs,payload); +				break; +					 +			case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server +				LLNotifications::instance().add("SOCKS_NOT_ACCEPTABLE", subs,payload); +				break; + +			case SOCKS_AUTH_FAIL: // Authentication failed +				LLNotifications::instance().add("SOCKS_AUTH_FAIL", subs,payload); +				break; + +			case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed +				LLNotifications::instance().add("SOCKS_UDP_FWD_NOT_GRANTED", subs,payload); +				break; + +			case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server +				LLNotifications::instance().add("SOCKS_HOST_CONNECT_FAILED", subs,payload); +				break;		 +		} + +		return false; +	} +	else +	{ +		LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up +	} + +	return true; +} +  bool login_alert_done(const LLSD& notification, const LLSD& response)  {  	LLPanelLogin::giveFocus(); diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index b3d9ef1dcc..a512ec7bff 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -113,6 +113,8 @@ public:  	static void setStartSLURL(const LLSLURL& slurl);   	static LLSLURL& getStartSLURL() { return sStartSLURL; }  +	static bool handleSocksProxy(bool reportOK); //handle kicking the socks 5 proxy code at startup time +  private:  	static LLSLURL sStartSLURL; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index a1c2c926af..7a078a8b53 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -230,6 +230,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostcard>);  	LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); +	LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);  	LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);  	LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerms>);  	LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 257884d921..b3d899c61a 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -41,6 +41,8 @@  #include "llappviewer.h"  #include "lltrans.h" +#include "llsocks5.h" +  // Static instance of LLXMLRPCListener declared here so that every time we  // bring in this code, we instantiate a listener. If we put the static  // instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would @@ -307,16 +309,23 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	}  	mErrorCert = NULL; -	if (gSavedSettings.getBOOL("BrowserProxyEnabled")) +	if (LLSocks::getInstance()->isHttpProxyEnabled())  	{ -		mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); -		S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); - -		// tell curl about the settings -		mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress); +		std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); +		U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); +		mCurlRequest->setoptString(CURLOPT_PROXY, address.c_str());  		mCurlRequest->setopt(CURLOPT_PROXYPORT, port); +		if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) +		{ +			mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); +			if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) +				mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); +		} +		else +		{  		mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);  	} +	}  //	mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging  	mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); diff --git a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml new file mode 100644 index 0000000000..bb9ade067b --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="490" + layout="topleft" + name="Socks5 Advanced Settings Floater" + help_topic="hardware_settings_floater" + title="Socks5 proxy advanced settings" + width="385"> +    <check_box +     control_name="BrowserProxyEnabled" +     top="30" +     enabled="true" +     follows="left|top" +     height="14" +     initial_value="false" +     commit_callback.function="Proxy.Change" +     label="Use HTTP Proxy for Web pages" +     left_delta="10" +     mouse_opaque="true" +     name="web_proxy_enabled" +     radio_style="false" +     width="400" +     top_pad="5" /> +    <check_box +     control_name="Socks5ProxyEnabled" +     height="16" +     label="Use Socks 5 Proxy for UDP traffic" +     layout="topleft" +     left_delta="0" +     name="socks_proxy_enabled" +     top_pad="5" +     width="256" +     commit_callback.function="Proxy.Change" /> +    <text +     type="string" +     length="1" +     follows="left|top" +     height="10" +     layout="topleft" +     left="10" +     name="Proxy location" +     top_delta="30" +     width="300"> +        Other Http traffic proxy: +     </text> +     <radio_group +      control_name="Socks5HttpProxyType" +      height="60" +      layout="topleft" +      name="other_http_proxy_selection" +      top_pad="10" +      width="120" +      border="1" +      left_delta="10"  +      commit_callback.function="Proxy.Change" > +          <radio_item +           height="16" +           label="Do not proxy" +           layout="topleft" +           value="None" +           width="120" +           tool_tip="Non web Http trafic should NOT be sent to any proxy."/> +          <radio_item +           height="16" +           label="Use Socks 5 Proxy" +           layout="topleft" +           value="Socks" +           width="120" +           enabled_control="Socks5ProxyEnabled" +           tool_tip="Non-web Http will be sent to the configured Socks 5 proxy."/> +          <radio_item +           height="16" +           label="Use Http Proxy" +           layout="topleft" +           value="Web" +           width="120" +           enabled_control="BrowserProxyEnabled" +           tool_tip="Non-web Http will be sent to the configured Web proxy." /> +    </radio_group> +    <text +	 type="string" +	 length="1" +	 follows="left|top" +	 height="10" +	 left="15" +	 layout="topleft" +	 name="Proxy location" +	 top_delta="82" +	 width="300"> +	    HTTP Proxy: +	</text> +	<line_editor +	 control_name="BrowserProxyAddress" +	 enabled_control="BrowserProxyEnabled" +     follows="left|top" +	 font="SansSerif" +	 height="23" +	 layout="topleft" +	 left_delta="0" +	 name="web_proxy_editor" +	 tool_tip="The DNS name or IP address of the HTTP proxy you would like to use." +	 top_pad="4" +	 width="200" /> +	<spinner +	 control_name="BrowserProxyPort" +	 enabled_control="BrowserProxyEnabled" +     decimal_digits="0" +	 follows="left|top" +	 height="23" +	 increment="1" +	 initial_value="80" +	 label="Port number:" +	 label_width="95" +	 layout="topleft" +	 left_delta="210" +	 max_val="12000" +	 min_val="10" +	 name="web_proxy_port" +	 top_delta="0" +      tool_tip="The port of the HTTP proxy you would like to use." +	 width="145" /> +	<text +	 type="string" +	 length="1" +	 follows="left|top" +	 height="10" +	 layout="topleft" +	 left="15" +	 name="Proxy location" +	 top_delta="32" +	 width="300"> +	    SOCKS 5 Proxy: +	</text> +	<line_editor +	 control_name="Socks5ProxyHost" +	 enabled_control="Socks5ProxyEnabled" +	 follows="left|top" +	 font="SansSerif" +	 height="23" +	 layout="topleft" +	 left_delta="0" +	 name="socks_proxy_editor" +	 tool_tip="The DNS name or IP address of the SOCKS 5 proxy you would like to use." +	 top_pad="4" +	 width="200" +	 commit_callback.function="Proxy.Change" /> +	<spinner +	 control_name="Socks5ProxyPort" +	 enabled_control="Socks5ProxyEnabled" +	 decimal_digits="0" +	 follows="left|top" +	 height="23" +	 increment="1" +	 initial_value="80" +	 label="Port number:" +	 label_width="95" +	 layout="topleft" +	 left_delta="210" +	 max_val="12000" +	 min_val="10" +	 name="socks_proxy_port" +	 top_delta="0" +	 width="145" +     tool_tip="The port of the SOCKS 5 proxy you would like to use." +	 commit_callback.function="Pref.SocksProxy" /> +	<text +     type="string" +     length="1" +     follows="left|top" +     height="10" +     layout="topleft" +     left="16" +     name="Proxy location" +     top_delta="35" +     width="300"> +	    Authentication: +	</text> +	<radio_group +	 control_name="Socks5AuthType" +	 enabled_control="Socks5ProxyEnabled" +	 height="50" +	 layout="topleft" +	 name="socks5_auth_type" +	 top_pad="10" +	 width="120" +	 border="1" +	 commit_callback.function="Proxy.Change" > +	    <radio_item +		 height="16" +		 label="No Authentication" +		 layout="topleft" +		 name="Socks5NoAuth" +		 value="None" +		 tool_tip="Socks5 proxy requires no authentication."/> +		 width="120" /> +		<radio_item +		 height="16" +		 label="Username/Password" +		 layout="topleft" +		 name="Socks5UserPass" +		 value="UserPass" +		 tool_tip="Socks5 proxy requires username/password authentication."/> +		 width="120" /> +	</radio_group> +	<text +	 type="string" +	 length="1" +	 follows="left|top" +	 height="10" +	 layout="topleft" +	 left_delta="20" +	 top_delta="50" +	 width="300"> +	    Username: +	</text> +	<line_editor +	 control_name="Socks5Username" +	 follows="left|top" +	 font="SansSerif" +	 height="23" +	 layout="topleft" +	 left_delta="0" +	 name="socks5_username" +	 tool_tip="The username used to authenticate with your SOCKS 5 server" +	 top_pad="4" +	 width="200" +	 commit_callback.function="Proxy.Change" /> +	<text +	 type="string" +	 length="1" +	 follows="left|top" +	 height="10" +	 layout="topleft" +	 left_delta="0" +	 top_delta="30" +	 width="300"> +	    Password: +	</text> +	<line_editor +	 control_name="Socks5Password" +	 follows="left|top" +	 font="SansSerif" +	 height="23" +	 layout="topleft" +	 left_delta="0" +	 name="socks5_password" +	 tool_tip="The password used to authenticate with your SOCKS 5 server" +	 top_pad="4" +	 width="200" +	 commit_callback.function="Proxy.Change" /> +	<button +	 follows="left|top" +	 height="22" +	 label="OK" +	 label_selected="OK" +	 layout="topleft" +	 right="275" +	 name="OK" +	 top_delta="53" +	 width="90" +	 commit_callback.function="Proxy.OK" /> +	<button +	 follows="left|top" +	 height="22" +	 label="Cancel" +	 label_selected="Cancel" +	 layout="topleft" +	 right="375" +	 name="Cancel" +	 top_delta="0" +	 width="90" +	 commit_callback.function="Proxy.Cancel" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ce96c488b4..815e8f96ab 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7159,6 +7159,76 @@ Click and drag anywhere on the world to rotate your view    </notification>    <notification +   icon="alertmodal.tga" +   name="SOCKS_NOT_PERMITTED" +   type="alertmodal"> +	The Socks5 proxy "[HOST]:[PORT]" refused the connection, not allowed by rule set +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SOCKS_CONNECT_ERROR" +   type="alertmodal"> +	The Socks5 proxy "[HOST]:[PORT]" refused the connection, could not open TCP channel +   <usetemplate +     name="okbutton" +     yestext="OK"/>	  +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SOCKS_NOT_ACCEPTABLE" +   type="alertmodal"> +	The Socks5 proxy "[HOST]:[PORT]" refused the selected authentication system +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SOCKS_AUTH_FAIL" +   type="alertmodal"> +	The Socks5 proxy "[HOST]:[PORT]" reported your credentials are invalid +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SOCKS_UDP_FWD_NOT_GRANTED" +   type="alertmodal"> +	The Socks5 proxy "[HOST]:[PORT]" refused the UDP associate request +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SOCKS_HOST_CONNECT_FAILED" +   type="alertmodal"> +	Could not connect to Socks5 proxy server "[HOST]:[PORT]" +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="ChangeSocks5Settings" +   type="alert"> +	Socks 5 proxy settings take effect after you restart [APP_NAME]. +   <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification    name="AuthRequest"    type="browser">  The site at '<nolink>[HOST_NAME]</nolink>' in realm '[REALM]' requires a user name and password. diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 1c22a5c02e..d306e46d5e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -70,7 +70,7 @@     layout="topleft"     left="77"     name="connection_port_enabled" -   top_pad="20" +   top_pad="10"     width="256">      <check_box.commit_callback       function="Notification.Show" @@ -195,60 +195,6 @@      name="media_popup_enabled"      width="400"                 top_pad="5"/> -  <check_box -    top_delta="4" -    enabled="true" -    follows="left|top" -    height="14" -    initial_value="false" -    control_name="BrowserProxyEnabled" -    label="Enable Web Proxy" -    left_delta="0" -    mouse_opaque="true" -    name="web_proxy_enabled" -    radio_style="false" -    width="400"           top_pad="5"/> -  <text -   type="string" -   length="1" -   follows="left|top" -   height="10" -   layout="topleft" -   left_delta="20" -   name="Proxy location" -   top_delta="16" -   width="300"> -    Proxy location: -  </text> -  <line_editor -   control_name="BrowserProxyAddress" -   enabled_control="BrowserProxyEnabled" - follows="left|top" -   font="SansSerif" -   height="23" -   layout="topleft" -   left_delta="0" -   name="web_proxy_editor" -   tool_tip="The name or IP address of the proxy you would like to use" -   top_pad="4" -   width="200" /> -  <spinner -   control_name="BrowserProxyPort" -   enabled_control="BrowserProxyEnabled" - decimal_digits="0" -   follows="left|top" -   height="23" -   increment="1" -   initial_value="80" -   label="Port number:" -   label_width="95" -   layout="topleft" -   left_delta="210" -   max_val="12000" -   min_val="10" -   name="web_proxy_port" -   top_delta="0" -   width="145" />    <text       type="string"       length="1" @@ -286,4 +232,31 @@           name="Install_manual"           value="0" />    </combo_box> +  <text +     type="string" +     length="1" +     follows="left|top" +     height="10" +     layout="topleft" +     left="30" +     name="Software updates:" +     mouse_opaque="false" +     top_pad="5" +     width="300"> +		Proxy Settings: +  </text> +  <button +	label="Adjust proxy settings" +    follows="left|top" +    height="23" +	width="140"  +    label_selected="Browse" +    layout="topleft" +    left_delta="50" +    name="set_proxy" +    top_pad="5" +    > +		<button.commit_callback +		  function="Pref.Proxy" /> +  </button>  </panel>  | 
