summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorRobin Cornelius <robin.cornelius@gmail.com>2011-03-28 11:20:06 +0100
committerRobin Cornelius <robin.cornelius@gmail.com>2011-03-28 11:20:06 +0100
commit74d9bf0d5525426feae4ea21e2a81034ddcf4d7f (patch)
tree5174ee85c5242295fa26c1b6da777932de27eba5 /indra
parentb7b9a37bc13d40a3caf7ea77d6857c2bb6036e06 (diff)
VWR-20801 Implement SOCKS 5 Proxy for the viewer
Diffstat (limited to 'indra')
-rw-r--r--indra/llmessage/CMakeLists.txt2
-rw-r--r--indra/llmessage/llcurl.cpp44
-rw-r--r--indra/llmessage/llpacketring.cpp60
-rw-r--r--indra/llmessage/llpacketring.h3
-rw-r--r--indra/llmessage/llsocks5.cpp224
-rw-r--r--indra/llmessage/llsocks5.h243
-rw-r--r--indra/llmessage/net.cpp156
-rw-r--r--indra/llmessage/net.h5
-rw-r--r--indra/newview/app_settings/settings.xml77
-rwxr-xr-xindra/newview/llfloaterpreference.cpp171
-rw-r--r--indra/newview/llfloaterpreference.h30
-rw-r--r--indra/newview/llstartup.cpp123
-rw-r--r--indra/newview/llstartup.h2
-rw-r--r--indra/newview/llviewerfloaterreg.cpp1
-rw-r--r--indra/newview/llxmlrpctransaction.cpp21
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_proxy.xml274
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml70
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml85
18 files changed, 1525 insertions, 66 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 1cad0f6d22..8c68d38926 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -74,6 +74,7 @@ set(llmessage_SOURCE_FILES
llsdrpcserver.cpp
llservicebuilder.cpp
llservice.cpp
+ llsocks5.cpp
llstoredmessage.cpp
lltemplatemessagebuilder.cpp
lltemplatemessagedispatcher.cpp
@@ -172,6 +173,7 @@ set(llmessage_HEADER_FILES
llsdrpcserver.h
llservice.h
llservicebuilder.h
+ llsocks5.h
llstoredmessage.h
lltaskname.h
llteleportflags.h
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a485fa0160..020c0d6a4a 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -50,6 +50,8 @@
#include "llsdserialize.h"
#include "llthread.h"
+#include "llsocks5.h"
+
//////////////////////////////////////////////////////////////////////////////
/*
The trick to getting curl to do keep-alives is to reuse the
@@ -273,6 +275,28 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
// set no DMS caching as default for all easy handles. This prevents them adopting a
// multi handles cache if they are added to one.
curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+
+ //Set the CURL options for either Socks or HTTP proxy
+ if (LLSocks::getInstance()->isHttpProxyEnabled())
+ {
+ std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString();
+ U16 port = LLSocks::getInstance()->getHTTPProxy().getPort();
+ curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXY,address.c_str());
+ curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYPORT,port);
+ if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS)
+ {
+ curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD)
+ {
+ curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd().c_str());
+ }
+ }
+ else
+ {
+ curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ }
+ }
+
++gCurlEasyCount;
return easy;
}
@@ -446,6 +470,26 @@ void LLCurl::Easy::prepRequest(const std::string& url,
// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
setopt(CURLOPT_NOSIGNAL, 1);
+ if (LLSocks::getInstance()->isHttpProxyEnabled())
+ {
+ std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString();
+ U16 port = LLSocks::getInstance()->getHTTPProxy().getPort();
+ setoptString(CURLOPT_PROXY, address.c_str());
+ setopt(CURLOPT_PROXYPORT, port);
+ if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS)
+ {
+ setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD)
+ {
+ setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd());
+ }
+ }
+ else
+ {
+ setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ }
+ }
+
mOutput.reset(new LLBufferArray);
setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
setopt(CURLOPT_WRITEDATA, (void*)this);
diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp
index 8999dec64a..0c8c5f763c 100644
--- a/indra/llmessage/llpacketring.cpp
+++ b/indra/llmessage/llpacketring.cpp
@@ -35,6 +35,17 @@
#include "llrand.h"
#include "u64.h"
+#include "llsocks5.h"
+#include "message.h"
+
+#if LL_WINDOWS
+ #include <winsock2.h>
+#else
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+#endif
+
+
///////////////////////////////////////////////////////////
LLPacketRing::LLPacketRing () :
mUseInThrottle(FALSE),
@@ -216,8 +227,31 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)
else
{
// no delay, pull straight from net
+ if (LLSocks::isEnabled())
+ {
+ U8 buffer[MAX_BUFFER_SIZE];
+ packet_size = receive_packet(socket, (char*)buffer);
+
+ if (packet_size > 10)
+ {
+ memcpy(datap,buffer+10,packet_size-10);
+ }
+ else
+ {
+ packet_size=0;
+ }
+
+ proxywrap_t * header;
+ header = (proxywrap_t *)buffer;
+ mLastSender.setAddress(header->addr);
+ mLastSender.setPort(ntohs(header->port));
+ }
+ else
+ {
packet_size = receive_packet(socket, datap);
mLastSender = ::get_sender();
+ }
+
mLastReceivingIF = ::get_receiving_interface();
if (packet_size) // did we actually get a packet?
@@ -243,7 +277,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
BOOL status = TRUE;
if (!mUseOutThrottle)
{
- return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() );
+ return doSendPacket(h_socket, send_buffer, buf_size, host );
}
else
{
@@ -264,7 +298,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
mOutBufferLength -= packetp->getSize();
packet_size = packetp->getSize();
- status = send_packet(h_socket, packetp->getData(), packet_size, packetp->getHost().getAddress(), packetp->getHost().getPort());
+ status = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost());
delete packetp;
// Update the throttle
@@ -273,7 +307,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
else
{
// If the queue's empty, we can just send this packet right away.
- status = send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() );
+ status = doSendPacket(h_socket, send_buffer, buf_size, host );
packet_size = buf_size;
// Update the throttle
@@ -311,3 +345,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
return status;
}
+
+BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
+{
+
+ if (!LLSocks::isEnabled())
+ {
+ return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
+ }
+
+ proxywrap_t *socks_header = (proxywrap_t *)&mProxyWrappedSendBuffer;
+ socks_header->rsv = 0;
+ socks_header->addr = host.getAddress();
+ socks_header->port = htons(host.getPort());
+ socks_header->atype = ADDRESS_IPV4;
+ socks_header->frag = 0;
+
+ memcpy(mProxyWrappedSendBuffer+10, send_buffer, buf_size);
+
+ return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size+10, LLSocks::getInstance()->getUDPProxy().getAddress(), LLSocks::getInstance()->getUDPProxy().getPort());
+}
diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h
index e6409d2048..2fe2f8e1e9 100644
--- a/indra/llmessage/llpacketring.h
+++ b/indra/llmessage/llpacketring.h
@@ -82,6 +82,9 @@ protected:
LLHost mLastSender;
LLHost mLastReceivingIF;
+
+ BOOL doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
+ U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE];
};
diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp
new file mode 100644
index 0000000000..1f458a007c
--- /dev/null
+++ b/indra/llmessage/llsocks5.cpp
@@ -0,0 +1,224 @@
+/**
+ * @file llsocks5.cpp
+ * @brief Socks 5 implementation
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include <string>
+
+#include "linden_common.h"
+#include "net.h"
+#include "llhost.h"
+#include "message.h"
+#include "llsocks5.h"
+
+// Static class variable instances
+
+// We want this to be static to avoid excessive indirection on every
+// incomming packet just to do a simple bool test. The getter for this
+// member is also static
+bool LLSocks::sUdpProxyEnabled;
+bool LLSocks::sHttpProxyEnabled;
+
+LLSocks::LLSocks()
+{
+ sUdpProxyEnabled = false;
+ sHttpProxyEnabled = false;
+ hProxyControlChannel = 0;
+ mProxyType = LLPROXY_SOCKS;
+}
+
+// Perform a Socks5 authentication and UDP assioacation to the proxy
+// specified by proxy, and assiocate UDP port message_port
+int LLSocks::proxyHandshake(LLHost proxy, U32 message_port)
+{
+ int result;
+
+ /* Socks 5 Auth request */
+ socks_auth_request_t socks_auth_request;
+ socks_auth_response_t socks_auth_response;
+
+ socks_auth_request.version = SOCKS_VERSION; // Socks version 5
+ socks_auth_request.num_methods = 1; // Sending 1 method
+ socks_auth_request.methods = mAuthMethodSelected; // send only the selected metho
+
+ result = tcp_handshake(hProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request_t), (char*)&socks_auth_response, sizeof(socks_auth_response_t));
+ if (result != 0)
+ {
+ llwarns << "Socks authentication request failed, error on TCP control channel : " << result << llendl;
+ stopProxy();
+ return SOCKS_CONNECT_ERROR;
+ }
+
+ if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
+ {
+ llwarns << "Socks5 server refused all our authentication methods" << llendl;
+ stopProxy();
+ return SOCKS_NOT_ACCEPTABLE;
+ }
+
+ // SOCKS5 USERNAME/PASSWORD authentication
+ if (socks_auth_response.method == METHOD_PASSWORD)
+ {
+ // The server has requested a username/password combination
+ U32 request_size = mSocksUsername.size() + mSocksPassword.size() + 3;
+ char * password_auth = (char *)malloc(request_size);
+ password_auth[0] = 0x01;
+ password_auth[1] = mSocksUsername.size();
+ memcpy(&password_auth[2],mSocksUsername.c_str(), mSocksUsername.size());
+ password_auth[mSocksUsername.size()+2] = mSocksPassword.size();
+ memcpy(&password_auth[mSocksUsername.size()+3], mSocksPassword.c_str(), mSocksPassword.size());
+
+ authmethod_password_reply_t password_reply;
+
+ result = tcp_handshake(hProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t));
+ free (password_auth);
+
+ if (result != 0)
+ {
+ llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl;
+ stopProxy();
+ return SOCKS_CONNECT_ERROR;
+ }
+
+ if (password_reply.status != AUTH_SUCCESS)
+ {
+ llwarns << "Socks authentication failed" << llendl;
+ stopProxy();
+ return SOCKS_AUTH_FAIL;
+ }
+ }
+
+ /* SOCKS5 connect request */
+
+ socks_command_request_t connect_request;
+ socks_command_response_t connect_reply;
+
+ connect_request.version = SOCKS_VERSION; //Socks V5
+ connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
+ connect_request.flag = FIELD_RESERVED;
+ connect_request.atype = ADDRESS_IPV4;
+ connect_request.address = 0; // 0.0.0.0 We are not fussy about address
+ // UDP is promiscious receive for our protocol
+ connect_request.port = 0; // Port must be 0 if you ever want to connect via NAT and your router does port rewrite for you
+
+ result = tcp_handshake(hProxyControlChannel, (char*)&connect_request, sizeof(socks_command_request_t), (char*)&connect_reply, sizeof(socks_command_response_t));
+ if (result != 0)
+ {
+ llwarns << "Socks connect request failed, error on TCP control channel : " << result << llendl;
+ stopProxy();
+ return SOCKS_CONNECT_ERROR;
+ }
+
+ if (connect_reply.reply != REPLY_REQUEST_GRANTED)
+ {
+ //Something went wrong
+ llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl;
+ stopProxy();
+ return SOCKS_UDP_FWD_NOT_GRANTED;
+ }
+
+ mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
+ mUDPProxy.setAddress(proxy.getAddress());
+ // All good now we have been given the UDP port to send requests that need forwarding.
+ llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl;
+ return SOCKS_OK;
+}
+
+int LLSocks::startProxy(LLHost proxy, U32 message_port)
+{
+ int status;
+
+ mTCPProxy = proxy;
+
+ if (hProxyControlChannel)
+ {
+ tcp_close_channel(hProxyControlChannel);
+ hProxyControlChannel=0;
+ }
+
+ hProxyControlChannel = tcp_open_channel(proxy);
+ if (hProxyControlChannel == -1)
+ {
+ return SOCKS_HOST_CONNECT_FAILED;
+ }
+
+ status = proxyHandshake(proxy, message_port);
+ if (status == SOCKS_OK)
+ {
+ sUdpProxyEnabled=true;
+ }
+ return status;
+}
+
+int LLSocks::startProxy(std::string host, U32 port)
+{
+ mTCPProxy.setHostByName(host);
+ mTCPProxy.setPort(port);
+ return startProxy(mTCPProxy, (U32)gMessageSystem->mPort);
+}
+
+void LLSocks::stopProxy()
+{
+ sUdpProxyEnabled = false;
+
+ // If the Socks proxy is requested to stop and we are using that for http as well
+ // then we must shut down any http proxy operations. But it is allowable if web
+ // proxy is being used to continue proxying http.
+
+ if(LLPROXY_SOCKS == mProxyType)
+ {
+ sHttpProxyEnabled = false;
+ }
+
+ if (hProxyControlChannel)
+ {
+ tcp_close_channel(hProxyControlChannel);
+ hProxyControlChannel=0;
+ }
+}
+
+void LLSocks::setAuthNone()
+{
+ mAuthMethodSelected = METHOD_NOAUTH;
+}
+
+void LLSocks::setAuthPassword(std::string username, std::string password)
+{
+ mAuthMethodSelected = METHOD_PASSWORD;
+ mSocksUsername = username;
+ mSocksPassword = password;
+}
+
+void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type)
+{
+ sHttpProxyEnabled = true;
+ mHTTPProxy = httpHost;
+ mProxyType = type;
+}
diff --git a/indra/llmessage/llsocks5.h b/indra/llmessage/llsocks5.h
new file mode 100644
index 0000000000..83e311a962
--- /dev/null
+++ b/indra/llmessage/llsocks5.h
@@ -0,0 +1,243 @@
+/**
+ * @file llsocks5.h
+ * @brief Socks 5 implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_SOCKS5_H
+#define LL_SOCKS5_H
+
+#include "llhost.h"
+#include "llmemory.h"
+#include "llsingleton.h"
+#include <string>
+
+// Error codes returned from the StartProxy method
+
+#define SOCKS_OK 0
+#define SOCKS_CONNECT_ERROR -1
+#define SOCKS_NOT_PERMITTED -2
+#define SOCKS_NOT_ACCEPTABLE -3
+#define SOCKS_AUTH_FAIL -4
+#define SOCKS_UDP_FWD_NOT_GRANTED -5
+#define SOCKS_HOST_CONNECT_FAILED -6
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
+#endif
+
+#define SOCKS_VERSION 0x05 // we are using socks 5
+
+// socks 5 address/hostname types
+#define ADDRESS_IPV4 0x01
+#define ADDRESS_HOSTNAME 0x03
+#define ADDRESS_IPV6 0x04
+
+// Lets just use our own ipv4 struct rather than dragging in system
+// specific headers
+union ipv4_address_t {
+ unsigned char octects[4];
+ U32 addr32;
+};
+
+// Socks 5 control channel commands
+#define COMMAND_TCP_STREAM 0x01
+#define COMMAND_TCP_BIND 0x02
+#define COMMAND_UDP_ASSOCIATE 0x03
+
+// Socks 5 command replys
+#define REPLY_REQUEST_GRANTED 0x00
+#define REPLY_GENERAL_FAIL 0x01
+#define REPLY_RULESET_FAIL 0x02
+#define REPLY_NETWORK_UNREACHABLE 0x03
+#define REPLY_HOST_UNREACHABLE 0x04
+#define REPLY_CONNECTION_REFUSED 0x05
+#define REPLY_TTL_EXPIRED 0x06
+#define REPLY_PROTOCOL_ERROR 0x07
+#define REPLY_TYPE_NOT_SUPPORTED 0x08
+
+#define FIELD_RESERVED 0x00
+
+// The standard socks5 request packet
+// Push current alignment to stack and set alignment to 1 byte boundary
+// This enabled us to use structs directly to set up and receive network packets
+// into the correct fields, without fear of boundary alignment causing issues
+#pragma pack(push,1)
+
+// Socks5 command packet
+struct socks_command_request_t {
+ unsigned char version;
+ unsigned char command;
+ unsigned char flag;
+ unsigned char atype;
+ U32 address;
+ U16 port;
+};
+
+// Standard socks5 reply packet
+struct socks_command_response_t {
+ unsigned char version;
+ unsigned char reply;
+ unsigned char flag;
+ unsigned char atype;
+ unsigned char add_bytes[4];
+ U16 port;
+};
+
+#define AUTH_NOT_ACCEPTABLE 0xFF // reply if prefered methods are not avaiable
+#define AUTH_SUCCESS 0x00 // reply if authentication successfull
+
+// socks 5 authentication request, stating which methods the client supports
+struct socks_auth_request_t {
+ unsigned char version;
+ unsigned char num_methods;
+ unsigned char methods; // We are only using a single method currently
+};
+
+// socks 5 authentication response packet, stating server prefered method
+struct socks_auth_response_t {
+ unsigned char version;
+ unsigned char method;
+};
+
+// socks 5 password reply packet
+struct authmethod_password_reply_t {
+ unsigned char version;
+ unsigned char status;
+};
+
+// socks 5 UDP packet header
+struct proxywrap_t {
+ U16 rsv;
+ U8 frag;
+ U8 atype;
+ U32 addr;
+ U16 port;
+};
+
+#pragma pack(pop) /* restore original alignment from stack */
+
+
+// Currently selected http proxy type
+enum LLHttpProxyType
+{
+ LLPROXY_SOCKS = 0,
+ LLPROXY_HTTP = 1
+};
+
+// Auth types
+enum LLSocks5AuthType
+{
+ METHOD_NOAUTH = 0x00, // Client supports no auth
+ METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported)
+ METHOD_PASSWORD = 0x02 // Client supports username/password
+};
+
+class LLSocks: public LLSingleton<LLSocks>
+{
+public:
+ LLSocks();
+
+ // Start a connection to the socks 5 proxy
+ int startProxy(std::string host,U32 port);
+ int startProxy(LLHost proxy,U32 messagePort);
+
+ // Disconnect and clean up any connection to the socks 5 proxy
+ void stopProxy();
+
+ // Set up to use Password auth when connecting to the socks proxy
+ void setAuthPassword(std::string username,std::string password);
+
+ // Set up to use No Auth when connecting to the socks proxy;
+ void setAuthNone();
+
+ // get the currently selected auth method
+ LLSocks5AuthType getSelectedAuthMethod() { return mAuthMethodSelected; };
+
+ // static check for enabled status for UDP packets
+ static bool isEnabled(){return sUdpProxyEnabled;};
+
+ // static check for enabled status for http packets
+ static bool isHttpProxyEnabled(){return sHttpProxyEnabled;};
+
+ // Proxy http packets via httpHost, which can be a Socks5 or a http proxy
+ // as specified in type
+ void EnableHttpProxy(LLHost httpHost,LLHttpProxyType type);
+
+ // Stop proxying http packets
+ void DisableHttpProxy() {sHttpProxyEnabled = false;};
+
+ // get the UDP proxy address and port
+ LLHost getUDPProxy(){return mUDPProxy;};
+
+ // get the socks 5 TCP control channel address and port
+ LLHost getTCPProxy(){return mTCPProxy;};
+
+ //get the http proxy address and port
+ LLHost getHTTPProxy(){return mHTTPProxy;};
+
+ // get the currently selected http proxy type
+ LLHttpProxyType getHttpProxyType(){return mProxyType;};
+
+ //Get the username password in a curl compatible format
+ std::string getProxyUserPwd(){ return (mSocksUsername + ":" + mSocksPassword);};
+
+private:
+
+ // Open a communication channel to the socks5 proxy proxy, at port messagePort
+ int proxyHandshake(LLHost proxy,U32 messagePort);
+
+ // socket handle to proxy tcp control channel
+ S32 hProxyControlChannel;
+
+ // is the UDP proxy enabled
+ static bool sUdpProxyEnabled;
+ // is the http proxy enabled
+ static bool sHttpProxyEnabled;
+
+ // currently selected http proxy type
+ LLHttpProxyType mProxyType;
+
+ // UDP proxy address and port
+ LLHost mUDPProxy;
+ // TCP Proxy control channel address and port
+ LLHost mTCPProxy;
+ // HTTP proxy address and port
+ LLHost mHTTPProxy;
+
+ // socks 5 auth method selected
+ LLSocks5AuthType mAuthMethodSelected;
+
+ // socks 5 username
+ std::string mSocksUsername;
+ // socks 5 password
+ std::string mSocksPassword;
+};
+
+#endif
diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp
index 97611c3b51..ab5c1950c6 100644
--- a/indra/llmessage/net.cpp
+++ b/indra/llmessage/net.cpp
@@ -50,6 +50,7 @@
#include "lltimer.h"
#include "indra_constants.h"
+#include "llsocks5.h"
// Globals
#if LL_WINDOWS
@@ -189,6 +190,90 @@ U32 ip_string_to_u32(const char* ip_string)
#if LL_WINDOWS
+int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen)
+{
+ int result;
+ result = send(handle, dataout, outlen, 0);
+ if (result != outlen)
+ {
+ S32 err = WSAGetLastError();
+ llwarns << "Error sending data to proxy control channel, number of bytes sent were " << result << " error code was " << err << llendl;
+ return -1;
+ }
+
+ result = recv(handle, datain, maxinlen, 0);
+ if (result != maxinlen)
+ {
+ S32 err = WSAGetLastError();
+ llwarns << "Error receiving data from proxy control channel, number of bytes received were " << result << " error code was " << err << llendl;
+ return -1;
+ }
+
+ return 0;
+}
+
+S32 tcp_open_channel(LLHost host)
+{
+ // Open a TCP channel
+ // Jump through some hoops to ensure that if the request hosts is down
+ // or not reachable connect() does not block
+
+ S32 handle;
+ handle = socket(AF_INET, SOCK_STREAM, 0);
+ if (!handle)
+ {
+ llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl;
+ return -1;
+ }
+
+ struct sockaddr_in address;
+ address.sin_port = htons(host.getPort());
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = host.getAddress();
+
+ // Non blocking
+ WSAEVENT hEvent=WSACreateEvent();
+ WSAEventSelect(handle, hEvent, FD_CONNECT) ;
+ connect(handle, (struct sockaddr*)&address, sizeof(address)) ;
+ // Wait fot 5 seconds, if we can't get a TCP channel open in this
+ // time frame then there is something badly wrong.
+ WaitForSingleObject(hEvent, 1000*5); // 5 seconds time out
+
+ WSANETWORKEVENTS netevents;
+ WSAEnumNetworkEvents(handle,hEvent,&netevents);
+
+ // Check the async event status to see if we connected
+ if ((netevents.lNetworkEvents & FD_CONNECT) == FD_CONNECT)
+ {
+ if (netevents.iErrorCode[FD_CONNECT_BIT] != 0)
+ {
+ llwarns << "Unable to open TCP channel, WSA returned an error code of " << netevents.iErrorCode[FD_CONNECT_BIT] << llendl;
+ WSACloseEvent(hEvent);
+ return -1;
+ }
+
+ // Now we are connected disable non blocking
+ // we don't need support an async interface as
+ // currently our only consumer (socks5) will make one round
+ // of packets then just hold the connection open
+ WSAEventSelect(handle, hEvent, NULL) ;
+ unsigned long NonBlock = 0;
+ ioctlsocket(handle, FIONBIO, &NonBlock);
+
+ return handle;
+ }
+
+ llwarns << "Unable to open TCP channel, Timeout is the host up?" << netevents.iErrorCode[FD_CONNECT_BIT] << llendl;
+ return -1;
+}
+
+void tcp_close_channel(S32 handle)
+{
+ llinfos << "Closing TCP channel" << llendl;
+ shutdown(handle, SD_BOTH);
+ closesocket(handle);
+}
+
S32 start_net(S32& socket_out, int& nPort)
{
// Create socket, make non-blocking
@@ -385,6 +470,77 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i
#else
+
+int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen)
+{
+ if (send(handle, dataout, outlen, 0) != outlen)
+ {
+ llwarns << "Error sending data to proxy control channel" << llendl;
+ return -1;
+ }
+
+ if (recv(handle, datain, maxinlen, 0) != maxinlen)
+ {
+ llwarns << "Error receiving data to proxy control channel" << llendl;
+ return -1;
+ }
+
+ return 0;
+}
+
+S32 tcp_open_channel(LLHost host)
+{
+ S32 handle;
+ handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (!handle)
+ {
+ llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl;
+ return -1;
+ }
+
+ struct sockaddr_in address;
+ address.sin_port = htons(host.getPort());
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = host.getAddress();
+
+ // Set the socket to non blocking for the connect()
+ int flags = fcntl(handle, F_GETFL, 0);
+ fcntl(handle, F_SETFL, flags | O_NONBLOCK);
+
+ S32 error = connect(handle, (sockaddr*)&address, sizeof(address));
+ if (error && (errno != EINPROGRESS))
+ {
+ llwarns << "Unable to open TCP channel, error code: " << errno << llendl;
+ return -1;
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = 5; // Maximum time to wait for the connect() to complete
+ timeout.tv_usec = 0;
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(handle, &fds);
+
+ // See if we have connectde or time out after 5 seconds
+ U32 rc = select(sizeof(fds)*8, NULL, &fds, NULL, &timeout);
+
+ if (rc != 1) // we require exactly one descriptor to be set
+ {
+ llwarns << "Unable to open TCP channel" << llendl;
+ return -1;
+ }
+
+ // Return the socket to blocking operations
+ fcntl(handle, F_SETFL, flags);
+
+ return handle;
+}
+
+void tcp_close_channel(S32 handle)
+{
+ close(handle);
+}
+
// Create socket, make non-blocking
S32 start_net(S32& socket_out, int& nPort)
{
diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h
index 9f4f5c5821..d93ed20c98 100644
--- a/indra/llmessage/net.h
+++ b/indra/llmessage/net.h
@@ -52,6 +52,11 @@ U32 get_sender_ip(void);
LLHost get_receiving_interface();
U32 get_receiving_interface_ip(void);
+// Some helpful tcp functions added for the socks 5 proxy support
+S32 tcp_open_channel(LLHost host); // Open a tcp channel to a given host
+void tcp_close_channel(S32 handle); // Close an open tcp channel
+int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen); // Do a TCP data handshake
+
const char* u32_to_ip_string(U32 ip); // Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls
char* u32_to_ip_string(U32 ip, char *ip_string); // NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars
U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr()
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f0e28d4ae3..2b7b7b8484 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -774,6 +774,83 @@
<key>Value</key>
<integer>5</integer>
</map>
+ <key>Socks5ProxyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Socks5 Proxy</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>Socks5HttpProxyType</key>
+ <map>
+ <key>Comment</key>
+ <string>Proxy type to use for HTTP operations</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Socks</string>
+ </map>
+ <key>Socks5ProxyHost</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Proxy Host</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>64.79.219.97</string>
+ </map>
+ <key>Socks5ProxyPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Proxy Port</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1080</integer>
+ </map>
+ <key>Socks5Username</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Username</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>Socks5Password</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Password</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>Socks5AuthType</key>
+ <map>
+ <key>Comment</key>
+ <string>Selected Auth mechanism for Socks5</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>None</string>
+ </map>
<key>BuildAxisDeadZone0</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 724096b443..a0d3852d30 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -103,6 +103,7 @@
#include "llviewermedia.h"
#include "llpluginclassmedia.h"
#include "llteleporthistorystorage.h"
+#include "llsocks5.h"
#include "lllogininstance.h" // to check if logged in yet
#include "llsdserialize.h"
@@ -325,6 +326,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2));
mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this));
mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this));
+ mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this));
sSkin = gSavedSettings.getString("SkinCurrent");
@@ -603,6 +605,12 @@ void LLFloaterPreference::cancel()
updateDoubleClickControls();
mDoubleClickActionDirty = false;
}
+ LLFloaterPreferenceProxy * advanced_socks_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_socks5_advanced");
+ if(advanced_socks_settings)
+ {
+ advanced_socks_settings->cancel();
+ }
+
}
void LLFloaterPreference::onOpen(const LLSD& key)
@@ -1497,6 +1505,11 @@ void LLFloaterPreference::updateDoubleClickSettings()
}
}
+void LLFloaterPreference::onClickProxySettings()
+{
+ LLFloaterReg::showInstance("prefs_proxy");
+}
+
void LLFloaterPreference::updateDoubleClickControls()
{
// check is one of double-click actions settings enabled
@@ -1805,3 +1818,161 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
resetDirtyChilds();
LLPanelPreference::setHardwareDefaults();
}
+
+
+/* ------------------------------------------------------------ */
+
+LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key)
+ : LLFloater(key),
+ mSocksSettingsDirty(false)
+{
+ mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this));
+ mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this));
+ mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this));
+}
+
+LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy()
+{
+}
+
+BOOL LLFloaterPreferenceProxy::postBuild()
+{
+ LLLineEditor* edit = getChild<LLLineEditor>("socks_password_editor");
+ if (edit) edit->setDrawAsterixes(TRUE);
+
+ LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type");
+ if(socksAuth->getSelectedValue().asString() == "None")
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(false);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(false);
+ }
+
+ center();
+ return TRUE;
+}
+
+void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
+{
+ saveSettings();
+}
+
+void LLFloaterPreferenceProxy::onClose(bool app_quitting)
+{
+ if(mSocksSettingsDirty)
+ {
+
+ // If the user plays with the Socks proxy settings after login, its only fair we let them know
+ // it will not be updated untill next restart.
+ if(LLStartUp::getStartupState()>STATE_LOGIN_WAIT)
+ {
+ if(this->mSocksSettingsDirty == true )
+ {
+ LLNotifications::instance().add("ChangeSocks5Settings",LLSD(),LLSD());
+ mSocksSettingsDirty = false; // we have notified the user now be quiet again
+ }
+ }
+ }
+}
+
+void LLFloaterPreferenceProxy::saveSettings()
+{
+ // Save the value of all controls in the hierarchy
+ mSavedValues.clear();
+ std::list<LLView*> view_stack;
+ view_stack.push_back(this);
+ while(!view_stack.empty())
+ {
+ // Process view on top of the stack
+ LLView* curview = view_stack.front();
+ view_stack.pop_front();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview);
+ if (ctrl)
+ {
+ LLControlVariable* control = ctrl->getControlVariable();
+ if (control)
+ {
+ mSavedValues[control] = control->getValue();
+ }
+ }
+
+ // Push children onto the end of the work stack
+ for (child_list_t::const_iterator iter = curview->getChildList()->begin();
+ iter != curview->getChildList()->end(); ++iter)
+ {
+ view_stack.push_back(*iter);
+ }
+ }
+
+}
+
+void LLFloaterPreferenceProxy::onBtnOk()
+{
+ // commit any outstanding text entry
+ if (hasFocus())
+ {
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus && cur_focus->acceptsTextInput())
+ {
+ cur_focus->onCommit();
+ }
+ }
+ closeFloater(false);
+}
+
+void LLFloaterPreferenceProxy::onBtnCancel()
+{
+ if (hasFocus())
+ {
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus && cur_focus->acceptsTextInput())
+ {
+ cur_focus->onCommit();
+ }
+ refresh();
+ }
+
+ cancel();
+
+}
+void LLFloaterPreferenceProxy::cancel()
+{
+
+ for (control_values_map_t::iterator iter = mSavedValues.begin();
+ iter != mSavedValues.end(); ++iter)
+ {
+ LLControlVariable* control = iter->first;
+ LLSD ctrl_value = iter->second;
+ control->set(ctrl_value);
+ }
+
+ closeFloater();
+}
+
+void LLFloaterPreferenceProxy::onChangeSocksSettings()
+{
+ mSocksSettingsDirty = true;
+
+ LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type");
+ if(socksAuth->getSelectedValue().asString() == "None")
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(false);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(false);
+ }
+ else
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(true);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(true);
+ }
+
+ //Check for invalid states for the other http proxy radio
+ LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_selection");
+ if( (otherHttpProxy->getSelectedValue().asString() == "Socks" &&
+ getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == FALSE )||(
+ otherHttpProxy->getSelectedValue().asString() == "Web" &&
+ getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == FALSE ) )
+ {
+ otherHttpProxy->selectFirstItem();
+ }
+
+}; \ No newline at end of file
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 46014804ec..fd5454ebcf 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -154,6 +154,7 @@ public:
void applyResolution();
void onChangeMaturity();
void onClickBlockList();
+ void onClickProxySettings();
void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
void getUIColor(LLUICtrl* ctrl, const LLSD& param);
@@ -225,4 +226,33 @@ protected:
};
+class LLFloaterPreferenceProxy : public LLFloater
+{
+public:
+ LLFloaterPreferenceProxy(const LLSD& key);
+ ~LLFloaterPreferenceProxy();
+
+ /// show off our menu
+ static void show();
+ void cancel();
+
+protected:
+ BOOL postBuild();
+ void onOpen(const LLSD& key);
+ void onClose(bool app_quitting);
+ void saveSettings();
+ void onBtnOk();
+ void onBtnCancel();
+
+ void onChangeSocksSettings();
+
+private:
+
+ bool mSocksSettingsDirty;
+ typedef std::map<LLControlVariable*, LLSD> control_values_map_t;
+ control_values_map_t mSavedValues;
+
+};
+
+
#endif // LL_LLPREFERENCEFLOATER_H
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8fccb35886..f054bd11b8 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -191,6 +191,8 @@
#include "llevents.h"
#include "llstartuplistener.h"
+#include "llsocks5.h"
+
#if LL_WINDOWS
#include "lldxhardware.h"
#endif
@@ -393,7 +395,7 @@ bool idle_startup()
gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
// load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
+ //LLFeatureManager::getInstance()->fetchHTTPTables();
std::string xml_file = LLUI::locateSkin("xui_version.xml");
LLXMLNodePtr root;
@@ -596,6 +598,15 @@ bool idle_startup()
LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
//-------------------------------------------------
+ // Init the socks 5 proxy and open the control TCP
+ // connection if the user is using SOCKS5
+ // We need to do this early incase the user is using
+ // socks for http so we get the login screen via socks
+ //-------------------------------------------------
+
+ LLStartUp::handleSocksProxy(false);
+
+ //-------------------------------------------------
// Init audio, which may be needed for prefs dialog
// or audio cues in connection UI.
//-------------------------------------------------
@@ -809,6 +820,27 @@ bool idle_startup()
if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
{
+ // Post login screen, we should see if any settings have changed that may
+ // require us to either start/stop or change the socks proxy. As various communications
+ // past this point may require the proxy to be up.
+ if ( gSavedSettings.getBOOL("Socks5ProxyEnabled") )
+ {
+ if (!LLStartUp::handleSocksProxy(true))
+ {
+ // Proxy start up failed, we should now bail the state machine
+ // HandleSocksProxy() will have reported an error to the user
+ // already, so we just go back to the login screen. The user
+ // could then change the preferences to fix the issue.
+ LLStartUp::setStartupState(STATE_LOGIN_SHOW);
+ return FALSE;
+ }
+ }
+ else
+ {
+ LLSocks::getInstance()->stopProxy();
+ }
+
+
//reset the values that could have come in from a slurl
// DEV-42215: Make sure they're not empty -- gUserCredential
// might already have been set from gSavedSettings, and it's too bad
@@ -2746,6 +2778,95 @@ void LLStartUp::setStartSLURL(const LLSLURL& slurl)
}
}
+bool LLStartUp::handleSocksProxy(bool reportOK)
+{
+ std::string httpProxyType = gSavedSettings.getString("Socks5HttpProxyType");
+
+ // Determine the http proxy type (if any)
+ if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled"))
+ {
+ LLHost httpHost;
+ httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress"));
+ httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort"));
+ LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_HTTP);
+ }
+ else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled"))
+ {
+ LLHost httpHost;
+ httpHost.setHostByName(gSavedSettings.getString("Socks5ProxyHost"));
+ httpHost.setPort(gSavedSettings.getU32("Socks5ProxyPort"));
+ LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_SOCKS);
+ }
+ else
+ {
+ LLSocks::getInstance()->DisableHttpProxy();
+ }
+
+ bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled");
+ if (use_socks_proxy)
+ {
+
+ // Determine and update LLSocks with the saved authentication system
+ std::string auth_type = gSavedSettings.getString("Socks5AuthType");
+
+ if (auth_type.compare("None") == 0)
+ {
+ LLSocks::getInstance()->setAuthNone();
+ }
+
+ if (auth_type.compare("UserPass") == 0)
+ {
+ LLSocks::getInstance()->setAuthPassword(gSavedSettings.getString("Socks5Username"),gSavedSettings.getString("Socks5Password"));
+ }
+
+ // Start the proxy and check for errors
+ int status = LLSocks::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort"));
+ LLSD subs;
+ LLSD payload;
+ subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost");
+ subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort");
+
+ switch(status)
+ {
+ case SOCKS_OK:
+ return true;
+ break;
+
+ case SOCKS_CONNECT_ERROR: // TCP Fail
+ LLNotifications::instance().add("SOCKS_CONNECT_ERROR", subs,payload);
+ break;
+
+ case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection
+ LLNotifications::instance().add("SOCKS_NOT_PERMITTED", subs,payload);
+ break;
+
+ case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server
+ LLNotifications::instance().add("SOCKS_NOT_ACCEPTABLE", subs,payload);
+ break;
+
+ case SOCKS_AUTH_FAIL: // Authentication failed
+ LLNotifications::instance().add("SOCKS_AUTH_FAIL", subs,payload);
+ break;
+
+ case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed
+ LLNotifications::instance().add("SOCKS_UDP_FWD_NOT_GRANTED", subs,payload);
+ break;
+
+ case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server
+ LLNotifications::instance().add("SOCKS_HOST_CONNECT_FAILED", subs,payload);
+ break;
+ }
+
+ return false;
+ }
+ else
+ {
+ LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up
+ }
+
+ return true;
+}
+
bool login_alert_done(const LLSD& notification, const LLSD& response)
{
LLPanelLogin::giveFocus();
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index b3d9ef1dcc..a512ec7bff 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -113,6 +113,8 @@ public:
static void setStartSLURL(const LLSLURL& slurl);
static LLSLURL& getStartSLURL() { return sStartSLURL; }
+ static bool handleSocksProxy(bool reportOK); //handle kicking the socks 5 proxy code at startup time
+
private:
static LLSLURL sStartSLURL;
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index dca1e33e60..976dc76b50 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -202,6 +202,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostcard>);
LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
+ LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);
LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerms>);
LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>);
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 257884d921..b3d899c61a 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -41,6 +41,8 @@
#include "llappviewer.h"
#include "lltrans.h"
+#include "llsocks5.h"
+
// Static instance of LLXMLRPCListener declared here so that every time we
// bring in this code, we instantiate a listener. If we put the static
// instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would
@@ -307,16 +309,23 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
}
mErrorCert = NULL;
- if (gSavedSettings.getBOOL("BrowserProxyEnabled"))
+ if (LLSocks::getInstance()->isHttpProxyEnabled())
{
- mProxyAddress = gSavedSettings.getString("BrowserProxyAddress");
- S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" );
-
- // tell curl about the settings
- mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress);
+ std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString();
+ U16 port = LLSocks::getInstance()->getHTTPProxy().getPort();
+ mCurlRequest->setoptString(CURLOPT_PROXY, address.c_str());
mCurlRequest->setopt(CURLOPT_PROXYPORT, port);
+ if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS)
+ {
+ mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD)
+ mCurlRequest->setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd());
+ }
+ else
+ {
mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
+ }
// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml
new file mode 100644
index 0000000000..bb9ade067b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="490"
+ layout="topleft"
+ name="Socks5 Advanced Settings Floater"
+ help_topic="hardware_settings_floater"
+ title="Socks5 proxy advanced settings"
+ width="385">
+ <check_box
+ control_name="BrowserProxyEnabled"
+ top="30"
+ enabled="true"
+ follows="left|top"
+ height="14"
+ initial_value="false"
+ commit_callback.function="Proxy.Change"
+ label="Use HTTP Proxy for Web pages"
+ left_delta="10"
+ mouse_opaque="true"
+ name="web_proxy_enabled"
+ radio_style="false"
+ width="400"
+ top_pad="5" />
+ <check_box
+ control_name="Socks5ProxyEnabled"
+ height="16"
+ label="Use Socks 5 Proxy for UDP traffic"
+ layout="topleft"
+ left_delta="0"
+ name="socks_proxy_enabled"
+ top_pad="5"
+ width="256"
+ commit_callback.function="Proxy.Change" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="10"
+ name="Proxy location"
+ top_delta="30"
+ width="300">
+ Other Http traffic proxy:
+ </text>
+ <radio_group
+ control_name="Socks5HttpProxyType"
+ height="60"
+ layout="topleft"
+ name="other_http_proxy_selection"
+ top_pad="10"
+ width="120"
+ border="1"
+ left_delta="10"
+ commit_callback.function="Proxy.Change" >
+ <radio_item
+ height="16"
+ label="Do not proxy"
+ layout="topleft"
+ value="None"
+ width="120"
+ tool_tip="Non web Http trafic should NOT be sent to any proxy."/>
+ <radio_item
+ height="16"
+ label="Use Socks 5 Proxy"
+ layout="topleft"
+ value="Socks"
+ width="120"
+ enabled_control="Socks5ProxyEnabled"
+ tool_tip="Non-web Http will be sent to the configured Socks 5 proxy."/>
+ <radio_item
+ height="16"
+ label="Use Http Proxy"
+ layout="topleft"
+ value="Web"
+ width="120"
+ enabled_control="BrowserProxyEnabled"
+ tool_tip="Non-web Http will be sent to the configured Web proxy." />
+ </radio_group>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ left="15"
+ layout="topleft"
+ name="Proxy location"
+ top_delta="82"
+ width="300">
+ HTTP Proxy:
+ </text>
+ <line_editor
+ control_name="BrowserProxyAddress"
+ enabled_control="BrowserProxyEnabled"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="web_proxy_editor"
+ tool_tip="The DNS name or IP address of the HTTP proxy you would like to use."
+ top_pad="4"
+ width="200" />
+ <spinner
+ control_name="BrowserProxyPort"
+ enabled_control="BrowserProxyEnabled"
+ decimal_digits="0"
+ follows="left|top"
+ height="23"
+ increment="1"
+ initial_value="80"
+ label="Port number:"
+ label_width="95"
+ layout="topleft"
+ left_delta="210"
+ max_val="12000"
+ min_val="10"
+ name="web_proxy_port"
+ top_delta="0"
+ tool_tip="The port of the HTTP proxy you would like to use."
+ width="145" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="15"
+ name="Proxy location"
+ top_delta="32"
+ width="300">
+ SOCKS 5 Proxy:
+ </text>
+ <line_editor
+ control_name="Socks5ProxyHost"
+ enabled_control="Socks5ProxyEnabled"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="socks_proxy_editor"
+ tool_tip="The DNS name or IP address of the SOCKS 5 proxy you would like to use."
+ top_pad="4"
+ width="200"
+ commit_callback.function="Proxy.Change" />
+ <spinner
+ control_name="Socks5ProxyPort"
+ enabled_control="Socks5ProxyEnabled"
+ decimal_digits="0"
+ follows="left|top"
+ height="23"
+ increment="1"
+ initial_value="80"
+ label="Port number:"
+ label_width="95"
+ layout="topleft"
+ left_delta="210"
+ max_val="12000"
+ min_val="10"
+ name="socks_proxy_port"
+ top_delta="0"
+ width="145"
+ tool_tip="The port of the SOCKS 5 proxy you would like to use."
+ commit_callback.function="Pref.SocksProxy" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="16"
+ name="Proxy location"
+ top_delta="35"
+ width="300">
+ Authentication:
+ </text>
+ <radio_group
+ control_name="Socks5AuthType"
+ enabled_control="Socks5ProxyEnabled"
+ height="50"
+ layout="topleft"
+ name="socks5_auth_type"
+ top_pad="10"
+ width="120"
+ border="1"
+ commit_callback.function="Proxy.Change" >
+ <radio_item
+ height="16"
+ label="No Authentication"
+ layout="topleft"
+ name="Socks5NoAuth"
+ value="None"
+ tool_tip="Socks5 proxy requires no authentication."/>
+ width="120" />
+ <radio_item
+ height="16"
+ label="Username/Password"
+ layout="topleft"
+ name="Socks5UserPass"
+ value="UserPass"
+ tool_tip="Socks5 proxy requires username/password authentication."/>
+ width="120" />
+ </radio_group>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="20"
+ top_delta="50"
+ width="300">
+ Username:
+ </text>
+ <line_editor
+ control_name="Socks5Username"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="socks5_username"
+ tool_tip="The username used to authenticate with your SOCKS 5 server"
+ top_pad="4"
+ width="200"
+ commit_callback.function="Proxy.Change" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="0"
+ top_delta="30"
+ width="300">
+ Password:
+ </text>
+ <line_editor
+ control_name="Socks5Password"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="socks5_password"
+ tool_tip="The password used to authenticate with your SOCKS 5 server"
+ top_pad="4"
+ width="200"
+ commit_callback.function="Proxy.Change" />
+ <button
+ follows="left|top"
+ height="22"
+ label="OK"
+ label_selected="OK"
+ layout="topleft"
+ right="275"
+ name="OK"
+ top_delta="53"
+ width="90"
+ commit_callback.function="Proxy.OK" />
+ <button
+ follows="left|top"
+ height="22"
+ label="Cancel"
+ label_selected="Cancel"
+ layout="topleft"
+ right="375"
+ name="Cancel"
+ top_delta="0"
+ width="90"
+ commit_callback.function="Proxy.Cancel" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index ba13479860..751b038252 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7070,6 +7070,76 @@ Mute everyone?
</notification>
<notification
+ icon="alertmodal.tga"
+ name="SOCKS_NOT_PERMITTED"
+ type="alertmodal">
+ The Socks5 proxy "[HOST]:[PORT]" refused the connection, not allowed by rule set
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_CONNECT_ERROR"
+ type="alertmodal">
+ The Socks5 proxy "[HOST]:[PORT]" refused the connection, could not open TCP channel
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_NOT_ACCEPTABLE"
+ type="alertmodal">
+ The Socks5 proxy "[HOST]:[PORT]" refused the selected authentication system
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_AUTH_FAIL"
+ type="alertmodal">
+ The Socks5 proxy "[HOST]:[PORT]" reported your credentials are invalid
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_UDP_FWD_NOT_GRANTED"
+ type="alertmodal">
+ The Socks5 proxy "[HOST]:[PORT]" refused the UDP associate request
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_HOST_CONNECT_FAILED"
+ type="alertmodal">
+ Could not connect to Socks5 proxy server "[HOST]:[PORT]"
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ChangeSocks5Settings"
+ type="alert">
+ Socks 5 proxy settings take effect after you restart [APP_NAME].
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
name="AuthRequest"
type="browser">
The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;[REALM]&apos; requires a user name and password.
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 901a1257e0..1a631293e7 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -70,7 +70,7 @@
layout="topleft"
left="77"
name="connection_port_enabled"
- top_pad="20"
+ top_pad="10"
width="256">
<check_box.commit_callback
function="Notification.Show"
@@ -102,7 +102,7 @@
left="80"
mouse_opaque="false"
name="cache_size_label_l"
- top_pad="20"
+ top_pad="10"
width="200">
Cache size
</text>
@@ -287,60 +287,6 @@
name="media_popup_enabled"
width="400"
top_pad="5"/>
- <check_box
- top_delta="4"
- enabled="true"
- follows="left|top"
- height="14"
- initial_value="false"
- control_name="BrowserProxyEnabled"
- label="Enable Web Proxy"
- left_delta="0"
- mouse_opaque="true"
- name="web_proxy_enabled"
- radio_style="false"
- width="400" top_pad="5"/>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="20"
- name="Proxy location"
- top_delta="16"
- width="300">
- Proxy location:
- </text>
- <line_editor
- control_name="BrowserProxyAddress"
- enabled_control="BrowserProxyEnabled"
- follows="left|top"
- font="SansSerif"
- height="23"
- layout="topleft"
- left_delta="0"
- name="web_proxy_editor"
- tool_tip="The name or IP address of the proxy you would like to use"
- top_pad="4"
- width="200" />
- <spinner
- control_name="BrowserProxyPort"
- enabled_control="BrowserProxyEnabled"
- decimal_digits="0"
- follows="left|top"
- height="23"
- increment="1"
- initial_value="80"
- label="Port number:"
- label_width="95"
- layout="topleft"
- left_delta="210"
- max_val="12000"
- min_val="10"
- name="web_proxy_port"
- top_delta="0"
- width="145" />
<text
type="string"
length="1"
@@ -378,4 +324,31 @@
name="Install_manual"
value="0" />
</combo_box>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="30"
+ name="Software updates:"
+ mouse_opaque="false"
+ top_pad="5"
+ width="300">
+ Proxy Settings:
+ </text>
+ <button
+ label="Adjust proxy settings"
+ follows="left|top"
+ height="23"
+ width="140"
+ label_selected="Browse"
+ layout="topleft"
+ left_delta="50"
+ name="set_proxy"
+ top_pad="5"
+ >
+ <button.commit_callback
+ function="Pref.Proxy" />
+ </button>
</panel>