diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llmessage/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llmessage/llcurl.cpp | 43 | ||||
-rw-r--r-- | indra/llmessage/llpacketring.cpp | 63 | ||||
-rw-r--r-- | indra/llmessage/llpacketring.h | 3 | ||||
-rw-r--r-- | indra/llmessage/llsocks5.cpp | 216 | ||||
-rw-r--r-- | indra/llmessage/llsocks5.h | 240 | ||||
-rw-r--r-- | indra/llmessage/net.cpp | 98 | ||||
-rw-r--r-- | indra/llmessage/net.h | 12 | ||||
-rwxr-xr-x | indra/newview/app_settings/settings.xml | 77 | ||||
-rwxr-xr-x | indra/newview/llfloaterpreference.cpp | 168 | ||||
-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 | 27 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_preferences_proxy.xml | 274 | ||||
-rwxr-xr-x | 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, 1444 insertions, 88 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..32dd438e68 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..62aaca0672 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -28,13 +28,28 @@ #include "llpacketring.h" +#if LL_WINDOWS + #include <winsock2.h> +#else + #include <sys/socket.h> + #include <netinet/in.h> +#endif + // linden library includes #include "llerror.h" +#include "message.h" +#include "llsocks5.h" #include "lltimer.h" #include "timing.h" #include "llrand.h" #include "u64.h" + + + + + + /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : mUseInThrottle(FALSE), @@ -216,8 +231,30 @@ 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 = (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 +280,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 +301,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 +310,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 +348,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..27a31e35b3 --- /dev/null +++ b/indra/llmessage/llsocks5.cpp @@ -0,0 +1,216 @@ +/** + * @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 +// incoming 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; + mProxyControlChannel.reset(); + mProxyType = LLPROXY_SOCKS; +} + +// Perform a SOCKS 5 authentication and UDP association to the proxy +// specified by proxy, and associate 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 method. + + result = tcp_handshake(mProxyControlChannel, (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 << "SOCKS 5 server refused all our authentication methods" << llendl; + stopProxy(); + return SOCKS_NOT_ACCEPTABLE; + } + + // SOCKS 5 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 = new char[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(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t)); + delete[] 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.reserved = FIELD_RESERVED; + connect_request.atype = ADDRESS_IPV4; + connect_request.address = htonl(0); // 0.0.0.0 + connect_request.port = htons(0); // 0 + // "If the client is not in possesion of the information at the time of the UDP ASSOCIATE, + // the client MUST use a port number and address of all zeros. RFC 1928" + + result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(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 SOCKS 5 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 (mProxyControlChannel) + { + tcp_close_channel(mProxyControlChannel); + } + + mProxyControlChannel = tcp_open_channel(mTCPProxy); + if (!mProxyControlChannel) + { + 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 (mProxyControlChannel) + { + tcp_close_channel(mProxyControlChannel); + } +} + +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..43a7c82fea --- /dev/null +++ b/indra/llmessage/llsocks5.h @@ -0,0 +1,240 @@ +/** + * @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 { + U8 octets[4]; + U32 addr32; +}; + +// SOCKS 5 control channel commands +#define COMMAND_TCP_STREAM 0x01 +#define COMMAND_TCP_BIND 0x02 +#define COMMAND_UDP_ASSOCIATE 0x03 + +// SOCKS 5 command replies +#define REPLY_REQUEST_GRANTED 0x00 +#define REPLY_GENERAL_FAIL 0x01 +#define REPLY_RULESET_FAIL 0x02 +#define REPLY_NETWORK_UNREACHABLE 0x03 +#define REPLY_HOST_UNREACHABLE 0x04 +#define REPLY_CONNECTION_REFUSED 0x05 +#define REPLY_TTL_EXPIRED 0x06 +#define REPLY_PROTOCOL_ERROR 0x07 +#define REPLY_TYPE_NOT_SUPPORTED 0x08 + +#define FIELD_RESERVED 0x00 + +// The standard SOCKS 5 request packet +// Push current alignment to stack and set alignment to 1 byte boundary +// This enabled us to use structs directly to set up and receive network packets +// into the correct fields, without fear of boundary alignment causing issues +#pragma pack(push,1) + +// SOCKS 5 command packet +struct socks_command_request_t { + U8 version; + U8 command; + U8 reserved; + U8 atype; + U32 address; + U16 port; +}; + +// Standard SOCKS 5 reply packet +struct socks_command_response_t { + U8 version; + U8 reply; + U8 reserved; + U8 atype; + U8 add_bytes[4]; + U16 port; +}; + +#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available +#define AUTH_SUCCESS 0x00 // reply if authentication successful + +// SOCKS 5 authentication request, stating which methods the client supports +struct socks_auth_request_t { + U8 version; + U8 num_methods; + U8 methods; // We are only using a single method currently +}; + +// SOCKS 5 authentication response packet, stating server preferred method +struct socks_auth_response_t { + U8 version; + U8 method; +}; + +// SOCKS 5 password reply packet +struct authmethod_password_reply_t { + U8 version; + U8 status; +}; + +// SOCKS 5 UDP packet header +struct proxywrap_t { + U16 rsv; + U8 frag; + U8 atype; + U32 addr; + U16 port; +}; + +#pragma pack(pop) /* restore original alignment from stack */ + + +// Currently selected http proxy type +enum LLHttpProxyType +{ + LLPROXY_SOCKS = 0, + LLPROXY_HTTP = 1 +}; + +// Auth types +enum LLSocks5AuthType +{ + METHOD_NOAUTH = 0x00, // Client supports no auth + METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported) + METHOD_PASSWORD = 0x02 // Client supports username/password +}; + +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() const { 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 SOCKS 5 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() const { return mUDPProxy; } + + // Get the SOCKS 5 TCP control channel address and port + LLHost getTCPProxy() const { return mTCPProxy; } + + // Get the HTTP proxy address and port + LLHost getHTTPProxy() const { return mHTTPProxy; } + + // Get the currently selected HTTP proxy type + LLHttpProxyType getHTTPProxyType() const { return mProxyType; } + + // Get the username password in a curl compatible format + std::string getProxyUserPwd() const { return (mSocksUsername + ":" + mSocksPassword); } + +private: + + // Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort + int proxyHandshake(LLHost proxy, U32 messagePort); + + // socket handle to proxy TCP control channel + LLSocket::ptr_t mProxyControlChannel; + + // 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; + + // APR pool for the socket + apr_pool_t* mPool; +}; + +#endif diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 97611c3b51..366a1835ca 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 @@ -174,7 +175,7 @@ U32 ip_string_to_u32(const char* ip_string) // use wildcard addresses. -Ambroff U32 ip = inet_addr(ip_string); if (ip == INADDR_NONE - && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0) + && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0) { llwarns << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << llendl; return INVALID_HOST_IP_ADDRESS; @@ -188,11 +189,11 @@ U32 ip_string_to_u32(const char* ip_string) ////////////////////////////////////////////////////////////////////////////////////////// #if LL_WINDOWS - + S32 start_net(S32& socket_out, int& nPort) { // Create socket, make non-blocking - // Init WinSock + // Init WinSock int nRet; int hSocket; @@ -201,7 +202,7 @@ S32 start_net(S32& socket_out, int& nPort) int buff_size = 4; // Initialize windows specific stuff - if(WSAStartup(0x0202, &stWSAData)) + if (WSAStartup(0x0202, &stWSAData)) { S32 err = WSAGetLastError(); WSACleanup(); @@ -210,8 +211,8 @@ S32 start_net(S32& socket_out, int& nPort) } // Get a datagram socket - hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); - if (hSocket == INVALID_SOCKET) + hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); + if (hSocket == INVALID_SOCKET) { S32 err = WSAGetLastError(); WSACleanup(); @@ -304,7 +305,7 @@ S32 start_net(S32& socket_out, int& nPort) // Setup a destination address stDstAddr.sin_family = AF_INET; stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS; - stDstAddr.sin_port = htons(nPort); + stDstAddr.sin_port = htons(nPort); socket_out = hSocket; return 0; @@ -393,10 +394,10 @@ S32 start_net(S32& socket_out, int& nPort) int rec_size = RECEIVE_BUFFER_SIZE; socklen_t buff_size = 4; - + // Create socket - hSocket = socket(AF_INET, SOCK_DGRAM, 0); - if (hSocket < 0) + hSocket = socket(AF_INET, SOCK_DGRAM, 0); + if (hSocket < 0) { llwarns << "socket() failed" << llendl; return 1; @@ -429,7 +430,7 @@ S32 start_net(S32& socket_out, int& nPort) } else { - // Name the socket (assign the local port number to receive on) + // Name the socket (assign the local port number to receive on) stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = htons(nPort); @@ -474,7 +475,7 @@ S32 start_net(S32& socket_out, int& nPort) nPort = attempt_port; } // Set socket to be non-blocking - fcntl(hSocket, F_SETFL, O_NONBLOCK); + fcntl(hSocket, F_SETFL, O_NONBLOCK); // set a large receive buffer nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size); if (nRet) @@ -510,8 +511,8 @@ S32 start_net(S32& socket_out, int& nPort) // Setup a destination address char achMCAddr[MAXADDRSTR] = "127.0.0.1"; /* Flawfinder: ignore */ stDstAddr.sin_family = AF_INET; - stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr); - stDstAddr.sin_port = htons(nPort); + stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr); + stDstAddr.sin_port = htons(nPort); socket_out = hSocket; return 0; @@ -537,7 +538,7 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro iov[0].iov_base = buf; iov[0].iov_len = len; - memset( &msg, 0, sizeof msg ); + memset(&msg, 0, sizeof msg); msg.msg_name = from; msg.msg_namelen = *fromlen; msg.msg_iov = iov; @@ -545,14 +546,14 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro msg.msg_control = &cmsg; msg.msg_controllen = sizeof(cmsg); - size = recvmsg( socket, &msg, 0 ); + size = recvmsg(socket, &msg, 0); - if( size == -1 ) + if (size == -1) { return -1; } - for( cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr ) ) + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr)) { if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO ) { @@ -650,7 +651,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, } } } - while ( resend && send_attempts < 3); + while (resend && send_attempts < 3); if (send_attempts >= 3) { @@ -663,4 +664,63 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, #endif +int tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) +{ + apr_socket_t* apr_socket = handle->getSocket(); + apr_status_t rv; + + apr_size_t expected_len = outlen; + + apr_socket_opt_set(apr_socket, APR_SO_NONBLOCK, -5); // Blocking connection, 5 second timeout + apr_socket_timeout_set(apr_socket, (APR_USEC_PER_SEC * 5)); + + rv = apr_socket_send(apr_socket, dataout, &outlen); + if (rv != APR_SUCCESS || expected_len != outlen) + { + llwarns << "Error sending data to proxy control channel" << llendl; + ll_apr_warn_status(rv); + return -1; + } + + expected_len = maxinlen; + do + { + rv = apr_socket_recv(apr_socket, datain, &maxinlen); + llinfos << "Receiving packets." << llendl; + llwarns << "Proxy control channel status: " << rv << llendl; + } while (APR_STATUS_IS_EAGAIN(rv)); + + if (rv != APR_SUCCESS) + { + llwarns << "Error receiving data from proxy control channel, status: " << rv << llendl; + llwarns << "Received " << maxinlen << " bytes." << llendl; + ll_apr_warn_status(rv); + return rv; + } + else if (expected_len != maxinlen) + { + llwarns << "Incorrect data received length in proxy control channel" << llendl; + return -1; + } + + return 0; +} + +LLSocket::ptr_t tcp_open_channel(LLHost host) +{ + LLSocket::ptr_t socket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + bool connected = socket->blockingConnect(host); + if (!connected) + { + tcp_close_channel(socket); + } + + return socket; +} + +void tcp_close_channel(LLSocket::ptr_t handle) +{ + handle.reset(); +} + //EOF diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index 9f4f5c5821..0d91cf2a2f 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -27,6 +27,9 @@ #ifndef LL_NET_H #define LL_NET_H +#include "lliosocket.h" +#include "llapr.h" + class LLTimer; class LLHost; @@ -46,12 +49,17 @@ S32 receive_packet(int hSocket, char * receiveBuffer); BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort); // Returns TRUE on success. //void get_sender(char * tmp); -LLHost get_sender(); +LLHost get_sender(); U32 get_sender_port(); U32 get_sender_ip(void); -LLHost get_receiving_interface(); +LLHost get_receiving_interface(); U32 get_receiving_interface_ip(void); +// Some helpful TCP functions +LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host +void tcp_close_channel(LLSocket::ptr_t handle); // Close an open TCP channel +int tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t 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 76fecdf05e..604b1f2fc6 100755 --- 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 7848484ac6..c97f0779a1 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" @@ -343,6 +344,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"); @@ -616,6 +618,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) @@ -1544,6 +1552,11 @@ void LLFloaterPreference::updateDoubleClickSettings() } } +void LLFloaterPreference::onClickProxySettings() +{ + LLFloaterReg::showInstance("prefs_proxy"); +} + void LLFloaterPreference::updateDoubleClickControls() { // check is one of double-click actions settings enabled @@ -1911,3 +1924,158 @@ 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, it's only fair we let them know + // it will not be updated until 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(); + } + +}; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 61f2c78640..ef9bc2dd53 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -156,6 +156,7 @@ public: void applyResolution(); void onChangeMaturity(); void onClickBlockList(); + void onClickProxySettings(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); @@ -229,4 +230,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..c2f0ca164b 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 it's 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..b9ce7d9fae 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,18 +309,27 @@ 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); - mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + 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_VERBOSE, 1); // useful for debugging mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); 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..9baa9a0e02 --- /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 traffic 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 09105c1d28..06a9baf8c8 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7161,6 +7161,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> |