377 lines
14 KiB
C++
377 lines
14 KiB
C++
/**
|
|
* @file llproxy.h
|
|
* @brief UDP and HTTP proxy communications
|
|
*
|
|
* $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 "llcurl.h"
|
|
#include "llhost.h"
|
|
#include "lliosocket.h"
|
|
#include "llmemory.h"
|
|
#include "llsingleton.h"
|
|
#include "llthread.h"
|
|
#include "aithreadsafe.h"
|
|
#include <string>
|
|
|
|
// SOCKS 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_INVALID_HOST (-7)
|
|
|
|
#ifndef MAXHOSTNAMELEN
|
|
#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
|
|
#endif
|
|
|
|
#define SOCKSMAXUSERNAMELEN 255
|
|
#define SOCKSMAXPASSWORDLEN 255
|
|
|
|
#define SOCKSMINUSERNAMELEN 1
|
|
#define SOCKSMINPASSWORDLEN 1
|
|
|
|
#define SOCKS_VERSION 0x05 // we are using SOCKS 5
|
|
|
|
#define SOCKS_HEADER_SIZE 10
|
|
|
|
// 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
|
|
};
|
|
|
|
/**
|
|
* @brief Manage SOCKS 5 UDP proxy and HTTP proxy.
|
|
*
|
|
* This class is responsible for managing two interconnected tasks,
|
|
* connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP
|
|
* packets and managing proxy settings for HTTP requests.
|
|
*
|
|
* <h1>Threading:</h1>
|
|
* Because HTTP requests can be generated in threads outside the
|
|
* main thread, it is necessary for some of the information stored
|
|
* by this class to be available to other threads. The members that
|
|
* need to be read across threads are in a labeled section below.
|
|
* To protect those members, a mutex, mProxyMutex should be locked
|
|
* before reading or writing those members. Methods that can lock
|
|
* mProxyMutex are in a labeled section below. Those methods should
|
|
* not be called while the mutex is already locked.
|
|
*
|
|
* There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used
|
|
* to track whether the HTTP proxy is currently enabled. This allows
|
|
* for faster unlocked checks to see if the proxy is enabled. This
|
|
* allows us to cut down on the performance hit when the proxy is
|
|
* disabled compared to before this class was introduced.
|
|
*
|
|
* <h1>UDP Proxying:</h1>
|
|
* UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate
|
|
* command. To initiate the proxy, a TCP socket connection is opened
|
|
* to the SOCKS 5 host, and after a handshake exchange, the server
|
|
* returns a port and address to send the UDP traffic that is to be
|
|
* proxied to. The LLProxy class tracks this address and port after the
|
|
* exchange and provides it to LLPacketRing when required to. All UDP
|
|
* proxy management occurs in the main thread.
|
|
*
|
|
* <h1>HTTP Proxying:</h1>
|
|
* This class allows all viewer HTTP packets to be sent through a proxy.
|
|
* The user can select whether to send HTTP packets through a standard
|
|
* "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP
|
|
* communication. This class does not manage the integrated web browser
|
|
* proxy, which is handled in llviewermedia.cpp.
|
|
*
|
|
* The implementation of HTTP proxying is handled by libcurl. LLProxy
|
|
* is responsible for managing the HTTP proxy options and provides a
|
|
* thread-safe method to apply those options to a curl request
|
|
* (LLProxy::applyProxySettings()).
|
|
*
|
|
* To ensure thread safety, all LLProxy members that relate to the HTTP
|
|
* proxy require the LLProxyMutex to be locked before accessing.
|
|
*/
|
|
|
|
struct ProxyUnshared
|
|
{
|
|
/*###########################################################################################
|
|
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD.
|
|
###########################################################################################*/
|
|
|
|
// UDP proxy address and port
|
|
LLHost mUDPProxy;
|
|
|
|
// TCP proxy control channel address and port
|
|
LLHost mTCPProxy;
|
|
|
|
// socket handle to proxy TCP control channel
|
|
LLSocket::ptr_t mProxyControlChannel;
|
|
|
|
/*###########################################################################################
|
|
END OF UNSHARED MEMBERS
|
|
###########################################################################################*/
|
|
};
|
|
|
|
struct ProxyShared
|
|
{
|
|
ProxyShared(void);
|
|
|
|
/*###########################################################################################
|
|
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD.
|
|
###########################################################################################*/
|
|
|
|
// HTTP proxy address and port
|
|
LLHost mHTTPProxy;
|
|
|
|
// Currently selected HTTP proxy type. Can be web or SOCKS.
|
|
LLHttpProxyType mProxyType;
|
|
|
|
// SOCKS 5 selected authentication method.
|
|
LLSocks5AuthType mAuthMethodSelected;
|
|
|
|
// SOCKS 5 username
|
|
std::string mSocksUsername;
|
|
// SOCKS 5 password
|
|
std::string mSocksPassword;
|
|
|
|
/*###########################################################################################
|
|
END OF SHARED MEMBERS
|
|
###########################################################################################*/
|
|
};
|
|
|
|
class LLProxy: public LLSingleton<LLProxy>
|
|
{
|
|
LOG_CLASS(LLProxy);
|
|
|
|
public:
|
|
typedef AISTAccessConst<ProxyUnshared> Unshared_crat; // Constant Read Access Type for Unshared (cannot be converted to write access).
|
|
typedef AISTAccess<ProxyUnshared> Unshared_rat; // Read Access Type for Unshared (same as write access type, since we don't lock at all).
|
|
typedef AISTAccess<ProxyUnshared> Unshared_wat; // Write Access Type, for Unshared.
|
|
typedef AIReadAccessConst<ProxyShared> Shared_crat; // Constant Read Access Type for Shared (cannot be converted to write access).
|
|
typedef AIReadAccess<ProxyShared> Shared_rat; // Read Access Type for Shared.
|
|
typedef AIWriteAccess<ProxyShared> Shared_wat; // Write Access Type for Shared.
|
|
|
|
/*###########################################################################################
|
|
Public methods that only access variables not shared between threads.
|
|
###########################################################################################*/
|
|
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
|
|
LLProxy();
|
|
|
|
// Static check for enabled status for UDP packets. Called from main thread only.
|
|
static bool isSOCKSProxyEnabled(void) { llassert(is_main_thread()); return sUDPProxyEnabled; }
|
|
|
|
// Get the UDP proxy address and port. Called from main thread only.
|
|
LLHost getUDPProxy(void) const { return Unshared_crat(mUnshared)->mUDPProxy; }
|
|
|
|
/*###########################################################################################
|
|
End of methods that only access variables not shared between threads.
|
|
###########################################################################################*/
|
|
|
|
// Return true if there is a good chance that the HTTP proxy is currently enabled.
|
|
bool HTTPProxyEnabled(void) const { return mHTTPProxyEnabled; }
|
|
|
|
/*###########################################################################################
|
|
Public methods that access variables shared between threads.
|
|
###########################################################################################*/
|
|
// Destructor, closes open connections. Do not call directly, use cleanupClass().
|
|
~LLProxy();
|
|
|
|
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
|
|
// destroyed before the call to apr_terminate. Call from main thread only.
|
|
static void cleanupClass();
|
|
|
|
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
|
|
// Safe to call from any thread.
|
|
void applyProxySettings(AICurlEasyRequest_wat const& curlEasyRequest_w);
|
|
|
|
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
|
|
S32 startSOCKSProxy(LLHost host);
|
|
|
|
// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.
|
|
void stopSOCKSProxy();
|
|
|
|
// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.
|
|
bool setAuthPassword(const std::string &username, const std::string &password);
|
|
|
|
// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.
|
|
void setAuthNone();
|
|
|
|
// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy.
|
|
// as specified in type. Call from main thread only.
|
|
bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
|
|
bool enableHTTPProxy();
|
|
|
|
// Stop proxying HTTP packets. Call from main thread only.
|
|
// Note that this needs shared_w to be passed because we want the shared members to be locked when this is reset to false.
|
|
void disableHTTPProxy(Shared_wat const& shared_w) { mHTTPProxyEnabled = false; }
|
|
void disableHTTPProxy(void) { disableHTTPProxy(Shared_wat(mShared)); }
|
|
|
|
// Get the currently selected HTTP proxy address and port
|
|
LLHost const& getHTTPProxy(Shared_crat const& shared_r) const { return shared_r->mHTTPProxy; }
|
|
|
|
// Get the currently selected HTTP proxy type
|
|
LLHttpProxyType getHTTPProxyType(Shared_crat const& shared_r) const { return shared_r->mProxyType; }
|
|
|
|
// Get the currently selected auth method.
|
|
LLSocks5AuthType getSelectedAuthMethod(Shared_crat const& shared_r) const { return shared_r->mAuthMethodSelected; }
|
|
|
|
// SOCKS 5 username and password accessors.
|
|
std::string getSocksUser(Shared_crat const& shared_r) const { return shared_r->mSocksUsername; }
|
|
std::string getSocksPwd(Shared_crat const& shared_r) const { return shared_r->mSocksPassword; }
|
|
|
|
/*###########################################################################################
|
|
End of methods that access variables shared between threads.
|
|
###########################################################################################*/
|
|
|
|
private:
|
|
/*###########################################################################################
|
|
Private methods that access variables shared between threads.
|
|
###########################################################################################*/
|
|
|
|
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
|
|
S32 proxyHandshake(LLHost proxy);
|
|
|
|
/*###########################################################################################
|
|
End of methods that access variables shared between threads.
|
|
###########################################################################################*/
|
|
|
|
private:
|
|
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
|
|
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
|
|
mutable LLAtomic32<bool> mHTTPProxyEnabled;
|
|
|
|
// Is the UDP proxy enabled?
|
|
static bool sUDPProxyEnabled;
|
|
|
|
AIThreadSafeSingleThreadDC<ProxyUnshared> mUnshared;
|
|
AIThreadSafeDC<ProxyShared> mShared;
|
|
|
|
public:
|
|
// For thread-safe read access. Use the _crat access types with these.
|
|
AIThreadSafeSingleThreadDC<ProxyUnshared> const& unshared_lockobj(void) const { return mUnshared; }
|
|
AIThreadSafeDC<ProxyShared> const& shared_lockobj(void) const { return mShared; }
|
|
};
|
|
|
|
#endif
|