From 809de77034c5956a95f35c90024e62b02b439164 Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Tue, 12 Apr 2011 17:41:10 -0700 Subject: Ported SOCKS5 proxy support from Snowglobe 1.5 --- linden/indra/llmessage/CMakeLists.txt | 2 + linden/indra/llmessage/llcurl.cpp | 40 ++++ linden/indra/llmessage/llpacketring.cpp | 56 ++++- linden/indra/llmessage/llpacketring.h | 3 + linden/indra/llmessage/llsocks5.cpp | 210 +++++++++++++++++ linden/indra/llmessage/llsocks5.h | 248 +++++++++++++++++++++ linden/indra/llmessage/message.cpp | 8 +- linden/indra/llmessage/message.h | 14 +- linden/indra/llmessage/net.cpp | 158 ++++++++++++- linden/indra/llmessage/net.h | 3 + linden/indra/newview/app_settings/settings.xml | 99 +++++++- linden/indra/newview/llpanelnetwork.cpp | 126 ++++++++++- linden/indra/newview/llpanelnetwork.h | 8 + linden/indra/newview/llstartup.cpp | 125 ++++++++++- linden/indra/newview/llstartup.h | 3 + linden/indra/newview/llxmlrpctransaction.cpp | 17 ++ .../skins/default/xui/en-us/notifications.xml | 56 +++++ .../xui/en-us/panel_preferences_network.xml | 115 ++++++++-- 18 files changed, 1259 insertions(+), 32 deletions(-) create mode 100644 linden/indra/llmessage/llsocks5.cpp create mode 100644 linden/indra/llmessage/llsocks5.h (limited to 'linden/indra') diff --git a/linden/indra/llmessage/CMakeLists.txt b/linden/indra/llmessage/CMakeLists.txt index 9965191..b3f2b4c 100644 --- a/linden/indra/llmessage/CMakeLists.txt +++ b/linden/indra/llmessage/CMakeLists.txt @@ -98,6 +98,7 @@ set(llmessage_SOURCE_FILES patch_code.cpp patch_dct.cpp patch_idct.cpp + llsocks5.cpp sound_ids.cpp ) @@ -198,6 +199,7 @@ set(llmessage_HEADER_FILES patch_code.h patch_dct.h sound_ids.h + llsocks5.h ) set_source_files_properties(${llmessage_HEADER_FILES} diff --git a/linden/indra/llmessage/llcurl.cpp b/linden/indra/llmessage/llcurl.cpp index 9ecfee4..b23ef33 100644 --- a/linden/indra/llmessage/llcurl.cpp +++ b/linden/indra/llmessage/llcurl.cpp @@ -56,6 +56,8 @@ #include "llsdserialize.h" #include "llthread.h" +#include "llsocks5.h" + ////////////////////////////////////////////////////////////////////////////// /* The trick to getting curl to do keep-alives is to reuse the @@ -270,6 +272,25 @@ 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); + + 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; } @@ -443,6 +464,24 @@ 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); @@ -742,6 +781,7 @@ bool LLCurlRequest::getByteRange(const std::string& url, if (length > 0) { std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1); + //llinfos << "http url: " << url << " " << range << llendl; easy->slist_append(range.c_str()); } easy->setHeaders(); diff --git a/linden/indra/llmessage/llpacketring.cpp b/linden/indra/llmessage/llpacketring.cpp index 7dcb606..a39b435 100644 --- a/linden/indra/llmessage/llpacketring.cpp +++ b/linden/indra/llmessage/llpacketring.cpp @@ -43,6 +43,15 @@ #include "llmessagelog.h" #include "message.h" +#include "llsocks5.h" + +#if LL_WINDOWS + #include +#else + #include + #include +#endif + /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : mUseInThrottle(FALSE), @@ -224,8 +233,25 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) else { // no delay, pull straight from net - packet_size = receive_packet(socket, datap); - mLastSender = ::get_sender(); + if (LLSocks::isEnabled()) + { + proxywrap_t * header; + datap = datap-10; + header = (proxywrap_t *)datap; + packet_size = receive_packet(socket, datap); + mLastSender.setAddress(header->addr); + mLastSender.setPort(ntohs(header->port)); + if (packet_size > 10) + { + packet_size -= 10; + } + } + else + { + packet_size = receive_packet(socket, datap); + mLastSender = ::get_sender(); + } + mLastReceivingIF = ::get_receiving_interface(); if (packet_size) // did we actually get a packet? @@ -254,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 { @@ -275,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 @@ -284,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 @@ -322,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()->getUDPPproxy().getAddress(), LLSocks::getInstance()->getUDPPproxy().getPort()); +} diff --git a/linden/indra/llmessage/llpacketring.h b/linden/indra/llmessage/llpacketring.h index 4408abe..5d2c246 100644 --- a/linden/indra/llmessage/llpacketring.h +++ b/linden/indra/llmessage/llpacketring.h @@ -88,6 +88,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/linden/indra/llmessage/llsocks5.cpp b/linden/indra/llmessage/llsocks5.cpp new file mode 100644 index 0000000..7326e80 --- /dev/null +++ b/linden/indra/llmessage/llsocks5.cpp @@ -0,0 +1,210 @@ +/** + * @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 + +#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; + mNeedUpdate = false; +} + +// 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; + mNeedUpdate = false; + + stopProxy(); + 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 (hProxyControlChannel) + { + tcp_close_channel(hProxyControlChannel); + } +} + +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/linden/indra/llmessage/llsocks5.h b/linden/indra/llmessage/llsocks5.h new file mode 100644 index 0000000..d422d20 --- /dev/null +++ b/linden/indra/llmessage/llsocks5.h @@ -0,0 +1,248 @@ +/** + * @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 + +// 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 +{ +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 getUDPPproxy(){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;}; + + // mark that we need an update due to a settings change + void updated() { mNeedUpdate = true; }; + // report if the current settings are applied or dirty pending a startProxy + bool needsUpdate() { return mNeedUpdate; }; + + //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; + + // Have all settings been applied + bool mNeedUpdate; + + // 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/linden/indra/llmessage/message.cpp b/linden/indra/llmessage/message.cpp index 53036bc..81f7c2a 100644 --- a/linden/indra/llmessage/message.cpp +++ b/linden/indra/llmessage/message.cpp @@ -548,9 +548,9 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak S32 acks = 0; S32 true_rcv_size = 0; - U8* buffer = mTrueReceiveBuffer; + U8* buffer = mTrueReceiveBuffer.buffer; - mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer); + mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer.buffer); // If you want to dump all received packets into SecondLife.log, uncomment this //dumpPacketToLog(); // @@ -622,7 +622,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak for(S32 i = 0; i < acks; ++i) { true_rcv_size -= sizeof(TPACKETID); - memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/ + memcpy(&mem_id, &buffer[true_rcv_size], /* Flawfinder: ignore*/ sizeof(TPACKETID)); packet_id = ntohl(mem_id); //LL_INFOS("Messaging") << "got ack: " << packet_id << llendl; @@ -3386,7 +3386,7 @@ void LLMessageSystem::dumpPacketToLog() { S32 offset = cur_line_pos * 3; snprintf(line_buffer + offset, sizeof(line_buffer) - offset, - "%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */ + "%02x ", mTrueReceiveBuffer.buffer[i]); /* Flawfinder: ignore */ cur_line_pos++; if (cur_line_pos >= 16) { diff --git a/linden/indra/llmessage/message.h b/linden/indra/llmessage/message.h index e6391d9..43c3b0a 100644 --- a/linden/indra/llmessage/message.h +++ b/linden/indra/llmessage/message.h @@ -66,6 +66,7 @@ #include "llmessagesenderinterface.h" #include "llstoredmessage.h" +#include "llsocks5.h" const U32 MESSAGE_MAX_STRINGS_LENGTH = 64; const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; @@ -775,7 +776,18 @@ private: LLMessagePollInfo *mPollInfop; U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE]; - U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE]; + +// Push current alignment to stack and set alignment to 1 byte boundary +#pragma pack(push,1) + + struct ReceiveBuffer_t + { + proxywrap_t header; + U8 buffer[MAX_BUFFER_SIZE]; + } mTrueReceiveBuffer; + +#pragma pack(pop) /* restore original alignment from stack */ + S32 mTrueReceiveSize; // Must be valid during decode diff --git a/linden/indra/llmessage/net.cpp b/linden/indra/llmessage/net.cpp index f63faa5..6db7214 100644 --- a/linden/indra/llmessage/net.cpp +++ b/linden/indra/llmessage/net.cpp @@ -56,6 +56,7 @@ #include "lltimer.h" #include "indra_constants.h" +#include "llsocks5.h" // Globals #if LL_WINDOWS @@ -179,7 +180,91 @@ 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 @@ -377,6 +462,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/linden/indra/llmessage/net.h b/linden/indra/llmessage/net.h index 45b07a0..531b5c3 100644 --- a/linden/indra/llmessage/net.h +++ b/linden/indra/llmessage/net.h @@ -64,6 +64,9 @@ U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr() extern const char* LOOPBACK_ADDRESS_STRING; +void tcp_close_channel(S32 handle); +S32 tcp_open_channel(LLHost host); +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen); // useful MTU consts diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index 00c30c1..3523c7f 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml @@ -2,7 +2,9 @@ - + + + TimeOffset @@ -48,7 +50,8 @@ Value SLVoice - + + AllowEditingOfTrees @@ -1689,6 +1692,7 @@ + ShowClientColor Comment @@ -2091,6 +2095,8 @@ + + RestrainedLove @@ -2268,6 +2274,93 @@ Value 1 + + + + + + Socks5ProxyEnabled + + Comment + Use Socks5 Proxy + Persist + 1 + Type + Boolean + Value + 0 + + Socks5HttpProxyType + + Comment + Proxy type to use for HTTP operations + Persist + 1 + Type + String + Value + None + + Socks5ProxyHost + + Comment + Socks 5 Proxy Host + Persist + 1 + Type + String + Value + + + Socks5ProxyPort + + Comment + Socks 5 Proxy Port + Persist + 1 + Type + U32 + Value + 1080 + + Socks5Username + + Comment + Socks 5 Username + Persist + 1 + Type + String + Value + + + Socks5Password + + Comment + Socks 5 Password + Persist + 1 + Type + String + Value + + + Socks5AuthType + + Comment + Selected Auth mechanism for Socks5 + Persist + 1 + Type + String + Value + None + + + + + + AFKTimeout Comment @@ -3024,7 +3117,7 @@ BrowserProxyAddress Comment - Address for the Web Proxy] + Address for the Web Proxy Persist 1 Type diff --git a/linden/indra/newview/llpanelnetwork.cpp b/linden/indra/newview/llpanelnetwork.cpp index 16b9a76..a371962 100644 --- a/linden/indra/newview/llpanelnetwork.cpp +++ b/linden/indra/newview/llpanelnetwork.cpp @@ -34,14 +34,18 @@ //file include #include "llpanelnetwork.h" +#include "llstartup.h" // project includes #include "llcheckboxctrl.h" +#include "llradiogroup.h" #include "lldirpicker.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llviewerwindow.h" +bool LLPanelNetwork::sSocksSettingsChanged; + LLPanelNetwork::LLPanelNetwork() { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_network.xml"); @@ -72,6 +76,31 @@ BOOL LLPanelNetwork::postBuild() childSetEnabled("xmlrpc_proxy_editor", gSavedSettings.getBOOL("XMLRPCProxyEnabled")); childSetEnabled("xmlrpc_proxy_port", gSavedSettings.getBOOL("XMLRPCProxyEnabled")); + // Socks 5 proxy settings, commit callbacks + childSetCommitCallback("socks5_proxy_enabled", onCommitSocks5ProxyEnabled, this); + childSetCommitCallback("socks5_auth", onSocksAuthChanged, this); + + //Socks 5 proxy settings, saved data + childSetValue("socks5_proxy_enabled", gSavedSettings.getBOOL("Socks5ProxyEnabled")); + childSetValue("socks5_http_proxy_type", gSavedSettings.getString("Socks5HttpProxyType")); + + childSetValue("socks5_proxy_host", gSavedSettings.getString("Socks5ProxyHost")); + childSetValue("socks5_proxy_port", (F32)gSavedSettings.getU32("Socks5ProxyPort")); + childSetValue("socks5_proxy_username", gSavedSettings.getString("Socks5Username")); + childSetValue("socks5_proxy_password", gSavedSettings.getString("Socks5Password")); + childSetValue("socks5_auth", gSavedSettings.getString("Socks5AuthType")); + + // Socks 5 proxy settings, check if settings modified callbacks + childSetCommitCallback("socks5_proxy_host", onSocksSettingsModified,this); + childSetCommitCallback("socks5_proxy_port", onSocksSettingsModified,this); + childSetCommitCallback("socks5_proxy_username", onSocksSettingsModified,this); + childSetCommitCallback("socks5_proxy_password", onSocksSettingsModified,this); + + // Socks 5 settings, Set all controls and labels enabled state + updateProxyEnabled(this, gSavedSettings.getBOOL("Socks5ProxyEnabled"), gSavedSettings.getString("Socks5AuthType")); + + sSocksSettingsChanged = false; + return TRUE; } @@ -91,6 +120,28 @@ void LLPanelNetwork::apply() gSavedSettings.setBOOL("XMLRPCProxyEnabled", childGetValue("xmlrpc_proxy_enabled")); gSavedSettings.setString("XMLRPCProxyAddress", childGetValue("xmlrpc_proxy_editor")); gSavedSettings.setS32("XMLRPCProxyPort", childGetValue("xmlrpc_proxy_port")); + + gSavedSettings.setBOOL("Socks5ProxyEnabled", childGetValue("socks5_proxy_enabled")); + gSavedSettings.setString("Socks5HttpProxyType", childGetValue("socks5_http_proxy_type")); + gSavedSettings.setString("Socks5ProxyHost", childGetValue("socks5_proxy_host")); + gSavedSettings.setU32("Socks5ProxyPort", childGetValue("socks5_proxy_port").asInteger()); + + gSavedSettings.setString("Socks5AuthType", childGetValue("socks5_auth")); + gSavedSettings.setString("Socks5Username", childGetValue("socks5_proxy_username")); + gSavedSettings.setString("Socks5Password", childGetValue("socks5_proxy_password")); + + if (sSocksSettingsChanged) + { + if (LLStartUp::getStartupState() != STATE_LOGIN_WAIT) + { + LLNotifications::instance().add("ProxyNeedRestart"); + } + else + { + // Mark the socks class that it needs to update its connection + LLSocks::getInstance()->updated(); + } + } } void LLPanelNetwork::cancel() @@ -167,4 +218,77 @@ void LLPanelNetwork::onCommitXMLRPCProxyEnabled(LLUICtrl* ctrl, void* data) self->childSetEnabled("xmlrpc_proxy_editor", check->get()); self->childSetEnabled("xmlrpc_proxy_port", check->get()); self->childSetEnabled("xmlrpc_proxy_text_label", check->get()); -} \ No newline at end of file +} + +// static +void LLPanelNetwork::onCommitSocks5ProxyEnabled(LLUICtrl* ctrl, void* data) +{ + LLPanelNetwork* self = (LLPanelNetwork*)data; + LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl; + + if (!self || !check) return; + + sSocksSettingsChanged = true; + + updateProxyEnabled(self, check->get(), self->childGetValue("socks5_auth")); +} + +// static +void LLPanelNetwork::onSocksSettingsModified(LLUICtrl* ctrl, void* data) +{ + sSocksSettingsChanged = true; +} + +// static +void LLPanelNetwork::onSocksAuthChanged(LLUICtrl* ctrl, void* data) +{ + LLRadioGroup* radio = static_cast(ctrl); + LLPanelNetwork* self = static_cast(data); + + sSocksSettingsChanged = true; + + std::string selection = radio->getValue().asString(); + updateProxyEnabled(self, true, selection); +} + +// static +void LLPanelNetwork::updateProxyEnabled(LLPanelNetwork * self, bool enabled, std::string authtype) +{ + // Manage all the enable/disable of the socks5 options from this single function + // to avoid code duplication + + // Update all socks labels and controls except auth specific ones + self->childSetEnabled("socks5_proxy_port", enabled); + self->childSetEnabled("socks5_proxy_host", enabled); + self->childSetEnabled("socks5_host_label", enabled); + self->childSetEnabled("socks5_proxy_label", enabled); + self->childSetEnabled("socks5_proxy_port", enabled); + self->childSetEnabled("socks5_auth_label", enabled); + self->childSetEnabled("socks5_auth", enabled); + + // disable the web option if the web proxy has not been configured + // this is still not ideal as apply or ok is needed for this to be saved to the preferences + self->childSetEnabled("Web", gSavedSettings.getBOOL("BrowserProxyEnabled")); + + self->childSetEnabled("Socks", enabled); + + // Hide the auth specific lables if authtype is none or + // we are not enabled. + if ((authtype.compare("None") == 0) || (enabled == false)) + { + self->childSetEnabled("socks5_username_label", false); + self->childSetEnabled("socks5_password_label", false); + self->childSetEnabled("socks5_proxy_username", false); + self->childSetEnabled("socks5_proxy_password", false); + } + + // Only show the username and password boxes if we are enabled + // and authtype is username pasword. + if ((authtype.compare("UserPass") == 0) && (enabled == true)) + { + self->childSetEnabled("socks5_username_label", true); + self->childSetEnabled("socks5_password_label", true); + self->childSetEnabled("socks5_proxy_username", true); + self->childSetEnabled("socks5_proxy_password", true); + } +} diff --git a/linden/indra/newview/llpanelnetwork.h b/linden/indra/newview/llpanelnetwork.h index 900158a..628f713 100644 --- a/linden/indra/newview/llpanelnetwork.h +++ b/linden/indra/newview/llpanelnetwork.h @@ -52,6 +52,14 @@ private: static void onClickResetCache(void*); static void onCommitPort(LLUICtrl* ctrl, void*); static void onCommitXMLRPCProxyEnabled(LLUICtrl* ctrl, void* data); + static void onCommitSocks5ProxyEnabled(LLUICtrl* ctrl, void* data); + static void onClickTestProxy(void* user_data); + static void onSocksSettingsModified(LLUICtrl* ctrl, void* data); + static void onSocksAuthChanged(LLUICtrl* ctrl, void* data); + static void updateProxyEnabled(LLPanelNetwork * self, bool enabled, std::string authtype); + + static bool sSocksSettingsChanged; + }; #endif diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index 8e11d8c..80ddfa4 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp @@ -189,6 +189,7 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llagentlanguage.h" +#include "llsocks5.h" #include "viewerversion.h" #include "lgghunspell_wrapper.h" @@ -635,6 +636,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. //------------------------------------------------- @@ -890,8 +900,31 @@ bool idle_startup() if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) { - LL_DEBUGS("AppInitStartupState") << "STATE_LOGIN_CLEANUP" << LL_ENDL; + + // 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. + bool socks_enable_required = gSavedSettings.getBOOL("Socks5ProxyEnabled"); + if ((LLSocks::getInstance()->isEnabled() != socks_enable_required) || LLSocks::getInstance()->needsUpdate()) + { + if (socks_enable_required) + { + if (!LLStartUp::handleSocksProxy(false)) + { + // 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 perferences to fix the issue. + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + return FALSE; + } + } + else + { + LLSocks::getInstance()->stopProxy(); + } + } gDisconnected = TRUE; @@ -4022,3 +4055,93 @@ void apply_udp_blacklist(const std::string& csv) } +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; + subs["PROXY"] = gSavedSettings.getString("Socks5ProxyHost"); + + switch(status) + { + case SOCKS_OK: + if (reportOK == true) + { + LLNotifications::instance().add("SOCKS_CONNECT_OK", subs); + } + return true; + break; + + case SOCKS_CONNECT_ERROR: // TCP Fail + LLNotifications::instance().add("SOCKS_CONNECT_ERROR", subs); + break; + + case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection + LLNotifications::instance().add("SOCKS_NOT_PERMITTED", subs); + break; + + case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server + LLNotifications::instance().add("SOCKS_NOT_ACCEPTABLE", subs); + break; + + case SOCKS_AUTH_FAIL: // Authentication failed + LLNotifications::instance().add("SOCKS_AUTH_FAIL", subs); + break; + + case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed + LLNotifications::instance().add("SOCKS_UDP_FWD_NOT_GRANTED", subs); + break; + + case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server + LLNotifications::instance().add("SOCKS_HOST_CONNECT_FAILED", subs); + break; + } + + return false; + } + else + { + LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up + } + + return true; +} diff --git a/linden/indra/newview/llstartup.h b/linden/indra/newview/llstartup.h index 3fe8daa..6dc3946 100644 --- a/linden/indra/newview/llstartup.h +++ b/linden/indra/newview/llstartup.h @@ -123,6 +123,9 @@ public: static std::string sSLURLCommand; // *HACK: On startup, if we were passed a secondlife://app/do/foo // command URL, store it for later processing. + + static bool handleSocksProxy(bool reportOK = true); + static bool shouldAutoLogin() { return mShouldAutoLogin; }; static void setShouldAutoLogin(bool value) { mShouldAutoLogin = value; }; diff --git a/linden/indra/newview/llxmlrpctransaction.cpp b/linden/indra/newview/llxmlrpctransaction.cpp index 675ba42..30b0249 100644 --- a/linden/indra/newview/llxmlrpctransaction.cpp +++ b/linden/indra/newview/llxmlrpctransaction.cpp @@ -236,6 +236,23 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) mCurlRequest->setopt(CURLOPT_PROXYPORT, port); mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); } + else if (LLSocks::getInstance()->isHttpProxyEnabled()) + { + 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/linden/indra/newview/skins/default/xui/en-us/notifications.xml b/linden/indra/newview/skins/default/xui/en-us/notifications.xml index 306e3b8..ecfc523 100644 --- a/linden/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/linden/indra/newview/skins/default/xui/en-us/notifications.xml @@ -7393,6 +7393,62 @@ Media/audio URL blocked for [DOMAIN] The media filters have been cleared + +Socks proxy settings will take effect after you restart [VIEWER_NAME]. + + + +Connection to Socks5 proxy [PROXY] was successful. + + + +The Socks5 proxy "[PROXY]" refused the connection, not allowed by rule set + + + +The Socks5 proxy "[PROXY]" refused the connection, could not open TCP channel + + + +The Socks5 proxy "[PROXY]" refused the selected authentication system + + + +The Socks5 proxy "[PROXY]" reported your credentials are invalid + + + +The Socks5 proxy "[PROXY]" refused the UDP associate request + + + +Could not connect to Socks5 proxy server "[PROXY]" + + - - XMLRPC Proxy (Login, Land- and Money purchase): - - + + + + + label="Enable XMLRPC proxy (Login, Land, and Money purchases)" left="15" mouse_opaque="true" + name="xmlrpc_proxy_enabled" radio_style="false" width="300" /> Address: - + + + + + + Socks 5 host: + + + + + Socks5 authentication: + + + + None + + + Username / Password + + + + Username: + + + + + Password: + + + + + HTTP proxy: + + + + None + + + Socks + + + Web + + -- cgit v1.1