diff options
author | Robin Cornelius <robin.cornelius@gmail.com> | 2011-03-28 11:20:06 +0100 |
---|---|---|
committer | Robin Cornelius <robin.cornelius@gmail.com> | 2011-03-28 11:20:06 +0100 |
commit | 74d9bf0d5525426feae4ea21e2a81034ddcf4d7f (patch) | |
tree | 5174ee85c5242295fa26c1b6da777932de27eba5 /indra | |
parent | b7b9a37bc13d40a3caf7ea77d6857c2bb6036e06 (diff) |
VWR-20801 Implement SOCKS 5 Proxy for the viewer
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llmessage/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llmessage/llcurl.cpp | 44 | ||||
-rw-r--r-- | indra/llmessage/llpacketring.cpp | 60 | ||||
-rw-r--r-- | indra/llmessage/llpacketring.h | 3 | ||||
-rw-r--r-- | indra/llmessage/llsocks5.cpp | 224 | ||||
-rw-r--r-- | indra/llmessage/llsocks5.h | 243 | ||||
-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 | 85 |
18 files changed, 1525 insertions, 66 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 1cad0f6d22..8c68d38926 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -74,6 +74,7 @@ set(llmessage_SOURCE_FILES llsdrpcserver.cpp llservicebuilder.cpp llservice.cpp + llsocks5.cpp llstoredmessage.cpp lltemplatemessagebuilder.cpp lltemplatemessagedispatcher.cpp @@ -172,6 +173,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 a485fa0160..020c0d6a4a 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -50,6 +50,8 @@ #include "llsdserialize.h" #include "llthread.h" +#include "llsocks5.h" + ////////////////////////////////////////////////////////////////////////////// /* The trick to getting curl to do keep-alives is to reuse the @@ -273,6 +275,28 @@ LLCurl::Easy* LLCurl::Easy::getEasy() // set no DMS caching as default for all easy handles. This prevents them adopting a // multi handles cache if they are added to one. curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); + + //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; } @@ -446,6 +470,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..1f458a007c --- /dev/null +++ b/indra/llmessage/llsocks5.cpp @@ -0,0 +1,224 @@ +/** + * @file llsocks5.cpp + * @brief Socks 5 implementation + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/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..83e311a962 --- /dev/null +++ b/indra/llmessage/llsocks5.h @@ -0,0 +1,243 @@ +/** + * @file llsocks5.h + * @brief Socks 5 implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/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 f0e28d4ae3..2b7b7b8484 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -774,6 +774,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 724096b443..a0d3852d30 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -103,6 +103,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" @@ -325,6 +326,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"); @@ -603,6 +605,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) @@ -1497,6 +1505,11 @@ void LLFloaterPreference::updateDoubleClickSettings() } } +void LLFloaterPreference::onClickProxySettings() +{ + LLFloaterReg::showInstance("prefs_proxy"); +} + void LLFloaterPreference::updateDoubleClickControls() { // check is one of double-click actions settings enabled @@ -1805,3 +1818,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 46014804ec..fd5454ebcf 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -154,6 +154,7 @@ public: void applyResolution(); void onChangeMaturity(); void onClickBlockList(); + void onClickProxySettings(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); @@ -225,4 +226,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 8fccb35886..f054bd11b8 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 @@ -393,7 +395,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; @@ -596,6 +598,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. //------------------------------------------------- @@ -809,6 +820,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 @@ -2746,6 +2778,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 dca1e33e60..976dc76b50 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -202,6 +202,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 ba13479860..751b038252 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7070,6 +7070,76 @@ Mute everyone? </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 901a1257e0..1a631293e7 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" @@ -102,7 +102,7 @@ left="80" mouse_opaque="false" name="cache_size_label_l" - top_pad="20" + top_pad="10" width="200"> Cache size </text> @@ -287,60 +287,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" @@ -378,4 +324,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> |