From 74d9bf0d5525426feae4ea21e2a81034ddcf4d7f Mon Sep 17 00:00:00 2001 From: Robin Cornelius Date: Mon, 28 Mar 2011 11:20:06 +0100 Subject: VWR-20801 Implement SOCKS 5 Proxy for the viewer --- indra/llmessage/CMakeLists.txt | 2 + indra/llmessage/llcurl.cpp | 44 ++++ indra/llmessage/llpacketring.cpp | 60 ++++- indra/llmessage/llpacketring.h | 3 + indra/llmessage/llsocks5.cpp | 224 +++++++++++++++++ indra/llmessage/llsocks5.h | 243 ++++++++++++++++++ indra/llmessage/net.cpp | 156 ++++++++++++ indra/llmessage/net.h | 5 + indra/newview/app_settings/settings.xml | 77 ++++++ indra/newview/llfloaterpreference.cpp | 171 +++++++++++++ indra/newview/llfloaterpreference.h | 30 +++ indra/newview/llstartup.cpp | 123 ++++++++- indra/newview/llstartup.h | 2 + indra/newview/llviewerfloaterreg.cpp | 1 + indra/newview/llxmlrpctransaction.cpp | 21 +- .../default/xui/en/floater_preferences_proxy.xml | 274 +++++++++++++++++++++ .../newview/skins/default/xui/en/notifications.xml | 70 ++++++ .../default/xui/en/panel_preferences_setup.xml | 85 +++---- 18 files changed, 1525 insertions(+), 66 deletions(-) create mode 100644 indra/llmessage/llsocks5.cpp create mode 100644 indra/llmessage/llsocks5.h create mode 100644 indra/newview/skins/default/xui/en/floater_preferences_proxy.xml diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 1cad0f6d22..8c68d38926 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -74,6 +74,7 @@ set(llmessage_SOURCE_FILES llsdrpcserver.cpp llservicebuilder.cpp llservice.cpp + llsocks5.cpp llstoredmessage.cpp lltemplatemessagebuilder.cpp lltemplatemessagedispatcher.cpp @@ -172,6 +173,7 @@ set(llmessage_HEADER_FILES llsdrpcserver.h llservice.h llservicebuilder.h + llsocks5.h llstoredmessage.h lltaskname.h llteleportflags.h diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index a485fa0160..020c0d6a4a 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -50,6 +50,8 @@ #include "llsdserialize.h" #include "llthread.h" +#include "llsocks5.h" + ////////////////////////////////////////////////////////////////////////////// /* The trick to getting curl to do keep-alives is to reuse the @@ -273,6 +275,28 @@ LLCurl::Easy* LLCurl::Easy::getEasy() // set no DMS caching as default for all easy handles. This prevents them adopting a // multi handles cache if they are added to one. curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); + + //Set the CURL options for either Socks or HTTP proxy + if (LLSocks::getInstance()->isHttpProxyEnabled()) + { + std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); + U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXY,address.c_str()); + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYPORT,port); + if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) + { + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) + { + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd().c_str()); + } + } + else + { + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } + } + ++gCurlEasyCount; return easy; } @@ -446,6 +470,26 @@ void LLCurl::Easy::prepRequest(const std::string& url, // setopt(CURLOPT_VERBOSE, 1); // usefull for debugging setopt(CURLOPT_NOSIGNAL, 1); + if (LLSocks::getInstance()->isHttpProxyEnabled()) + { + std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); + U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); + setoptString(CURLOPT_PROXY, address.c_str()); + setopt(CURLOPT_PROXYPORT, port); + if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) + { + setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) + { + setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); + } + } + else + { + setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } + } + mOutput.reset(new LLBufferArray); setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback); setopt(CURLOPT_WRITEDATA, (void*)this); diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 8999dec64a..0c8c5f763c 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -35,6 +35,17 @@ #include "llrand.h" #include "u64.h" +#include "llsocks5.h" +#include "message.h" + +#if LL_WINDOWS + #include +#else + #include + #include +#endif + + /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : mUseInThrottle(FALSE), @@ -216,8 +227,31 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) else { // no delay, pull straight from net + if (LLSocks::isEnabled()) + { + U8 buffer[MAX_BUFFER_SIZE]; + packet_size = receive_packet(socket, (char*)buffer); + + if (packet_size > 10) + { + memcpy(datap,buffer+10,packet_size-10); + } + else + { + packet_size=0; + } + + proxywrap_t * header; + header = (proxywrap_t *)buffer; + mLastSender.setAddress(header->addr); + mLastSender.setPort(ntohs(header->port)); + } + else + { packet_size = receive_packet(socket, datap); mLastSender = ::get_sender(); + } + mLastReceivingIF = ::get_receiving_interface(); if (packet_size) // did we actually get a packet? @@ -243,7 +277,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL BOOL status = TRUE; if (!mUseOutThrottle) { - return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); + return doSendPacket(h_socket, send_buffer, buf_size, host ); } else { @@ -264,7 +298,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL mOutBufferLength -= packetp->getSize(); packet_size = packetp->getSize(); - status = send_packet(h_socket, packetp->getData(), packet_size, packetp->getHost().getAddress(), packetp->getHost().getPort()); + status = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost()); delete packetp; // Update the throttle @@ -273,7 +307,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL else { // If the queue's empty, we can just send this packet right away. - status = send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); + status = doSendPacket(h_socket, send_buffer, buf_size, host ); packet_size = buf_size; // Update the throttle @@ -311,3 +345,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL return status; } + +BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) +{ + + if (!LLSocks::isEnabled()) + { + return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort()); + } + + proxywrap_t *socks_header = (proxywrap_t *)&mProxyWrappedSendBuffer; + socks_header->rsv = 0; + socks_header->addr = host.getAddress(); + socks_header->port = htons(host.getPort()); + socks_header->atype = ADDRESS_IPV4; + socks_header->frag = 0; + + memcpy(mProxyWrappedSendBuffer+10, send_buffer, buf_size); + + return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size+10, LLSocks::getInstance()->getUDPProxy().getAddress(), LLSocks::getInstance()->getUDPProxy().getPort()); +} diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index e6409d2048..2fe2f8e1e9 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -82,6 +82,9 @@ protected: LLHost mLastSender; LLHost mLastReceivingIF; + + BOOL doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); + U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE]; }; diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp new file mode 100644 index 0000000000..1f458a007c --- /dev/null +++ b/indra/llmessage/llsocks5.cpp @@ -0,0 +1,224 @@ +/** + * @file llsocks5.cpp + * @brief Socks 5 implementation + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include + +#include "linden_common.h" +#include "net.h" +#include "llhost.h" +#include "message.h" +#include "llsocks5.h" + +// Static class variable instances + +// We want this to be static to avoid excessive indirection on every +// incomming packet just to do a simple bool test. The getter for this +// member is also static +bool LLSocks::sUdpProxyEnabled; +bool LLSocks::sHttpProxyEnabled; + +LLSocks::LLSocks() +{ + sUdpProxyEnabled = false; + sHttpProxyEnabled = false; + hProxyControlChannel = 0; + mProxyType = LLPROXY_SOCKS; +} + +// Perform a Socks5 authentication and UDP assioacation to the proxy +// specified by proxy, and assiocate UDP port message_port +int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) +{ + int result; + + /* Socks 5 Auth request */ + socks_auth_request_t socks_auth_request; + socks_auth_response_t socks_auth_response; + + socks_auth_request.version = SOCKS_VERSION; // Socks version 5 + socks_auth_request.num_methods = 1; // Sending 1 method + socks_auth_request.methods = mAuthMethodSelected; // send only the selected metho + + result = tcp_handshake(hProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request_t), (char*)&socks_auth_response, sizeof(socks_auth_response_t)); + if (result != 0) + { + llwarns << "Socks authentication request failed, error on TCP control channel : " << result << llendl; + stopProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE) + { + llwarns << "Socks5 server refused all our authentication methods" << llendl; + stopProxy(); + return SOCKS_NOT_ACCEPTABLE; + } + + // SOCKS5 USERNAME/PASSWORD authentication + if (socks_auth_response.method == METHOD_PASSWORD) + { + // The server has requested a username/password combination + U32 request_size = mSocksUsername.size() + mSocksPassword.size() + 3; + char * password_auth = (char *)malloc(request_size); + password_auth[0] = 0x01; + password_auth[1] = mSocksUsername.size(); + memcpy(&password_auth[2],mSocksUsername.c_str(), mSocksUsername.size()); + password_auth[mSocksUsername.size()+2] = mSocksPassword.size(); + memcpy(&password_auth[mSocksUsername.size()+3], mSocksPassword.c_str(), mSocksPassword.size()); + + authmethod_password_reply_t password_reply; + + result = tcp_handshake(hProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t)); + free (password_auth); + + if (result != 0) + { + llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl; + stopProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (password_reply.status != AUTH_SUCCESS) + { + llwarns << "Socks authentication failed" << llendl; + stopProxy(); + return SOCKS_AUTH_FAIL; + } + } + + /* SOCKS5 connect request */ + + socks_command_request_t connect_request; + socks_command_response_t connect_reply; + + connect_request.version = SOCKS_VERSION; //Socks V5 + connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP + connect_request.flag = FIELD_RESERVED; + connect_request.atype = ADDRESS_IPV4; + connect_request.address = 0; // 0.0.0.0 We are not fussy about address + // UDP is promiscious receive for our protocol + connect_request.port = 0; // Port must be 0 if you ever want to connect via NAT and your router does port rewrite for you + + result = tcp_handshake(hProxyControlChannel, (char*)&connect_request, sizeof(socks_command_request_t), (char*)&connect_reply, sizeof(socks_command_response_t)); + if (result != 0) + { + llwarns << "Socks connect request failed, error on TCP control channel : " << result << llendl; + stopProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (connect_reply.reply != REPLY_REQUEST_GRANTED) + { + //Something went wrong + llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl; + stopProxy(); + return SOCKS_UDP_FWD_NOT_GRANTED; + } + + mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order + mUDPProxy.setAddress(proxy.getAddress()); + // All good now we have been given the UDP port to send requests that need forwarding. + llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl; + return SOCKS_OK; +} + +int LLSocks::startProxy(LLHost proxy, U32 message_port) +{ + int status; + + mTCPProxy = proxy; + + if (hProxyControlChannel) + { + tcp_close_channel(hProxyControlChannel); + hProxyControlChannel=0; + } + + hProxyControlChannel = tcp_open_channel(proxy); + if (hProxyControlChannel == -1) + { + return SOCKS_HOST_CONNECT_FAILED; + } + + status = proxyHandshake(proxy, message_port); + if (status == SOCKS_OK) + { + sUdpProxyEnabled=true; + } + return status; +} + +int LLSocks::startProxy(std::string host, U32 port) +{ + mTCPProxy.setHostByName(host); + mTCPProxy.setPort(port); + return startProxy(mTCPProxy, (U32)gMessageSystem->mPort); +} + +void LLSocks::stopProxy() +{ + sUdpProxyEnabled = false; + + // If the Socks proxy is requested to stop and we are using that for http as well + // then we must shut down any http proxy operations. But it is allowable if web + // proxy is being used to continue proxying http. + + if(LLPROXY_SOCKS == mProxyType) + { + sHttpProxyEnabled = false; + } + + if (hProxyControlChannel) + { + tcp_close_channel(hProxyControlChannel); + hProxyControlChannel=0; + } +} + +void LLSocks::setAuthNone() +{ + mAuthMethodSelected = METHOD_NOAUTH; +} + +void LLSocks::setAuthPassword(std::string username, std::string password) +{ + mAuthMethodSelected = METHOD_PASSWORD; + mSocksUsername = username; + mSocksPassword = password; +} + +void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type) +{ + sHttpProxyEnabled = true; + mHTTPProxy = httpHost; + mProxyType = type; +} diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h new file mode 100644 index 0000000000..83e311a962 --- /dev/null +++ b/indra/llmessage/llsocks5.h @@ -0,0 +1,243 @@ +/** + * @file llsocks5.h + * @brief Socks 5 implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_SOCKS5_H +#define LL_SOCKS5_H + +#include "llhost.h" +#include "llmemory.h" +#include "llsingleton.h" +#include + +// 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 getUDPProxy(){return mUDPProxy;}; + + // get the socks 5 TCP control channel address and port + LLHost getTCPProxy(){return mTCPProxy;}; + + //get the http proxy address and port + LLHost getHTTPProxy(){return mHTTPProxy;}; + + // get the currently selected http proxy type + LLHttpProxyType getHttpProxyType(){return mProxyType;}; + + //Get the username password in a curl compatible format + std::string getProxyUserPwd(){ return (mSocksUsername + ":" + mSocksPassword);}; + +private: + + // Open a communication channel to the socks5 proxy proxy, at port messagePort + int proxyHandshake(LLHost proxy,U32 messagePort); + + // socket handle to proxy tcp control channel + S32 hProxyControlChannel; + + // is the UDP proxy enabled + static bool sUdpProxyEnabled; + // is the http proxy enabled + static bool sHttpProxyEnabled; + + // currently selected http proxy type + LLHttpProxyType mProxyType; + + // UDP proxy address and port + LLHost mUDPProxy; + // TCP Proxy control channel address and port + LLHost mTCPProxy; + // HTTP proxy address and port + LLHost mHTTPProxy; + + // socks 5 auth method selected + LLSocks5AuthType mAuthMethodSelected; + + // socks 5 username + std::string mSocksUsername; + // socks 5 password + std::string mSocksPassword; +}; + +#endif diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 97611c3b51..ab5c1950c6 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -50,6 +50,7 @@ #include "lltimer.h" #include "indra_constants.h" +#include "llsocks5.h" // Globals #if LL_WINDOWS @@ -189,6 +190,90 @@ U32 ip_string_to_u32(const char* ip_string) #if LL_WINDOWS +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen) +{ + int result; + result = send(handle, dataout, outlen, 0); + if (result != outlen) + { + S32 err = WSAGetLastError(); + llwarns << "Error sending data to proxy control channel, number of bytes sent were " << result << " error code was " << err << llendl; + return -1; + } + + result = recv(handle, datain, maxinlen, 0); + if (result != maxinlen) + { + S32 err = WSAGetLastError(); + llwarns << "Error receiving data from proxy control channel, number of bytes received were " << result << " error code was " << err << llendl; + return -1; + } + + return 0; +} + +S32 tcp_open_channel(LLHost host) +{ + // Open a TCP channel + // Jump through some hoops to ensure that if the request hosts is down + // or not reachable connect() does not block + + S32 handle; + handle = socket(AF_INET, SOCK_STREAM, 0); + if (!handle) + { + llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; + return -1; + } + + struct sockaddr_in address; + address.sin_port = htons(host.getPort()); + address.sin_family = AF_INET; + address.sin_addr.s_addr = host.getAddress(); + + // Non blocking + WSAEVENT hEvent=WSACreateEvent(); + WSAEventSelect(handle, hEvent, FD_CONNECT) ; + connect(handle, (struct sockaddr*)&address, sizeof(address)) ; + // Wait fot 5 seconds, if we can't get a TCP channel open in this + // time frame then there is something badly wrong. + WaitForSingleObject(hEvent, 1000*5); // 5 seconds time out + + WSANETWORKEVENTS netevents; + WSAEnumNetworkEvents(handle,hEvent,&netevents); + + // Check the async event status to see if we connected + if ((netevents.lNetworkEvents & FD_CONNECT) == FD_CONNECT) + { + if (netevents.iErrorCode[FD_CONNECT_BIT] != 0) + { + llwarns << "Unable to open TCP channel, WSA returned an error code of " << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; + WSACloseEvent(hEvent); + return -1; + } + + // Now we are connected disable non blocking + // we don't need support an async interface as + // currently our only consumer (socks5) will make one round + // of packets then just hold the connection open + WSAEventSelect(handle, hEvent, NULL) ; + unsigned long NonBlock = 0; + ioctlsocket(handle, FIONBIO, &NonBlock); + + return handle; + } + + llwarns << "Unable to open TCP channel, Timeout is the host up?" << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; + return -1; +} + +void tcp_close_channel(S32 handle) +{ + llinfos << "Closing TCP channel" << llendl; + shutdown(handle, SD_BOTH); + closesocket(handle); +} + S32 start_net(S32& socket_out, int& nPort) { // Create socket, make non-blocking @@ -385,6 +470,77 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i #else + +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen) +{ + if (send(handle, dataout, outlen, 0) != outlen) + { + llwarns << "Error sending data to proxy control channel" << llendl; + return -1; + } + + if (recv(handle, datain, maxinlen, 0) != maxinlen) + { + llwarns << "Error receiving data to proxy control channel" << llendl; + return -1; + } + + return 0; +} + +S32 tcp_open_channel(LLHost host) +{ + S32 handle; + handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (!handle) + { + llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; + return -1; + } + + struct sockaddr_in address; + address.sin_port = htons(host.getPort()); + address.sin_family = AF_INET; + address.sin_addr.s_addr = host.getAddress(); + + // Set the socket to non blocking for the connect() + int flags = fcntl(handle, F_GETFL, 0); + fcntl(handle, F_SETFL, flags | O_NONBLOCK); + + S32 error = connect(handle, (sockaddr*)&address, sizeof(address)); + if (error && (errno != EINPROGRESS)) + { + llwarns << "Unable to open TCP channel, error code: " << errno << llendl; + return -1; + } + + struct timeval timeout; + timeout.tv_sec = 5; // Maximum time to wait for the connect() to complete + timeout.tv_usec = 0; + fd_set fds; + FD_ZERO(&fds); + FD_SET(handle, &fds); + + // See if we have connectde or time out after 5 seconds + U32 rc = select(sizeof(fds)*8, NULL, &fds, NULL, &timeout); + + if (rc != 1) // we require exactly one descriptor to be set + { + llwarns << "Unable to open TCP channel" << llendl; + return -1; + } + + // Return the socket to blocking operations + fcntl(handle, F_SETFL, flags); + + return handle; +} + +void tcp_close_channel(S32 handle) +{ + close(handle); +} + // Create socket, make non-blocking S32 start_net(S32& socket_out, int& nPort) { diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index 9f4f5c5821..d93ed20c98 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -52,6 +52,11 @@ U32 get_sender_ip(void); LLHost get_receiving_interface(); U32 get_receiving_interface_ip(void); +// Some helpful tcp functions added for the socks 5 proxy support +S32 tcp_open_channel(LLHost host); // Open a tcp channel to a given host +void tcp_close_channel(S32 handle); // Close an open tcp channel +int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen); // Do a TCP data handshake + const char* u32_to_ip_string(U32 ip); // Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls char* u32_to_ip_string(U32 ip, char *ip_string); // NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr() diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f0e28d4ae3..2b7b7b8484 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -774,6 +774,83 @@ Value 5 + Socks5ProxyEnabled + + Comment + Use Socks5 Proxy + Persist + 1 + Type + Boolean + Value + 1 + + Socks5HttpProxyType + + Comment + Proxy type to use for HTTP operations + Persist + 1 + Type + String + Value + Socks + + Socks5ProxyHost + + Comment + Socks 5 Proxy Host + Persist + 1 + Type + String + Value + 64.79.219.97 + + 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 + BuildAxisDeadZone0 Comment diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 724096b443..a0d3852d30 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -103,6 +103,7 @@ #include "llviewermedia.h" #include "llpluginclassmedia.h" #include "llteleporthistorystorage.h" +#include "llsocks5.h" #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" @@ -325,6 +326,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); + mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -603,6 +605,12 @@ void LLFloaterPreference::cancel() updateDoubleClickControls(); mDoubleClickActionDirty = false; } + LLFloaterPreferenceProxy * advanced_socks_settings = LLFloaterReg::findTypedInstance("prefs_socks5_advanced"); + if(advanced_socks_settings) + { + advanced_socks_settings->cancel(); + } + } void LLFloaterPreference::onOpen(const LLSD& key) @@ -1497,6 +1505,11 @@ void LLFloaterPreference::updateDoubleClickSettings() } } +void LLFloaterPreference::onClickProxySettings() +{ + LLFloaterReg::showInstance("prefs_proxy"); +} + void LLFloaterPreference::updateDoubleClickControls() { // check is one of double-click actions settings enabled @@ -1805,3 +1818,161 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); LLPanelPreference::setHardwareDefaults(); } + + +/* ------------------------------------------------------------ */ + +LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) + : LLFloater(key), + mSocksSettingsDirty(false) +{ + mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); + mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); + mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); +} + +LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() +{ +} + +BOOL LLFloaterPreferenceProxy::postBuild() +{ + LLLineEditor* edit = getChild("socks_password_editor"); + if (edit) edit->setDrawAsterixes(TRUE); + + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if(socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } + + center(); + return TRUE; +} + +void LLFloaterPreferenceProxy::onOpen(const LLSD& key) +{ + saveSettings(); +} + +void LLFloaterPreferenceProxy::onClose(bool app_quitting) +{ + if(mSocksSettingsDirty) + { + + // If the user plays with the Socks proxy settings after login, its only fair we let them know + // it will not be updated untill next restart. + if(LLStartUp::getStartupState()>STATE_LOGIN_WAIT) + { + if(this->mSocksSettingsDirty == true ) + { + LLNotifications::instance().add("ChangeSocks5Settings",LLSD(),LLSD()); + mSocksSettingsDirty = false; // we have notified the user now be quiet again + } + } + } +} + +void LLFloaterPreferenceProxy::saveSettings() +{ + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list 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(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(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + closeFloater(false); +} + +void LLFloaterPreferenceProxy::onBtnCancel() +{ + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(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("socks5_auth_type"); + if(socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } + else + { + getChild("socks5_username")->setEnabled(true); + getChild("socks5_password")->setEnabled(true); + } + + //Check for invalid states for the other http proxy radio + LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_selection"); + if( (otherHttpProxy->getSelectedValue().asString() == "Socks" && + getChild("socks_proxy_enabled")->get() == FALSE )||( + otherHttpProxy->getSelectedValue().asString() == "Web" && + getChild("web_proxy_enabled")->get() == FALSE ) ) + { + otherHttpProxy->selectFirstItem(); + } + +}; \ No newline at end of file diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 46014804ec..fd5454ebcf 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -154,6 +154,7 @@ public: void applyResolution(); void onChangeMaturity(); void onClickBlockList(); + void onClickProxySettings(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); @@ -225,4 +226,33 @@ protected: }; +class LLFloaterPreferenceProxy : public LLFloater +{ +public: + LLFloaterPreferenceProxy(const LLSD& key); + ~LLFloaterPreferenceProxy(); + + /// show off our menu + static void show(); + void cancel(); + +protected: + BOOL postBuild(); + void onOpen(const LLSD& key); + void onClose(bool app_quitting); + void saveSettings(); + void onBtnOk(); + void onBtnCancel(); + + void onChangeSocksSettings(); + +private: + + bool mSocksSettingsDirty; + typedef std::map control_values_map_t; + control_values_map_t mSavedValues; + +}; + + #endif // LL_LLPREFERENCEFLOATER_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 8fccb35886..f054bd11b8 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -191,6 +191,8 @@ #include "llevents.h" #include "llstartuplistener.h" +#include "llsocks5.h" + #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -393,7 +395,7 @@ bool idle_startup() gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass()); // load dynamic GPU/feature tables from website (S3) - LLFeatureManager::getInstance()->fetchHTTPTables(); + //LLFeatureManager::getInstance()->fetchHTTPTables(); std::string xml_file = LLUI::locateSkin("xui_version.xml"); LLXMLNodePtr root; @@ -595,6 +597,15 @@ bool idle_startup() LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; + //------------------------------------------------- + // Init the socks 5 proxy and open the control TCP + // connection if the user is using SOCKS5 + // We need to do this early incase the user is using + // socks for http so we get the login screen via socks + //------------------------------------------------- + + LLStartUp::handleSocksProxy(false); + //------------------------------------------------- // Init audio, which may be needed for prefs dialog // or audio cues in connection UI. @@ -809,6 +820,27 @@ bool idle_startup() if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) { + // Post login screen, we should see if any settings have changed that may + // require us to either start/stop or change the socks proxy. As various communications + // past this point may require the proxy to be up. + if ( gSavedSettings.getBOOL("Socks5ProxyEnabled") ) + { + if (!LLStartUp::handleSocksProxy(true)) + { + // Proxy start up failed, we should now bail the state machine + // HandleSocksProxy() will have reported an error to the user + // already, so we just go back to the login screen. The user + // could then change the preferences to fix the issue. + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + return FALSE; + } + } + else + { + LLSocks::getInstance()->stopProxy(); + } + + //reset the values that could have come in from a slurl // DEV-42215: Make sure they're not empty -- gUserCredential // might already have been set from gSavedSettings, and it's too bad @@ -2746,6 +2778,95 @@ void LLStartUp::setStartSLURL(const LLSLURL& slurl) } } +bool LLStartUp::handleSocksProxy(bool reportOK) +{ + std::string httpProxyType = gSavedSettings.getString("Socks5HttpProxyType"); + + // Determine the http proxy type (if any) + if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) + { + LLHost httpHost; + httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); + httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort")); + LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_HTTP); + } + else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + LLHost httpHost; + httpHost.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + httpHost.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_SOCKS); + } + else + { + LLSocks::getInstance()->DisableHttpProxy(); + } + + bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled"); + if (use_socks_proxy) + { + + // Determine and update LLSocks with the saved authentication system + std::string auth_type = gSavedSettings.getString("Socks5AuthType"); + + if (auth_type.compare("None") == 0) + { + LLSocks::getInstance()->setAuthNone(); + } + + if (auth_type.compare("UserPass") == 0) + { + LLSocks::getInstance()->setAuthPassword(gSavedSettings.getString("Socks5Username"),gSavedSettings.getString("Socks5Password")); + } + + // Start the proxy and check for errors + int status = LLSocks::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort")); + LLSD subs; + LLSD payload; + subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); + subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + + switch(status) + { + case SOCKS_OK: + return true; + break; + + case SOCKS_CONNECT_ERROR: // TCP Fail + LLNotifications::instance().add("SOCKS_CONNECT_ERROR", subs,payload); + break; + + case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection + LLNotifications::instance().add("SOCKS_NOT_PERMITTED", subs,payload); + break; + + case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server + LLNotifications::instance().add("SOCKS_NOT_ACCEPTABLE", subs,payload); + break; + + case SOCKS_AUTH_FAIL: // Authentication failed + LLNotifications::instance().add("SOCKS_AUTH_FAIL", subs,payload); + break; + + case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed + LLNotifications::instance().add("SOCKS_UDP_FWD_NOT_GRANTED", subs,payload); + break; + + case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server + LLNotifications::instance().add("SOCKS_HOST_CONNECT_FAILED", subs,payload); + break; + } + + return false; + } + else + { + LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up + } + + return true; +} + bool login_alert_done(const LLSD& notification, const LLSD& response) { LLPanelLogin::giveFocus(); diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index b3d9ef1dcc..a512ec7bff 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -113,6 +113,8 @@ public: static void setStartSLURL(const LLSLURL& slurl); static LLSLURL& getStartSLURL() { return sStartSLURL; } + static bool handleSocksProxy(bool reportOK); //handle kicking the socks 5 proxy code at startup time + private: static LLSLURL sStartSLURL; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index dca1e33e60..976dc76b50 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -202,6 +202,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 257884d921..b3d899c61a 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -41,6 +41,8 @@ #include "llappviewer.h" #include "lltrans.h" +#include "llsocks5.h" + // Static instance of LLXMLRPCListener declared here so that every time we // bring in this code, we instantiate a listener. If we put the static // instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would @@ -307,16 +309,23 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) } mErrorCert = NULL; - if (gSavedSettings.getBOOL("BrowserProxyEnabled")) + if (LLSocks::getInstance()->isHttpProxyEnabled()) { - mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); - S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); - - // tell curl about the settings - mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress); + std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); + U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); + mCurlRequest->setoptString(CURLOPT_PROXY, address.c_str()); mCurlRequest->setopt(CURLOPT_PROXYPORT, port); + if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS) + { + mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) + mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); + } + else + { mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); } + } // mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); diff --git a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml new file mode 100644 index 0000000000..bb9ade067b --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml @@ -0,0 +1,274 @@ + + + + + + Other Http traffic proxy: + + + + + + + + HTTP Proxy: + + + + + SOCKS 5 Proxy: + + + + + Authentication: + + + + width="120" /> + + width="120" /> + + + Username: + + + + Password: + + + -- cgit v1.2.3 From 6ce2c20a06e32825f4e4260575059a9867510ecd Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Fri, 10 Jun 2011 17:34:00 -0400 Subject: STORM-1112 First pass at cleanup of SOCKS 5 proxy code based on Linden Coding Standard and comments in the code review. --- indra/llmessage/llpacketring.cpp | 23 +- indra/llmessage/llsocks5.cpp | 295 +++++++++++---------- indra/llmessage/llsocks5.h | 184 ++++++------- indra/llmessage/net.cpp | 61 +++-- indra/llmessage/net.h | 4 +- indra/newview/llfloaterpreference.cpp | 225 ++++++++-------- indra/newview/llstartup.cpp | 8 +- indra/newview/llxmlrpctransaction.cpp | 8 +- .../default/xui/en/floater_preferences_proxy.xml | 2 +- 9 files changed, 409 insertions(+), 401 deletions(-) diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 0c8c5f763c..62aaca0672 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -28,22 +28,26 @@ #include "llpacketring.h" +#if LL_WINDOWS + #include +#else + #include + #include +#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" -#include "llsocks5.h" -#include "message.h" -#if LL_WINDOWS - #include -#else - #include - #include -#endif + + + /////////////////////////////////////////////////////////// @@ -241,8 +245,7 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) packet_size=0; } - proxywrap_t * header; - header = (proxywrap_t *)buffer; + proxywrap_t * header = (proxywrap_t *)buffer; mLastSender.setAddress(header->addr); mLastSender.setPort(ntohs(header->port)); } diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp index 8a63287f22..7eac27d4bb 100644 --- a/indra/llmessage/llsocks5.cpp +++ b/indra/llmessage/llsocks5.cpp @@ -35,184 +35,185 @@ // 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 +// 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; - hProxyControlChannel = 0; - mProxyType = LLPROXY_SOCKS; + sUdpProxyEnabled = false; + sHttpProxyEnabled = false; + mProxyControlChannel = 0; + mProxyType = LLPROXY_SOCKS; } -// Perform a Socks5 authentication and UDP assioacation to the proxy -// specified by proxy, and assiocate UDP port message_port +// Perform a Socks5 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 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 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 << "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); + 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.flag = FIELD_RESERVED; + connect_request.atype = ADDRESS_IPV4; + connect_request.address = 0; // 0.0.0.0 We are not fussy about address + // UDP is promiscuous 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(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 SOCKS5 server failed, UDP forward request not granted" << llendl; + stopProxy(); + return SOCKS_UDP_FWD_NOT_GRANTED; + } + + mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order + mUDPProxy.setAddress(proxy.getAddress()); + // All good now we have been given the UDP port to send requests that need forwarding. + llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl; + return SOCKS_OK; } int LLSocks::startProxy(LLHost proxy, U32 message_port) { - int status; - - mTCPProxy = proxy; - - if (hProxyControlChannel) - { - tcp_close_channel(hProxyControlChannel); - hProxyControlChannel=0; - } - - hProxyControlChannel = tcp_open_channel(proxy); - if (hProxyControlChannel == -1) - { - return SOCKS_HOST_CONNECT_FAILED; - } - - status = proxyHandshake(proxy, message_port); - if (status == SOCKS_OK) - { - sUdpProxyEnabled=true; - } - return status; + int status; + + mTCPProxy = proxy; + + if (mProxyControlChannel) + { + tcp_close_channel(mProxyControlChannel); + mProxyControlChannel = 0; + } + + mProxyControlChannel = tcp_open_channel(proxy); + if (mProxyControlChannel == -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); + mTCPProxy.setHostByName(host); + mTCPProxy.setPort(port); + return startProxy(mTCPProxy, (U32)gMessageSystem->mPort); } void LLSocks::stopProxy() { - sUdpProxyEnabled = false; - - // If the Socks proxy is requested to stop and we are using that for http as well - // then we must shut down any http proxy operations. But it is allowable if web - // proxy is being used to continue proxying http. - - if(LLPROXY_SOCKS == mProxyType) - { - sHttpProxyEnabled = false; - } - - if (hProxyControlChannel) - { - tcp_close_channel(hProxyControlChannel); - hProxyControlChannel=0; - } + 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); + mProxyControlChannel = 0; + } } void LLSocks::setAuthNone() { - mAuthMethodSelected = METHOD_NOAUTH; + mAuthMethodSelected = METHOD_NOAUTH; } void LLSocks::setAuthPassword(std::string username, std::string password) { - mAuthMethodSelected = METHOD_PASSWORD; - mSocksUsername = username; - mSocksPassword = password; + mAuthMethodSelected = METHOD_PASSWORD; + mSocksUsername = username; + mSocksPassword = password; } -void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type) +void LLSocks::enableHttpProxy(LLHost httpHost, LLHttpProxyType type) { - sHttpProxyEnabled = true; - mHTTPProxy = httpHost; - mProxyType = type; + sHttpProxyEnabled = true; + mHTTPProxy = httpHost; + mProxyType = type; } diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h index a78acb8b23..171a933d32 100644 --- a/indra/llmessage/llsocks5.h +++ b/indra/llmessage/llsocks5.h @@ -35,12 +35,12 @@ // Error codes returned from the StartProxy method #define SOCKS_OK 0 -#define SOCKS_CONNECT_ERROR -1 -#define SOCKS_NOT_PERMITTED -2 -#define SOCKS_NOT_ACCEPTABLE -3 -#define SOCKS_AUTH_FAIL -4 -#define SOCKS_UDP_FWD_NOT_GRANTED -5 -#define SOCKS_HOST_CONNECT_FAILED -6 +#define SOCKS_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. */ @@ -56,8 +56,8 @@ // Lets just use our own ipv4 struct rather than dragging in system // specific headers union ipv4_address_t { - unsigned char octects[4]; - U32 addr32; + unsigned char octets[4]; + U32 addr32; }; // Socks 5 control channel commands @@ -86,53 +86,53 @@ union ipv4_address_t { // Socks5 command packet struct socks_command_request_t { - unsigned char version; - unsigned char command; - unsigned char flag; - unsigned char atype; - U32 address; - U16 port; + 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; + 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 +#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 { - unsigned char version; - unsigned char num_methods; - unsigned char methods; // We are only using a single method currently + 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; + unsigned char version; + unsigned char method; }; // socks 5 password reply packet struct authmethod_password_reply_t { - unsigned char version; - unsigned char status; + unsigned char version; + unsigned char status; }; // socks 5 UDP packet header struct proxywrap_t { - U16 rsv; - U8 frag; - U8 atype; - U32 addr; - U16 port; + U16 rsv; + U8 frag; + U8 atype; + U32 addr; + U16 port; }; #pragma pack(pop) /* restore original alignment from stack */ @@ -141,97 +141,97 @@ struct proxywrap_t { // Currently selected http proxy type enum LLHttpProxyType { - LLPROXY_SOCKS = 0, - LLPROXY_HTTP = 1 + 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 + 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(); + LLSocks(); - // Start a connection to the socks 5 proxy - int startProxy(std::string host,U32 port); - int startProxy(LLHost proxy,U32 messagePort); + // 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(); + // 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 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(); + // Set up to use No Auth when connecting to the socks proxy + void setAuthNone(); - // get the currently selected auth method - LLSocks5AuthType getSelectedAuthMethod() { return mAuthMethodSelected; }; + // 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 UDP packets + static bool isEnabled() { return sUdpProxyEnabled; } - // static check for enabled status for http packets - static bool isHttpProxyEnabled(){return sHttpProxyEnabled;}; + // 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); + // 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;}; + // Stop proxying http packets + void disableHttpProxy() { sHttpProxyEnabled = false; }; - // get the UDP proxy address and port - LLHost getUDPProxy(){return mUDPProxy;}; + // Get the UDP proxy address and port + LLHost getUDPProxy() const { return mUDPProxy; } - // get the socks 5 TCP control channel address and port - LLHost getTCPProxy(){return mTCPProxy;}; + // Get the socks 5 TCP control channel address and port + LLHost getTCPProxy() const { return mTCPProxy; } - //get the http proxy address and port - LLHost getHTTPProxy(){return mHTTPProxy;}; + // Get the http proxy address and port + LLHost getHTTPProxy() const { return mHTTPProxy; } - // get the currently selected http proxy type - LLHttpProxyType getHttpProxyType(){return mProxyType;}; + // Get the currently selected http proxy type + LLHttpProxyType getHttpProxyType() const { return mProxyType; } - //Get the username password in a curl compatible format - std::string getProxyUserPwd(){ return (mSocksUsername + ":" + mSocksPassword);}; + // Get the username password in a curl compatible format + std::string getProxyUserPwd() const { return (mSocksUsername + ":" + mSocksPassword); } private: - // Open a communication channel to the socks5 proxy proxy, at port messagePort - int proxyHandshake(LLHost proxy,U32 messagePort); + // 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; + // socket handle to proxy tcp control channel + S32 mProxyControlChannel; - // is the UDP proxy enabled - static bool sUdpProxyEnabled; - // is the http proxy enabled - static bool sHttpProxyEnabled; + // is the UDP proxy enabled? + static bool sUdpProxyEnabled; + // is the http proxy enabled? + static bool sHttpProxyEnabled; - // currently selected http proxy type - LLHttpProxyType mProxyType; + // 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; + // 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 auth method selected + LLSocks5AuthType mAuthMethodSelected; - // socks 5 username - std::string mSocksUsername; - // socks 5 password - std::string mSocksPassword; + // socks 5 username + std::string mSocksUsername; + // socks 5 password + std::string mSocksPassword; }; #endif diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index ab5c1950c6..a51d80ff48 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -175,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; @@ -220,9 +220,10 @@ S32 tcp_open_channel(LLHost host) S32 handle; handle = socket(AF_INET, SOCK_STREAM, 0); - if (!handle) + if (INVALID_SOCKET == handle) { - llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; + llwarns << "Error opening TCP control socket, socket() returned " + << WSAGetLastError() << ", " << DecodeError(WSAGetLastError()) << llendl; return -1; } @@ -232,15 +233,15 @@ S32 tcp_open_channel(LLHost host) address.sin_addr.s_addr = host.getAddress(); // Non blocking - WSAEVENT hEvent=WSACreateEvent(); + 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 + // Wait for 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 + WaitForSingleObject(hEvent, 1000 * 5); // 5 seconds time out WSANETWORKEVENTS netevents; - WSAEnumNetworkEvents(handle,hEvent,&netevents); + WSAEnumNetworkEvents(handle, hEvent, &netevents); // Check the async event status to see if we connected if ((netevents.lNetworkEvents & FD_CONNECT) == FD_CONNECT) @@ -249,6 +250,7 @@ S32 tcp_open_channel(LLHost host) { llwarns << "Unable to open TCP channel, WSA returned an error code of " << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; WSACloseEvent(hEvent); + tcp_close_channel(handle); return -1; } @@ -264,6 +266,7 @@ S32 tcp_open_channel(LLHost host) } llwarns << "Unable to open TCP channel, Timeout is the host up?" << netevents.iErrorCode[FD_CONNECT_BIT] << llendl; + tcp_close_channel(handle); return -1; } @@ -277,7 +280,7 @@ void tcp_close_channel(S32 handle) S32 start_net(S32& socket_out, int& nPort) { // Create socket, make non-blocking - // Init WinSock + // Init WinSock int nRet; int hSocket; @@ -286,7 +289,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(); @@ -295,8 +298,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(); @@ -389,7 +392,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; @@ -492,9 +495,9 @@ S32 tcp_open_channel(LLHost host) { S32 handle; handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (!handle) + if (-1 == handle) { - llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl; + llwarns << "Error opening TCP control socket, socket() returned " << handle << "error code: " << errno << llendl; return -1; } @@ -511,6 +514,7 @@ S32 tcp_open_channel(LLHost host) if (error && (errno != EINPROGRESS)) { llwarns << "Unable to open TCP channel, error code: " << errno << llendl; + tcp_close_channel(handle); return -1; } @@ -521,12 +525,13 @@ S32 tcp_open_channel(LLHost host) 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); + // See if we have connected or time out after 5 seconds + S32 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; + tcp_close_channel(handle); return -1; } @@ -549,10 +554,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; @@ -585,7 +590,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); @@ -630,7 +635,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) @@ -666,8 +671,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; @@ -693,7 +698,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; @@ -701,14 +706,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 ) { @@ -806,7 +811,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, } } } - while ( resend && send_attempts < 3); + while (resend && send_attempts < 3); if (send_attempts >= 3) { diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index d93ed20c98..047e8ce646 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -46,10 +46,10 @@ S32 receive_packet(int hSocket, char * receiveBuffer); BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort); // Returns TRUE on success. //void get_sender(char * tmp); -LLHost get_sender(); +LLHost get_sender(); U32 get_sender_port(); U32 get_sender_ip(void); -LLHost get_receiving_interface(); +LLHost get_receiving_interface(); U32 get_receiving_interface_ip(void); // Some helpful tcp functions added for the socks 5 proxy support diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b49026de38..dfc3fe1fc7 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -343,7 +343,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); - mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); + mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -1545,7 +1545,7 @@ void LLFloaterPreference::updateDoubleClickSettings() void LLFloaterPreference::onClickProxySettings() { - LLFloaterReg::showInstance("prefs_proxy"); + LLFloaterReg::showInstance("prefs_proxy"); } void LLFloaterPreference::updateDoubleClickControls() @@ -1916,16 +1916,13 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() LLPanelPreference::setHardwareDefaults(); } - -/* ------------------------------------------------------------ */ - LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) - : LLFloater(key), - mSocksSettingsDirty(false) + : 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)); + 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() @@ -1934,142 +1931,142 @@ LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() BOOL LLFloaterPreferenceProxy::postBuild() { - LLLineEditor* edit = getChild("socks_password_editor"); - if (edit) edit->setDrawAsterixes(TRUE); + LLLineEditor* edit = getChild("socks_password_editor"); + if (edit) edit->setDrawAsterixes(TRUE); - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); - if(socksAuth->getSelectedValue().asString() == "None") - { - getChild("socks5_username")->setEnabled(false); - getChild("socks5_password")->setEnabled(false); - } + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if(socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } - center(); - return TRUE; + center(); + return TRUE; } void LLFloaterPreferenceProxy::onOpen(const LLSD& key) { - saveSettings(); + saveSettings(); } void LLFloaterPreferenceProxy::onClose(bool app_quitting) { - if(mSocksSettingsDirty) - { + if(mSocksSettingsDirty) + { - // If the user plays with the Socks proxy settings after login, its only fair we let them know - // it will not be updated untill next restart. - if(LLStartUp::getStartupState()>STATE_LOGIN_WAIT) - { - if(this->mSocksSettingsDirty == true ) - { - LLNotifications::instance().add("ChangeSocks5Settings",LLSD(),LLSD()); - mSocksSettingsDirty = false; // we have notified the user now be quiet again - } - } - } + // 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 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(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); - } - } + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list 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(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(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - } - closeFloater(false); + // commit any outstanding text entry + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + closeFloater(false); } void LLFloaterPreferenceProxy::onBtnCancel() { - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - refresh(); - } - - cancel(); - + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(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(); + 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; + mSocksSettingsDirty = true; - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); - if(socksAuth->getSelectedValue().asString() == "None") - { - getChild("socks5_username")->setEnabled(false); - getChild("socks5_password")->setEnabled(false); - } - else - { - getChild("socks5_username")->setEnabled(true); - getChild("socks5_password")->setEnabled(true); - } + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if(socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } + else + { + getChild("socks5_username")->setEnabled(true); + getChild("socks5_password")->setEnabled(true); + } - //Check for invalid states for the other http proxy radio - LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_selection"); - if( (otherHttpProxy->getSelectedValue().asString() == "Socks" && - getChild("socks_proxy_enabled")->get() == FALSE )||( - otherHttpProxy->getSelectedValue().asString() == "Web" && - getChild("web_proxy_enabled")->get() == FALSE ) ) - { - otherHttpProxy->selectFirstItem(); - } + //Check for invalid states for the other http proxy radio + LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_selection"); + if( (otherHttpProxy->getSelectedValue().asString() == "Socks" && + getChild("socks_proxy_enabled")->get() == FALSE )||( + otherHttpProxy->getSelectedValue().asString() == "Web" && + getChild("web_proxy_enabled")->get() == FALSE ) ) + { + otherHttpProxy->selectFirstItem(); + } -}; \ No newline at end of file +}; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d54c5b177a..6d94a5454e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2770,18 +2770,18 @@ bool LLStartUp::handleSocksProxy(bool reportOK) LLHost httpHost; httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort")); - LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_HTTP); + 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); + LLSocks::getInstance()->enableHttpProxy(httpHost,LLPROXY_SOCKS); } else { - LLSocks::getInstance()->DisableHttpProxy(); + LLSocks::getInstance()->disableHttpProxy(); } bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled"); @@ -2843,7 +2843,7 @@ bool LLStartUp::handleSocksProxy(bool reportOK) } else { - LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up + LLSocks::getInstance()->stopProxy(); // ensure no UDP proxy is running and it's all cleaned up } return true; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index b3d899c61a..87d2f780be 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -319,15 +319,17 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { 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_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 index bb9ade067b..9baa9a0e02 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml @@ -60,7 +60,7 @@ layout="topleft" value="None" width="120" - tool_tip="Non web Http trafic should NOT be sent to any proxy."/> + tool_tip="Non web Http traffic should NOT be sent to any proxy."/> Date: Tue, 21 Jun 2011 17:09:12 -0400 Subject: Refactored SOCKS 5 handshake to use existing LLSocket class. --- indra/llmessage/llcurl.cpp | 8 +- indra/llmessage/llsocks5.cpp | 73 ++++++------ indra/llmessage/llsocks5.h | 129 ++++++++++---------- indra/llmessage/net.cpp | 219 +++++++++------------------------- indra/llmessage/net.h | 11 +- indra/newview/llstartup.cpp | 6 +- indra/newview/llxmlrpctransaction.cpp | 4 +- 7 files changed, 176 insertions(+), 274 deletions(-) diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 9c507517c7..32dd438e68 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -359,13 +359,13 @@ LLCurl::Easy* LLCurl::Easy::getEasy() check_curl_code(result); //Set the CURL options for either Socks or HTTP proxy - if (LLSocks::getInstance()->isHttpProxyEnabled()) + 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) + if (LLSocks::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) { curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) @@ -557,13 +557,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, //setopt(CURLOPT_VERBOSE, 1); // usefull for debugging setopt(CURLOPT_NOSIGNAL, 1); - if (LLSocks::getInstance()->isHttpProxyEnabled()) + 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) + if (LLSocks::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) { setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp index 7eac27d4bb..27a31e35b3 100644 --- a/indra/llmessage/llsocks5.cpp +++ b/indra/llmessage/llsocks5.cpp @@ -1,6 +1,6 @@ /** * @file llsocks5.cpp - * @brief Socks 5 implementation + * @brief SOCKS 5 implementation * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -37,52 +37,51 @@ // 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; +bool LLSocks::sUDPProxyEnabled; +bool LLSocks::sHTTPProxyEnabled; LLSocks::LLSocks() { - sUdpProxyEnabled = false; - sHttpProxyEnabled = false; - mProxyControlChannel = 0; + sUDPProxyEnabled = false; + sHTTPProxyEnabled = false; + mProxyControlChannel.reset(); mProxyType = LLPROXY_SOCKS; } -// Perform a Socks5 authentication and UDP association to the proxy +// 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 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 + 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; + 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; + llwarns << "SOCKS 5 server refused all our authentication methods" << llendl; stopProxy(); return SOCKS_NOT_ACCEPTABLE; } - // SOCKS5 USERNAME/PASSWORD authentication + // 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 = (char *)malloc(request_size); char * password_auth = new char[request_size]; password_auth[0] = 0x01; password_auth[1] = mSocksUsername.size(); @@ -97,14 +96,14 @@ int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) if (result != 0) { - llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl; + 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; + llwarns << "SOCKS authentication failed" << llendl; stopProxy(); return SOCKS_AUTH_FAIL; } @@ -115,18 +114,19 @@ int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) 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 promiscuous 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 + 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; + llwarns << "SOCKS connect request failed, error on TCP control channel : " << result << llendl; stopProxy(); return SOCKS_CONNECT_ERROR; } @@ -134,7 +134,7 @@ int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) if (connect_reply.reply != REPLY_REQUEST_GRANTED) { //Something went wrong - llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl; + llwarns << "Connection to SOCKS 5 server failed, UDP forward request not granted" << llendl; stopProxy(); return SOCKS_UDP_FWD_NOT_GRANTED; } @@ -142,7 +142,7 @@ int LLSocks::proxyHandshake(LLHost proxy, U32 message_port) 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; + llinfos << "SOCKS 5 UDP proxy connected on " << mUDPProxy << llendl; return SOCKS_OK; } @@ -155,19 +155,17 @@ int LLSocks::startProxy(LLHost proxy, U32 message_port) if (mProxyControlChannel) { tcp_close_channel(mProxyControlChannel); - mProxyControlChannel = 0; } - mProxyControlChannel = tcp_open_channel(proxy); - if (mProxyControlChannel == -1) + mProxyControlChannel = tcp_open_channel(mTCPProxy); + if (!mProxyControlChannel) { return SOCKS_HOST_CONNECT_FAILED; } - status = proxyHandshake(proxy, message_port); if (status == SOCKS_OK) { - sUdpProxyEnabled = true; + sUDPProxyEnabled = true; } return status; } @@ -181,21 +179,20 @@ int LLSocks::startProxy(std::string host, U32 port) void LLSocks::stopProxy() { - sUdpProxyEnabled = false; + sUDPProxyEnabled = false; - // If the Socks proxy is requested to stop and we are using that for http as well + // 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; + sHTTPProxyEnabled = false; } if (mProxyControlChannel) { tcp_close_channel(mProxyControlChannel); - mProxyControlChannel = 0; } } @@ -211,9 +208,9 @@ void LLSocks::setAuthPassword(std::string username, std::string password) mSocksPassword = password; } -void LLSocks::enableHttpProxy(LLHost httpHost, LLHttpProxyType type) +void LLSocks::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) { - sHttpProxyEnabled = true; + sHTTPProxyEnabled = true; mHTTPProxy = httpHost; mProxyType = type; } diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h index 171a933d32..43a7c82fea 100644 --- a/indra/llmessage/llsocks5.h +++ b/indra/llmessage/llsocks5.h @@ -46,9 +46,9 @@ #define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */ #endif -#define SOCKS_VERSION 0x05 // we are using socks 5 +#define SOCKS_VERSION 0x05 // we are using SOCKS 5 -// socks 5 address/hostname types +// SOCKS 5 address/hostname types #define ADDRESS_IPV4 0x01 #define ADDRESS_HOSTNAME 0x03 #define ADDRESS_IPV6 0x04 @@ -56,16 +56,16 @@ // Lets just use our own ipv4 struct rather than dragging in system // specific headers union ipv4_address_t { - unsigned char octets[4]; - U32 addr32; + U8 octets[4]; + U32 addr32; }; -// Socks 5 control channel commands +// SOCKS 5 control channel commands #define COMMAND_TCP_STREAM 0x01 #define COMMAND_TCP_BIND 0x02 #define COMMAND_UDP_ASSOCIATE 0x03 -// Socks 5 command replys +// SOCKS 5 command replies #define REPLY_REQUEST_GRANTED 0x00 #define REPLY_GENERAL_FAIL 0x01 #define REPLY_RULESET_FAIL 0x02 @@ -78,61 +78,61 @@ union ipv4_address_t { #define FIELD_RESERVED 0x00 -// The standard socks5 request packet +// 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) -// Socks5 command packet +// SOCKS 5 command packet struct socks_command_request_t { - unsigned char version; - unsigned char command; - unsigned char flag; - unsigned char atype; - U32 address; - U16 port; + U8 version; + U8 command; + U8 reserved; + U8 atype; + U32 address; + U16 port; }; -// Standard socks5 reply packet +// Standard SOCKS 5 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; + 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 +// 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 + U8 version; + U8 num_methods; + U8 methods; // We are only using a single method currently }; -// socks 5 authentication response packet, stating server prefered method +// SOCKS 5 authentication response packet, stating server preferred method struct socks_auth_response_t { - unsigned char version; - unsigned char method; + U8 version; + U8 method; }; -// socks 5 password reply packet +// SOCKS 5 password reply packet struct authmethod_password_reply_t { - unsigned char version; - unsigned char status; + U8 version; + U8 status; }; -// socks 5 UDP packet header +// SOCKS 5 UDP packet header struct proxywrap_t { - U16 rsv; - U8 frag; - U8 atype; - U32 addr; - U16 port; + U16 rsv; + U8 frag; + U8 atype; + U32 addr; + U16 port; }; #pragma pack(pop) /* restore original alignment from stack */ @@ -158,62 +158,62 @@ 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); + // 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 + // 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 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 + // 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 bool isEnabled() { return sUDPProxyEnabled; } // static check for enabled status for http packets - static bool isHttpProxyEnabled() { return sHttpProxyEnabled; } + static bool isHTTPProxyEnabled() { return sHTTPProxyEnabled; } - // Proxy http packets via httpHost, which can be a Socks5 or a http proxy + // 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); + void enableHTTPProxy(LLHost httpHost, LLHttpProxyType type); - // Stop proxying http packets - void disableHttpProxy() { sHttpProxyEnabled = false; }; + // 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 + // Get the SOCKS 5 TCP control channel address and port LLHost getTCPProxy() const { return mTCPProxy; } - // Get the http proxy address and port + // 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 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 socks5 proxy proxy, at port messagePort - int proxyHandshake(LLHost proxy,U32 messagePort); + // 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 - S32 mProxyControlChannel; + // socket handle to proxy TCP control channel + LLSocket::ptr_t mProxyControlChannel; // is the UDP proxy enabled? - static bool sUdpProxyEnabled; + static bool sUDPProxyEnabled; // is the http proxy enabled? - static bool sHttpProxyEnabled; + static bool sHTTPProxyEnabled; // currently selected http proxy type LLHttpProxyType mProxyType; @@ -225,13 +225,16 @@ private: // HTTP proxy address and port LLHost mHTTPProxy; - // socks 5 auth method selected + // SOCKS 5 auth method selected LLSocks5AuthType mAuthMethodSelected; - // socks 5 username + // SOCKS 5 username std::string mSocksUsername; - // socks 5 password + // 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 a51d80ff48..366a1835ca 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -189,93 +189,6 @@ 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 (INVALID_SOCKET == handle) - { - llwarns << "Error opening TCP control socket, socket() returned " - << WSAGetLastError() << ", " << DecodeError(WSAGetLastError()) << 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 for 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); - tcp_close_channel(handle); - 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; - tcp_close_channel(handle); - 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) { @@ -473,79 +386,6 @@ 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 (-1 == handle) - { - llwarns << "Error opening TCP control socket, socket() returned " << handle << "error code: " << errno << 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; - tcp_close_channel(handle); - 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 connected or time out after 5 seconds - S32 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; - tcp_close_channel(handle); - 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) { @@ -824,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 047e8ce646..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; @@ -52,10 +55,10 @@ U32 get_sender_ip(void); LLHost get_receiving_interface(); U32 get_receiving_interface_ip(void); -// Some helpful tcp functions added for the socks 5 proxy support -S32 tcp_open_channel(LLHost host); // Open a tcp channel to a given host -void tcp_close_channel(S32 handle); // Close an open tcp channel -int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen); // Do a TCP data handshake +// 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 diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6d94a5454e..c2f0ca164b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2770,18 +2770,18 @@ bool LLStartUp::handleSocksProxy(bool reportOK) LLHost httpHost; httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort")); - LLSocks::getInstance()->enableHttpProxy(httpHost,LLPROXY_HTTP); + 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); + LLSocks::getInstance()->enableHTTPProxy(httpHost,LLPROXY_SOCKS); } else { - LLSocks::getInstance()->disableHttpProxy(); + LLSocks::getInstance()->disableHTTPProxy(); } bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled"); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 87d2f780be..b9ce7d9fae 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -309,13 +309,13 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) } mErrorCert = NULL; - if (LLSocks::getInstance()->isHttpProxyEnabled()) + 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) + if (LLSocks::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) { mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) -- cgit v1.2.3 From f91d40c25949ee8c5b1d5c1babab62d6dd90d0c8 Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Wed, 22 Jun 2011 14:35:31 -0400 Subject: Merge, fixed build issues by refactoring SOCKS 5 code. --- indra/llmessage/llsocks5.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++-- indra/llmessage/llsocks5.h | 1 + indra/llmessage/net.cpp | 59 ---------------------------------- indra/llmessage/net.h | 8 ----- 4 files changed, 73 insertions(+), 70 deletions(-) diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp index 27a31e35b3..278350bf25 100644 --- a/indra/llmessage/llsocks5.cpp +++ b/indra/llmessage/llsocks5.cpp @@ -24,13 +24,16 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + +#include "llsocks5.h" + #include -#include "linden_common.h" -#include "net.h" +#include "llapr.h" #include "llhost.h" #include "message.h" -#include "llsocks5.h" +#include "net.h" // Static class variable instances @@ -40,6 +43,12 @@ bool LLSocks::sUDPProxyEnabled; bool LLSocks::sHTTPProxyEnabled; +// Some helpful TCP functions +static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host +static void tcp_close_channel(LLSocket::ptr_t handle); // Close an open TCP channel +static int tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake + + LLSocks::LLSocks() { sUDPProxyEnabled = false; @@ -214,3 +223,63 @@ void LLSocks::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) mHTTPProxy = httpHost; mProxyType = type; } + +static 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; +} + +static 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; +} + +static void tcp_close_channel(LLSocket::ptr_t handle) +{ + handle.reset(); +} + diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h index 43a7c82fea..3c10f661de 100644 --- a/indra/llmessage/llsocks5.h +++ b/indra/llmessage/llsocks5.h @@ -28,6 +28,7 @@ #define LL_SOCKS5_H #include "llhost.h" +#include "lliosocket.h" #include "llmemory.h" #include "llsingleton.h" #include diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 366a1835ca..e2d185b959 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -664,63 +664,4 @@ 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 0d91cf2a2f..0f2437479d 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -27,9 +27,6 @@ #ifndef LL_NET_H #define LL_NET_H -#include "lliosocket.h" -#include "llapr.h" - class LLTimer; class LLHost; @@ -55,11 +52,6 @@ U32 get_sender_ip(void); 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() -- cgit v1.2.3 From 7717b6f647feb250c0b94d038f72a640a7888915 Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Tue, 28 Jun 2011 19:54:53 -0400 Subject: STORM-1112 More cleanup of SOCKS 5 proxy code. Renamed llsocks5.cpp to llproxy.cpp. --- indra/llmessage/CMakeLists.txt | 4 +- indra/llmessage/llcurl.cpp | 38 +-- indra/llmessage/lliosocket.h | 2 +- indra/llmessage/llpacketring.cpp | 40 ++- indra/llmessage/llproxy.cpp | 294 +++++++++++++++++++++ indra/llmessage/llproxy.h | 244 +++++++++++++++++ indra/llmessage/llsocks5.cpp | 285 -------------------- indra/llmessage/llsocks5.h | 241 ----------------- indra/llmessage/net.cpp | 2 +- indra/llui/llfunctorregistry.h | 4 +- indra/newview/llfloaterpreference.cpp | 47 +++- indra/newview/llloginhandler.cpp | 6 +- indra/newview/llpanellogin.h | 3 - indra/newview/llsecapi.h | 4 +- indra/newview/llstartup.cpp | 80 +++--- indra/newview/llstartup.h | 2 +- indra/newview/llxmlrpctransaction.cpp | 14 +- .../default/xui/en/floater_preferences_proxy.xml | 181 +++++++------ .../newview/skins/default/xui/en/notifications.xml | 21 +- .../skins/default/xui/en/panel_cof_wearables.xml | 2 +- .../default/xui/en/panel_preferences_privacy.xml | 2 +- .../default/xui/en/panel_preferences_setup.xml | 2 +- 22 files changed, 773 insertions(+), 745 deletions(-) create mode 100644 indra/llmessage/llproxy.cpp create mode 100644 indra/llmessage/llproxy.h delete mode 100644 indra/llmessage/llsocks5.cpp delete mode 100644 indra/llmessage/llsocks5.h diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 4b679ef6a5..0f40a670fa 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -65,6 +65,7 @@ set(llmessage_SOURCE_FILES llpacketbuffer.cpp llpacketring.cpp llpartdata.cpp + llproxy.cpp llpumpio.cpp llregionpresenceverifier.cpp llsdappservices.cpp @@ -76,7 +77,6 @@ set(llmessage_SOURCE_FILES llsdrpcserver.cpp llservicebuilder.cpp llservice.cpp - llsocks5.cpp llstoredmessage.cpp lltemplatemessagebuilder.cpp lltemplatemessagedispatcher.cpp @@ -162,6 +162,7 @@ set(llmessage_HEADER_FILES llpacketring.h llpartdata.h llpumpio.h + llproxy.h llqueryflags.h llregionflags.h llregionhandle.h @@ -175,7 +176,6 @@ 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 32dd438e68..0b368196d2 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -46,12 +46,12 @@ #endif #include "llbufferstream.h" -#include "llstl.h" #include "llsdserialize.h" +#include "llproxy.h" +#include "llstl.h" #include "llthread.h" #include "lltimer.h" -#include "llsocks5.h" ////////////////////////////////////////////////////////////////////////////// /* @@ -357,27 +357,6 @@ 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; @@ -557,18 +536,19 @@ void LLCurl::Easy::prepRequest(const std::string& url, //setopt(CURLOPT_VERBOSE, 1); // usefull for debugging setopt(CURLOPT_NOSIGNAL, 1); - if (LLSocks::getInstance()->isHTTPProxyEnabled()) + // Set the CURL options for either Socks or HTTP proxy + if (LLProxy::getInstance()->isHTTPProxyEnabled()) { - std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); - U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); + std::string address = LLProxy::getInstance()->getHTTPProxy().getIPString(); + U16 port = LLProxy::getInstance()->getHTTPProxy().getPort(); setoptString(CURLOPT_PROXY, address.c_str()); setopt(CURLOPT_PROXYPORT, port); - if (LLSocks::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) + if (LLProxy::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) { setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); - if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) + if(LLProxy::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) { - setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); + setoptString(CURLOPT_PROXYUSERPWD, LLProxy::getInstance()->getProxyUserPwdCURL()); } } else diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index 6806e5084a..ec60470459 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -159,7 +159,7 @@ protected: public: /** - * @brief Do not call this directly. + * @brief Do not call this directly. Use LLSocket::ptr_t.reset() instead. */ ~LLSocket(); diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 62aaca0672..91ab1df149 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -37,19 +37,13 @@ // linden library includes #include "llerror.h" -#include "message.h" -#include "llsocks5.h" #include "lltimer.h" -#include "timing.h" +#include "llproxy.h" #include "llrand.h" +#include "message.h" +#include "timing.h" #include "u64.h" - - - - - - /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : mUseInThrottle(FALSE), @@ -231,28 +225,28 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) else { // no delay, pull straight from net - if (LLSocks::isEnabled()) + if (LLProxy::isEnabled()) { - U8 buffer[MAX_BUFFER_SIZE]; - packet_size = receive_packet(socket, (char*)buffer); + U8 buffer[NET_BUFFER_SIZE]; + packet_size = receive_packet(socket, reinterpret_cast(buffer)); if (packet_size > 10) { - memcpy(datap,buffer+10,packet_size-10); + // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) + memcpy(datap, buffer + 10, packet_size - 10); + proxywrap_t * header = reinterpret_cast(buffer); + mLastSender.setAddress(header->addr); + mLastSender.setPort(ntohs(header->port)); } else { - packet_size=0; + 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(); + packet_size = receive_packet(socket, datap); + mLastSender = ::get_sender(); } mLastReceivingIF = ::get_receiving_interface(); @@ -352,7 +346,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) { - if (!LLSocks::isEnabled()) + if (!LLProxy::isEnabled()) { return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort()); } @@ -364,7 +358,7 @@ BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_ socks_header->atype = ADDRESS_IPV4; socks_header->frag = 0; - memcpy(mProxyWrappedSendBuffer+10, send_buffer, buf_size); + 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()); + return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort()); } diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp new file mode 100644 index 0000000000..6bc9e8b62b --- /dev/null +++ b/indra/llmessage/llproxy.cpp @@ -0,0 +1,294 @@ +/** + * @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 "linden_common.h" + +#include "llproxy.h" + +#include + +#include "llapr.h" +#include "llhost.h" +#include "message.h" +#include "net.h" + +// Static class variable instances + +// We want this to be static to avoid excessive indirection on every +// incoming packet just to do a simple bool test. The getter for this +// member is also static +bool LLProxy::sUDPProxyEnabled = false; +bool LLProxy::sHTTPProxyEnabled = false; + +// Some helpful TCP functions +static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host); // Open a TCP channel to a given host +static void tcp_close_channel(LLSocket::ptr_t handle); // Close an open TCP channel +static int tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake + + +LLProxy::LLProxy(): + mProxyType(LLPROXY_SOCKS), + mUDPProxy(), + mTCPProxy(), + mHTTPProxy(), + mAuthMethodSelected(METHOD_NOAUTH), + mSocksUsername(), + mSocksPassword(), + mPool(gAPRPoolp) +{ +} + +LLProxy::~LLProxy() +{ + tcp_close_channel(mProxyControlChannel); + sUDPProxyEnabled = false; + sHTTPProxyEnabled = false; +} + +// Perform a SOCKS 5 authentication and UDP association to the proxy +// specified by proxy, and associate UDP port message_port +int LLProxy::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), (char*)&socks_auth_response, sizeof(socks_auth_response)); + 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 possession of the information at the time of the UDP ASSOCIATE, + // the client MUST use a port number and address of all zeros. RFC 1928" + + result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(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 LLProxy::startProxy(std::string host, U32 port) +{ + mTCPProxy.setHostByName(host); + mTCPProxy.setPort(port); + + int status; + + if (mProxyControlChannel) + { + tcp_close_channel(mProxyControlChannel); + } + + mProxyControlChannel = tcp_open_channel(mPool, mTCPProxy); + if (!mProxyControlChannel) + { + return SOCKS_HOST_CONNECT_FAILED; + } + status = proxyHandshake(mTCPProxy, (U32)gMessageSystem->mPort); + if (status == SOCKS_OK) + { + sUDPProxyEnabled = true; + } + else + { + stopProxy(); + } + return status; + +} + +void LLProxy::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 LLProxy::setAuthNone() +{ + mAuthMethodSelected = METHOD_NOAUTH; +} + +void LLProxy::setAuthPassword(const std::string &username, const std::string &password) +{ + mAuthMethodSelected = METHOD_PASSWORD; + mSocksUsername = username; + mSocksPassword = password; +} + +void LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) +{ + sHTTPProxyEnabled = true; + mHTTPProxy = httpHost; + mProxyType = type; +} + +static 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; +} + +static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, 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; +} + +static void tcp_close_channel(LLSocket::ptr_t handle) +{ + handle.reset(); +} diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h new file mode 100644 index 0000000000..979514a7e0 --- /dev/null +++ b/indra/llmessage/llproxy.h @@ -0,0 +1,244 @@ +/** + * @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_PROXY_H +#define LL_PROXY_H + +#include "llhost.h" +#include "lliosocket.h" +#include "llmemory.h" +#include "llsingleton.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 { + 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 LLProxy: public LLSingleton +{ +public: + LLProxy(); + ~LLProxy(); + + // Start a connection to the SOCKS 5 proxy + int startProxy(std::string host, U32 port); + + // 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(const std::string &username, const std::string &password); + + // Set up to use No Auth when connecting to the SOCKS proxy + void setAuthNone(); + + // get the currently selected auth method + LLSocks5AuthType getSelectedAuthMethod() const { 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 getProxyUserPwdCURL() const { return (mSocksUsername + ":" + mSocksPassword); } + + std::string getSocksPwd() const { return mSocksPassword; } + std::string getSocksUser() const { return mSocksUsername; } + +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/llsocks5.cpp b/indra/llmessage/llsocks5.cpp deleted file mode 100644 index 278350bf25..0000000000 --- a/indra/llmessage/llsocks5.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/** - * @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 "linden_common.h" - -#include "llsocks5.h" - -#include - -#include "llapr.h" -#include "llhost.h" -#include "message.h" -#include "net.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; - -// Some helpful TCP functions -static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host -static void tcp_close_channel(LLSocket::ptr_t handle); // Close an open TCP channel -static int tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake - - -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; -} - -static 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; -} - -static 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; -} - -static void tcp_close_channel(LLSocket::ptr_t handle) -{ - handle.reset(); -} - diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h deleted file mode 100644 index 3c10f661de..0000000000 --- a/indra/llmessage/llsocks5.h +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @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 "lliosocket.h" -#include "llmemory.h" -#include "llsingleton.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 { - 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 -{ -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 e2d185b959..f8ab55143c 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -50,7 +50,7 @@ #include "lltimer.h" #include "indra_constants.h" -#include "llsocks5.h" +#include "llproxy.h" // Globals #if LL_WINDOWS diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 752c7df7ee..899cc3a326 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -103,7 +103,7 @@ public: } else { - llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl; + lldebugs << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl; return mMap[LOGFUNCTOR]; } } @@ -115,7 +115,7 @@ private: static void log_functor(const LLSD& notification, const LLSD& payload) { - llwarns << "log_functor called with payload: " << payload << llendl; + lldebugs << "log_functor called with payload: " << payload << llendl; } static void do_nothing(const LLSD& notification, const LLSD& payload) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c97f0779a1..ebdef8e38f 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -105,7 +105,7 @@ #include "llviewermedia.h" #include "llpluginclassmedia.h" #include "llteleporthistorystorage.h" -#include "llsocks5.h" +#include "llproxy.h" #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" @@ -1940,15 +1940,19 @@ LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() BOOL LLFloaterPreferenceProxy::postBuild() { - LLLineEditor* edit = getChild("socks_password_editor"); - if (edit) edit->setDrawAsterixes(TRUE); - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); if(socksAuth->getSelectedValue().asString() == "None") { getChild("socks5_username")->setEnabled(false); getChild("socks5_password")->setEnabled(false); } + else + { + // Populate the SOCKS 5 credential fields with protected values. + LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + getChild("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString()); + getChild("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString()); + } center(); return TRUE; @@ -1968,11 +1972,8 @@ void LLFloaterPreferenceProxy::onClose(bool app_quitting) // 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 - } + LLNotifications::instance().add("ChangeSocks5Settings", LLSD(), LLSD()); + mSocksSettingsDirty = false; // we have notified the user now be quiet again } } } @@ -2006,7 +2007,6 @@ void LLFloaterPreferenceProxy::saveSettings() view_stack.push_back(*iter); } } - } void LLFloaterPreferenceProxy::onBtnOk() @@ -2020,6 +2020,29 @@ void LLFloaterPreferenceProxy::onBtnOk() cur_focus->onCommit(); } } + + // Save SOCKS proxy credentials securely if password auth is enabled + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if(socksAuth->getSelectedValue().asString() == "UserPass") + { + LLSD socks_id = LLSD::emptyMap(); + socks_id["type"] = "SOCKS5"; + socks_id["username"] = getChild("socks5_username")->getValue().asString(); + + LLSD socks_authenticator = LLSD::emptyMap(); + socks_authenticator["type"] = "SOCKS5"; + socks_authenticator["creds"] = getChild("socks5_password")->getValue().asString(); + + LLPointer socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator); + gSecAPIHandler->saveCredential(socks_cred, true); + } + else + { + // Clear SOCKS5 credentials since they are no longer needed. + LLPointer socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + } + closeFloater(false); } @@ -2036,8 +2059,8 @@ void LLFloaterPreferenceProxy::onBtnCancel() } cancel(); - } + void LLFloaterPreferenceProxy::cancel() { @@ -2068,7 +2091,7 @@ void LLFloaterPreferenceProxy::onChangeSocksSettings() getChild("socks5_password")->setEnabled(true); } - //Check for invalid states for the other http proxy radio + // Check for invalid states for the other HTTP proxy radio LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_selection"); if( (otherHttpProxy->getSelectedValue().asString() == "Socks" && getChild("socks_proxy_enabled")->get() == FALSE )||( diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index 48be251611..9b4f146332 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -30,13 +30,13 @@ // viewer includes #include "llsecapi.h" -#include "lllogininstance.h" // to check if logged in yet -#include "llpanellogin.h" // save_password_to_disk() +#include "lllogininstance.h" // to check if logged in yet +#include "llpanellogin.h" #include "llstartup.h" // getStartupState() #include "llslurl.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewernetwork.h" // EGridInfo -#include "llviewerwindow.h" // getWindow() +#include "llviewerwindow.h" // getWindow() // library includes #include "llmd5.h" diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 11273453ba..b1390a483a 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -115,7 +115,4 @@ private: static BOOL sCapslockDidNotification; }; -std::string load_password_from_disk(void); -void save_password_to_disk(const char* hashed_password); - #endif diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index b65cf37e7f..812a539324 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -286,8 +286,8 @@ bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVe #define CRED_AUTHENTICATOR_TYPE_HASH "hash" // // LLCredential - interface for credentials providing the following functionality: -// * persistance of credential information based on grid (for saving username/password) -// * serialization to an OGP identifier/authenticator pair +// * Persistence of credential information based on grid (for saving username/password) +// * Serialization to an OGP identifier/authenticator pair // class LLCredential : public LLRefCount { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c2f0ca164b..7f14e403b0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -125,6 +125,7 @@ #include "llpanelgroupnotices.h" #include "llpreview.h" #include "llpreviewscript.h" +#include "llproxy.h" #include "llproductinforequest.h" #include "llsecondlifeurls.h" #include "llselectmgr.h" @@ -191,8 +192,6 @@ #include "llevents.h" #include "llstartuplistener.h" -#include "llsocks5.h" - #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -392,7 +391,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; @@ -595,13 +594,13 @@ 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 + // Init the SOCKS 5 proxy and open the control TCP + // connection if the user is using SOCKS 5 + // We need to do this early in case the user is using + // socks for HTTP so we get the login screen via SOCKS //------------------------------------------------- - LLStartUp::handleSocksProxy(false); + LLStartUp::handleSocksProxy(); //------------------------------------------------- // Init audio, which may be needed for prefs dialog @@ -823,7 +822,7 @@ bool idle_startup() // past this point may require the proxy to be up. if ( gSavedSettings.getBOOL("Socks5ProxyEnabled") ) { - if (!LLStartUp::handleSocksProxy(true)) + if (!LLStartUp::handleSocksProxy()) { // Proxy start up failed, we should now bail the state machine // HandleSocksProxy() will have reported an error to the user @@ -835,7 +834,7 @@ bool idle_startup() } else { - LLSocks::getInstance()->stopProxy(); + LLProxy::getInstance()->stopProxy(); } @@ -2760,54 +2759,70 @@ void LLStartUp::setStartSLURL(const LLSLURL& slurl) } } -bool LLStartUp::handleSocksProxy(bool reportOK) +bool LLStartUp::handleSocksProxy() { std::string httpProxyType = gSavedSettings.getString("Socks5HttpProxyType"); - // Determine the http proxy type (if any) + // 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); + LLProxy::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); + LLProxy::getInstance()->enableHTTPProxy(httpHost, LLPROXY_SOCKS); } else { - LLSocks::getInstance()->disableHTTPProxy(); + LLProxy::getInstance()->disableHTTPProxy(); } bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled"); if (use_socks_proxy) { - // Determine and update LLSocks with the saved authentication system + // Determine and update LLProxy 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")); + LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + std::string socks_user = socks_cred->getIdentifier()["username"].asString(); + std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); + LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); + } + else if (auth_type.compare("None") == 0) + { + LLProxy::getInstance()->setAuthNone(); + } + else + { + // Unknown or missing setting. + gSavedSettings.setString("Socks5AuthType", "None"); + + // Clear the SOCKS credentials. + LLPointer socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + + LLProxy::getInstance()->setAuthNone(); } // Start the proxy and check for errors - int status = LLSocks::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort")); + // If status != SOCKS_OK, stopProxy() will already have been called when startProxy() returns. + int status = LLProxy::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort")); LLSD subs; LLSD payload; subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + std::string error_string; + switch(status) { case SOCKS_OK: @@ -2815,35 +2830,36 @@ bool LLStartUp::handleSocksProxy(bool reportOK) break; case SOCKS_CONNECT_ERROR: // TCP Fail - LLNotifications::instance().add("SOCKS_CONNECT_ERROR", subs,payload); + error_string = "SOCKS_CONNECT_ERROR"; break; - case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection - LLNotifications::instance().add("SOCKS_NOT_PERMITTED", subs,payload); + case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection + error_string = "SOCKS_NOT_PERMITTED"; break; case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server - LLNotifications::instance().add("SOCKS_NOT_ACCEPTABLE", subs,payload); + error_string = "SOCKS_NOT_ACCEPTABLE"; break; case SOCKS_AUTH_FAIL: // Authentication failed - LLNotifications::instance().add("SOCKS_AUTH_FAIL", subs,payload); + error_string = "SOCKS_AUTH_FAIL"; break; case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed - LLNotifications::instance().add("SOCKS_UDP_FWD_NOT_GRANTED", subs,payload); + error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; 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; + error_string = "SOCKS_HOST_CONNECT_FAILED"; + break; } + LLNotificationsUtil::add(error_string, subs); return false; } else { - LLSocks::getInstance()->stopProxy(); // ensure no UDP proxy is running and it's all cleaned up + LLProxy::getInstance()->stopProxy(); // ensure no UDP proxy is running and it's all cleaned up } return true; diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index a512ec7bff..7292e4d68c 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -113,7 +113,7 @@ 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 + static bool handleSocksProxy(); // Initialize the SOCKS 5 proxy private: static LLSLURL sStartSLURL; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index b9ce7d9fae..ef6763a5d1 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -41,7 +41,7 @@ #include "llappviewer.h" #include "lltrans.h" -#include "llsocks5.h" +#include "llproxy.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 @@ -309,18 +309,18 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) } mErrorCert = NULL; - if (LLSocks::getInstance()->isHTTPProxyEnabled()) + if (LLProxy::getInstance()->isHTTPProxyEnabled()) { - std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString(); - U16 port = LLSocks::getInstance()->getHTTPProxy().getPort(); + std::string address = LLProxy::getInstance()->getHTTPProxy().getIPString(); + U16 port = LLProxy::getInstance()->getHTTPProxy().getPort(); mCurlRequest->setoptString(CURLOPT_PROXY, address.c_str()); mCurlRequest->setopt(CURLOPT_PROXYPORT, port); - if (LLSocks::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) + if (LLProxy::getInstance()->getHTTPProxyType() == LLPROXY_SOCKS) { mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); - if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) + if(LLProxy::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD) { - mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd()); + mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLProxy::getInstance()->getProxyUserPwdCURL()); } } else diff --git a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml index 9baa9a0e02..53060b0326 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml @@ -3,82 +3,82 @@ legacy_header_height="18" height="490" layout="topleft" - name="Socks5 Advanced Settings Floater" + name="Proxy Settings Floater" help_topic="hardware_settings_floater" title="Socks5 proxy advanced settings" width="385"> - - - - Other Http traffic proxy: - - - - - - - + + + Other Http traffic proxy: + + + + + + + + tool_tip="The port of the SOCKS 5 proxy you would like to use." + commit_callback.function="Proxy.Change" /> + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="16" + name="Proxy location" + top_delta="35" + width="300"> Authentication: - + tool_tip="Socks5 proxy requires no authentication." width="120" /> + tool_tip="Socks5 proxy requires username/password authentication." width="120" />